1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <viewopt.hxx>
22 #include "porglue.hxx"
26 #include <comphelper/string.hxx>
28 SwGluePortion::SwGluePortion( const sal_uInt16 nInitFixWidth
)
29 : m_nFixWidth( nInitFixWidth
)
31 PrtWidth( m_nFixWidth
);
32 SetWhichPor( PortionType::Glue
);
35 TextFrameIndex
SwGluePortion::GetModelPositionForViewPoint(const sal_uInt16 nOfst
) const
37 // FIXME why nOfst > GetLen() ? is that supposed to be > Width() ?
38 if( !GetLen() || nOfst
> sal_Int32(GetLen()) || !Width() )
39 return SwLinePortion::GetModelPositionForViewPoint( nOfst
);
41 return TextFrameIndex(nOfst
/ (Width() / sal_Int32(GetLen())));
44 SwPosSize
SwGluePortion::GetTextSize( const SwTextSizeInfo
&rInf
) const
46 if (TextFrameIndex(1) >= GetLen() || rInf
.GetLen() > GetLen() || !Width() || !GetLen())
47 return SwPosSize(*this);
49 return SwPosSize((Width() / sal_Int32(GetLen())) * sal_Int32(rInf
.GetLen()), Height());
52 bool SwGluePortion::GetExpText( const SwTextSizeInfo
&rInf
, OUString
&rText
) const
54 if( GetLen() && rInf
.OnWin() &&
55 rInf
.GetOpt().IsBlank() && rInf
.IsNoSymbol() )
57 OUStringBuffer
aBuf(GetLen().get());
58 comphelper::string::padToLength(aBuf
, sal_Int32(GetLen()), CH_BULLET
);
59 rText
= aBuf
.makeStringAndClear();
65 void SwGluePortion::Paint( const SwTextPaintInfo
&rInf
) const
70 if( rInf
.GetFont()->IsPaintBlank() )
72 const sal_Int32 nCount
= GetFixWidth() / sal_Int32(GetLen());
73 OUStringBuffer
aBuf(nCount
);
74 comphelper::string::padToLength(aBuf
, nCount
, ' ');
75 OUString
aText(aBuf
.makeStringAndClear());
76 SwTextPaintInfo
aInf( rInf
, &aText
);
77 aInf
.DrawText(*this, TextFrameIndex(aText
.getLength()), true);
80 if( !(rInf
.OnWin() && rInf
.GetOpt().IsBlank() && rInf
.IsNoSymbol()) )
83 #if OSL_DEBUG_LEVEL > 0
84 const sal_Unicode cChar
= rInf
.GetChar( rInf
.GetIdx() );
85 OSL_ENSURE( CH_BLANK
== cChar
|| CH_BULLET
== cChar
,
86 "SwGluePortion::Paint: blank expected" );
88 if (TextFrameIndex(1) == GetLen())
90 OUString
aBullet( CH_BULLET
);
91 SwPosSize
aBulletSize( rInf
.GetTextSize( aBullet
) );
92 Point
aPos( rInf
.GetPos() );
93 aPos
.AdjustX((Width()/2) - (aBulletSize
.Width()/2) );
94 SwTextPaintInfo
aInf( rInf
, &aBullet
);
96 SwTextPortion aBulletPor
;
97 aBulletPor
.Width( aBulletSize
.Width() );
98 aBulletPor
.Height( aBulletSize
.Height() );
99 aBulletPor
.SetAscent( GetAscent() );
100 aInf
.DrawText(aBulletPor
, TextFrameIndex(aBullet
.getLength()), true);
104 SwTextSlot
aSlot( &rInf
, this, true, false );
105 rInf
.DrawText( *this, rInf
.GetLen(), true );
109 void SwGluePortion::MoveGlue( SwGluePortion
*pTarget
, const tools::Long nPrtGlue
)
111 auto nPrt
= std::min( nPrtGlue
, GetPrtGlue() );
114 pTarget
->AddPrtWidth( nPrt
); //TODO: overflow
115 SubPrtWidth( nPrt
); //TODO: overflow
119 void SwGluePortion::Join( SwGluePortion
*pVictim
)
121 // The GluePortion is extracted and flushed away ...
122 AddPrtWidth( pVictim
->PrtWidth() );
123 SetLen( pVictim
->GetLen() + GetLen() );
124 if( Height() < pVictim
->Height() )
125 Height( pVictim
->Height() );
132 void SwGluePortion::dumpAsXml(xmlTextWriterPtr pWriter
, const OUString
& rText
,
133 TextFrameIndex
& nOffset
) const
135 (void)xmlTextWriterStartElement(pWriter
, BAD_CAST("SwGluePortion"));
136 dumpAsXmlAttributes(pWriter
, rText
, nOffset
);
139 (void)xmlTextWriterWriteAttribute(pWriter
, BAD_CAST("fix-width"), BAD_CAST(OString::number(m_nFixWidth
).getStr()));
141 (void)xmlTextWriterEndElement(pWriter
);
145 * We're expecting a frame-local SwRect!
147 SwFixPortion::SwFixPortion( const SwRect
&rRect
)
148 :SwGluePortion( sal_uInt16(rRect
.Width()) ), m_nFix( sal_uInt16(rRect
.Left()) )
150 Height( sal_uInt16(rRect
.Height()) );
151 SetWhichPor( PortionType::Fix
);
154 SwFixPortion::SwFixPortion()
155 : SwGluePortion(0), m_nFix(0)
157 SetWhichPor( PortionType::Fix
);
160 void SwFixPortion::dumpAsXml(xmlTextWriterPtr pWriter
, const OUString
& rText
, TextFrameIndex
& nOffset
) const
162 (void)xmlTextWriterStartElement(pWriter
, BAD_CAST("SwFixPortion"));
163 dumpAsXmlAttributes(pWriter
, rText
, nOffset
);
166 (void)xmlTextWriterWriteAttribute(pWriter
, BAD_CAST("fix"),
167 BAD_CAST(OString::number(m_nFix
).getStr()));
169 (void)xmlTextWriterEndElement(pWriter
);
172 SwMarginPortion::SwMarginPortion()
175 SetWhichPor( PortionType::Margin
);
179 * In the outer loop all portions are inspected - the GluePortions
180 * at the end are processed first.
181 * The end is shifted forwardly till no more GluePortions remain.
182 * Always GluePortion-pairs (pLeft and pRight) are treated, where
183 * textportions between pLeft and pRight are moved at the back of
184 * pRight if pRight has enough Glue. With every move part of the
185 * Glue is transferred from pRight to pLeft.
186 * The next loop starts with the processed pLeft as pRight.
188 void SwMarginPortion::AdjustRight( const SwLineLayout
*pCurr
)
190 SwGluePortion
*pRight
= nullptr;
191 bool bNoMove
= nullptr != pCurr
->GetpKanaComp();
192 while( pRight
!= this )
195 // 1) We search for the left Glue
196 SwLinePortion
*pPos
= this;
197 SwGluePortion
*pLeft
= nullptr;
200 if( pPos
->InFixMargGrp() )
201 pLeft
= static_cast<SwGluePortion
*>(pPos
);
202 pPos
= pPos
->GetNextPortion();
207 // Two adjoining FlyPortions are merged
208 if( pRight
&& pLeft
&& pLeft
->GetNextPortion() == pRight
)
210 pRight
->MoveAllGlue( pLeft
);
213 auto nRightGlue
= pRight
&& 0 < pRight
->GetPrtGlue()
214 ? pRight
->GetPrtGlue() : 0;
215 // 2) balance left and right Glue
216 // But not for tabs ...
217 if( pLeft
&& nRightGlue
&& !pRight
->InTabGrp() )
219 // pPrev is the portion immediately before pRight
220 SwLinePortion
*pPrev
= pRight
->FindPrevPortion( pLeft
);
222 if ( pRight
->IsFlyPortion() && pRight
->GetLen() )
224 SwFlyPortion
*pFly
= static_cast<SwFlyPortion
*>(pRight
);
225 if ( pFly
->GetBlankWidth() < nRightGlue
)
227 // Creating new TextPortion, that takes over the
228 // Blank previously swallowed by the Fly.
229 nRightGlue
= nRightGlue
- pFly
->GetBlankWidth();
230 pFly
->SubPrtWidth( pFly
->GetBlankWidth() );
231 pFly
->SetLen(TextFrameIndex(0));
232 SwTextPortion
*pNewPor
= new SwTextPortion
;
233 pNewPor
->SetLen(TextFrameIndex(1));
234 pNewPor
->Height( pFly
->Height() );
235 pNewPor
->Width( pFly
->GetBlankWidth() );
236 pFly
->Insert( pNewPor
);
241 while( pPrev
!= pLeft
)
243 if( bNoMove
|| pPrev
->PrtWidth() >= nRightGlue
||
244 pPrev
->InHyphGrp() || pPrev
->IsKernPortion() )
246 // The portion before the pRight cannot be moved
247 // because no Glue is remaining.
248 // We set the break condition:
253 nRightGlue
= nRightGlue
- pPrev
->PrtWidth();
254 // pPrev is moved behind pRight. For this the
255 // Glue value between pRight and pLeft gets balanced.
256 pRight
->MoveGlue( pLeft
, pPrev
->PrtWidth() );
257 // Now fix the linking of our portions.
258 SwLinePortion
*pPrevPrev
= pPrev
->FindPrevPortion( pLeft
);
259 pPrevPrev
->SetNextPortion( pRight
);
260 pPrev
->SetNextPortion( pRight
->GetNextPortion() );
261 pRight
->SetNextPortion( pPrev
);
262 if ( pPrev
->GetNextPortion() && pPrev
->InTextGrp()
263 && pPrev
->GetNextPortion()->IsHolePortion() )
265 SwHolePortion
*pHolePor
=
266 static_cast<SwHolePortion
*>(pPrev
->GetNextPortion());
267 if ( !pHolePor
->GetNextPortion() ||
268 !pHolePor
->GetNextPortion()->InFixMargGrp() )
270 pPrev
->AddPrtWidth( pHolePor
->GetBlankWidth() );
271 pPrev
->SetLen(pPrev
->GetLen() + TextFrameIndex(1));
272 pPrev
->SetNextPortion( pHolePor
->GetNextPortion() );
280 // If no left Glue remains, we set the break condition.
281 pRight
= pLeft
? pLeft
: this;
285 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */