xref: /trunk/main/sw/source/core/text/porglue.cxx (revision efeef26f)
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