1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sw.hxx"
26
27
28
29 #include "swrect.hxx"
30 #include "paratr.hxx" // pTabStop, ADJ*
31 #include "viewopt.hxx" // SwViewOptions
32 #include "errhdl.hxx" // ASSERT
33 #include <SwPortionHandler.hxx>
34
35 #include "txtcfg.hxx"
36 #include "porglue.hxx"
37 #include "inftxt.hxx"
38 #include "porlay.hxx" // SwParaPortion, SetFull
39 #include "porfly.hxx" // SwParaPortion, SetFull
40
41 /*************************************************************************
42 * class SwGluePortion
43 *************************************************************************/
44
SwGluePortion(const KSHORT nInitFixWidth)45 SwGluePortion::SwGluePortion( const KSHORT nInitFixWidth )
46 : nFixWidth( nInitFixWidth )
47 {
48 PrtWidth( nFixWidth );
49 SetWhichPor( POR_GLUE );
50 }
51
52 /*************************************************************************
53 * virtual SwGluePortion::GetCrsrOfst()
54 *************************************************************************/
55
GetCrsrOfst(const KSHORT nOfst) const56 xub_StrLen SwGluePortion::GetCrsrOfst( const KSHORT nOfst ) const
57 {
58 if( !GetLen() || nOfst > GetLen() || !Width() )
59 return SwLinePortion::GetCrsrOfst( nOfst );
60 else
61 return nOfst / (Width() / GetLen());
62 }
63
64 /*************************************************************************
65 * virtual SwGluePortion::GetTxtSize()
66 *************************************************************************/
67
GetTxtSize(const SwTxtSizeInfo & rInf) const68 SwPosSize SwGluePortion::GetTxtSize( const SwTxtSizeInfo &rInf ) const
69 {
70 if( 1 >= GetLen() || rInf.GetLen() > GetLen() || !Width() || !GetLen() )
71 return SwPosSize(*this);
72 else
73 return SwPosSize( (Width() / GetLen()) * rInf.GetLen(), Height() );
74 }
75
76 /*************************************************************************
77 * virtual SwGluePortion::GetExpTxt()
78 *************************************************************************/
79
GetExpTxt(const SwTxtSizeInfo & rInf,XubString & rTxt) const80 sal_Bool SwGluePortion::GetExpTxt( const SwTxtSizeInfo &rInf, XubString &rTxt ) const
81 {
82 if( GetLen() && rInf.OnWin() &&
83 rInf.GetOpt().IsBlank() && rInf.IsNoSymbol() )
84 {
85 rTxt.Fill( GetLen(), CH_BULLET );
86 return sal_True;
87 }
88 return sal_False;
89 }
90
91 /*************************************************************************
92 * virtual SwGluePortion::Paint()
93 *************************************************************************/
94
Paint(const SwTxtPaintInfo & rInf) const95 void SwGluePortion::Paint( const SwTxtPaintInfo &rInf ) const
96 {
97 if( !GetLen() )
98 return;
99
100 if( rInf.GetFont()->IsPaintBlank() )
101 {
102 XubString aTxt;
103 aTxt.Fill( GetFixWidth() / GetLen(), ' ' );
104 SwTxtPaintInfo aInf( rInf, aTxt );
105 aInf.DrawText( *this, aTxt.Len(), sal_True );
106 }
107
108 if( rInf.OnWin() && rInf.GetOpt().IsBlank() && rInf.IsNoSymbol() )
109 {
110 #ifdef DBG_UTIL
111 const xub_Unicode cChar = rInf.GetChar( rInf.GetIdx() );
112 ASSERT( CH_BLANK == cChar || CH_BULLET == cChar,
113 "SwGluePortion::Paint: blank expected" );
114 #endif
115 if( 1 == GetLen() )
116 {
117 String aBullet( CH_BULLET );
118 SwPosSize aBulletSize( rInf.GetTxtSize( aBullet ) );
119 Point aPos( rInf.GetPos() );
120 aPos.X() += (Width()/2) - (aBulletSize.Width()/2);
121 SwTxtPaintInfo aInf( rInf, aBullet );
122 aInf.SetPos( aPos );
123 SwTxtPortion aBulletPor;
124 aBulletPor.Width( aBulletSize.Width() );
125 aBulletPor.Height( aBulletSize.Height() );
126 aBulletPor.SetAscent( GetAscent() );
127 aInf.DrawText( aBulletPor, aBullet.Len(), sal_True );
128 }
129 else
130 {
131 SwTxtSlot aSlot( &rInf, this, true, false );
132 rInf.DrawText( *this, rInf.GetLen(), sal_True );
133 }
134 }
135 }
136
137 /*************************************************************************
138 * SwGluePortion::MoveGlue()
139 *************************************************************************/
140
MoveGlue(SwGluePortion * pTarget,const short nPrtGlue)141 void SwGluePortion::MoveGlue( SwGluePortion *pTarget, const short nPrtGlue )
142 {
143 short nPrt = Min( nPrtGlue, GetPrtGlue() );
144 if( 0 < nPrt )
145 {
146 pTarget->AddPrtWidth( nPrt );
147 SubPrtWidth( nPrt );
148 }
149 }
150
151 /*************************************************************************
152 * void SwGluePortion::Join()
153 *************************************************************************/
154
Join(SwGluePortion * pVictim)155 void SwGluePortion::Join( SwGluePortion *pVictim )
156 {
157 // Die GluePortion wird ausgesogen und weggespuelt ...
158 AddPrtWidth( pVictim->PrtWidth() );
159 SetLen( pVictim->GetLen() + GetLen() );
160 if( Height() < pVictim->Height() )
161 Height( pVictim->Height() );
162
163 AdjFixWidth();
164 Cut( pVictim );
165 delete pVictim;
166 }
167
168 /*************************************************************************
169 * class SwFixPortion
170 *************************************************************************/
171
172 // Wir erwarten ein framelokales SwRect !
SwFixPortion(const SwRect & rRect)173 SwFixPortion::SwFixPortion( const SwRect &rRect )
174 :SwGluePortion( KSHORT(rRect.Width()) ), nFix( KSHORT(rRect.Left()) )
175 {
176 Height( KSHORT(rRect.Height()) );
177 SetWhichPor( POR_FIX );
178 }
179
SwFixPortion(const KSHORT nFixedWidth,const KSHORT nFixedPos)180 SwFixPortion::SwFixPortion(const KSHORT nFixedWidth, const KSHORT nFixedPos)
181 : SwGluePortion(nFixedWidth), nFix(nFixedPos)
182 {
183 SetWhichPor( POR_FIX );
184 }
185
186 /*************************************************************************
187 * class SwMarginPortion
188 *************************************************************************/
189
SwMarginPortion(const KSHORT nFixedWidth)190 SwMarginPortion::SwMarginPortion( const KSHORT nFixedWidth )
191 :SwGluePortion( nFixedWidth )
192 {
193 SetWhichPor( POR_MARGIN );
194 }
195
196 /*************************************************************************
197 * SwMarginPortion::AdjustRight()
198 *
199 * In der umschliessenden Schleife werden alle Portions durchsucht,
200 * dabei werden erst die am Ende liegenden GluePortions verarbeitet.
201 * Das Ende wird nach jeder Schleife nach vorne verlegt, bis keine
202 * GluePortions mehr vorhanden sind.
203 * Es werden immer GluePortion-Paare betrachtet (pLeft und pRight),
204 * wobei Textportions zwischen pLeft und pRight hinter pRight verschoben
205 * werden, wenn pRight genuegend Glue besitzt. Bei jeder Verschiebung
206 * wandert ein Teil des Glues von pRight nach pLeft.
207 * Im naechsten Schleifendurchlauf ist pLeft das pRight und das Spiel
208 * beginnt von vorne.
209 *************************************************************************/
210
AdjustRight(const SwLineLayout * pCurr)211 void SwMarginPortion::AdjustRight( const SwLineLayout *pCurr )
212 {
213 SwGluePortion *pRight = 0;
214 sal_Bool bNoMove = 0 != pCurr->GetpKanaComp();
215 while( pRight != this )
216 {
217
218 // 1) Wir suchen den linken Glue
219 SwLinePortion *pPos = (SwLinePortion*)this;
220 SwGluePortion *pLeft = 0;
221 while( pPos )
222 {
223 DBG_LOOP;
224 if( pPos->InFixMargGrp() )
225 pLeft = (SwGluePortion*)pPos;
226 pPos = pPos->GetPortion();
227 if( pPos == pRight)
228 pPos = 0;
229 }
230
231 // Zwei nebeneinander liegende FlyPortions verschmelzen
232 if( pRight && pLeft->GetPortion() == pRight )
233 {
234 pRight->MoveAllGlue( pLeft );
235 pRight = 0;
236 }
237 KSHORT nRightGlue = pRight && 0 < pRight->GetPrtGlue()
238 ? KSHORT(pRight->GetPrtGlue()) : 0;
239 // 2) linken und rechten Glue ausgleichen
240 // Bei Tabs haengen wir nix um ...
241 if( pLeft && nRightGlue && !pRight->InTabGrp() )
242 {
243 // pPrev ist die Portion, die unmittelbar vor pRight liegt.
244 SwLinePortion *pPrev = pRight->FindPrevPortion( pLeft );
245
246 if ( pRight->IsFlyPortion() && pRight->GetLen() )
247 {
248 SwFlyPortion *pFly = (SwFlyPortion *)pRight;
249 if ( pFly->GetBlankWidth() < nRightGlue )
250 {
251 // Hier entsteht eine neue TxtPortion, die dass zuvor
252 // vom Fly verschluckte Blank reaktiviert.
253 nRightGlue = nRightGlue - pFly->GetBlankWidth();
254 pFly->SubPrtWidth( pFly->GetBlankWidth() );
255 pFly->SetLen( 0 );
256 SwTxtPortion *pNewPor = new SwTxtPortion;
257 pNewPor->SetLen( 1 );
258 pNewPor->Height( pFly->Height() );
259 pNewPor->Width( pFly->GetBlankWidth() );
260 pFly->Insert( pNewPor );
261 }
262 else
263 pPrev = pLeft;
264 }
265 while( pPrev != pLeft )
266 {
267 DBG_LOOP;
268
269 if( bNoMove || pPrev->PrtWidth() >= nRightGlue ||
270 pPrev->InHyphGrp() || pPrev->IsKernPortion() )
271 {
272 // Die Portion, die vor pRight liegt kann nicht
273 // verschoben werden, weil kein Glue mehr vorhanden ist.
274 // Wir fuehren die Abbruchbedingung herbei:
275 pPrev = pLeft;
276 }
277 else
278 {
279 nRightGlue = nRightGlue - pPrev->PrtWidth();
280 // pPrev wird hinter pRight verschoben.
281 // Dazu wird der Gluewert zwischen pRight und pLeft
282 // ausgeglichen.
283 pRight->MoveGlue( pLeft, short( pPrev->PrtWidth() ) );
284 // Jetzt wird die Verkettung gerichtet.
285 SwLinePortion *pPrevPrev = pPrev->FindPrevPortion( pLeft );
286 pPrevPrev->SetPortion( pRight );
287 pPrev->SetPortion( pRight->GetPortion() );
288 pRight->SetPortion( pPrev );
289 if ( pPrev->GetPortion() && pPrev->InTxtGrp()
290 && pPrev->GetPortion()->IsHolePortion() )
291 {
292 SwHolePortion *pHolePor =
293 (SwHolePortion*)pPrev->GetPortion();
294 if ( !pHolePor->GetPortion() ||
295 !pHolePor->GetPortion()->InFixMargGrp() )
296 {
297 pPrev->AddPrtWidth( pHolePor->GetBlankWidth() );
298 pPrev->SetLen( pPrev->GetLen() + 1 );
299 pPrev->SetPortion( pHolePor->GetPortion() );
300 delete pHolePor;
301 }
302 }
303 pPrev = pPrevPrev;
304 }
305 }
306 }
307 // Wenn es keinen linken Glue mehr gibt, wird die Abbruchbedingung
308 // herbeigefuehrt.
309 pRight = pLeft ? pLeft : (SwGluePortion*)this;
310 }
311 }
312
313
314
315