xref: /trunk/main/sw/source/core/text/pormulti.cxx (revision f6675432)
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 #include <hintids.hxx>
29 
30 #include <com/sun/star/i18n/ScriptType.hdl>
31 #include <editeng/twolinesitem.hxx>
32 #include <editeng/charrotateitem.hxx>
33 #include <vcl/outdev.hxx>
34 #include <fmtfld.hxx>
35 #include <fldbas.hxx>	// SwField
36 #include <txatbase.hxx>
37 #include <fmtruby.hxx>	// SwFmtRuby
38 #include <txtatr.hxx>	// SwTxtRuby
39 #include <charfmt.hxx>
40 #include <txtinet.hxx>
41 #include <fchrfmt.hxx>
42 #include <layfrm.hxx>		// GetUpper()
43 #include <SwPortionHandler.hxx>
44 #include <pormulti.hxx> 	// SwMultiPortion
45 #include <inftxt.hxx>		// SwTxtSizeInfo
46 #include <itrpaint.hxx>		// SwTxtPainter
47 #include <viewopt.hxx>		// SwViewOptions
48 #include <itrform2.hxx>		// SwTxtFormatter
49 #include <porfld.hxx>		// SwFldPortion
50 #include <porglue.hxx>
51 #include <breakit.hxx>
52 #include <pagefrm.hxx>
53 #include <rowfrm.hxx>
54 #include <pagedesc.hxx>	// SwPageDesc
55 #include <tgrditem.hxx>
56 #include <swtable.hxx>
57 #include <fmtfsize.hxx>
58 
59 using namespace ::com::sun::star;
60 extern sal_Bool IsUnderlineBreak( const SwLinePortion& rPor, const SwFont& rFnt );
61 
62 /*-----------------10.10.00 15:23-------------------
63  * class SwMultiPortion
64  *
65  * A SwMultiPortion is not a simple portion,
66  * it's a container, which contains almost a SwLineLayoutPortion.
67  * This SwLineLayout could be followed by other textportions via pPortion
68  * and by another SwLineLayout via pNext to realize a doubleline portion.
69  * --------------------------------------------------*/
70 
~SwMultiPortion()71 SwMultiPortion::~SwMultiPortion()
72 {
73 	delete pFldRest;
74 }
75 
Paint(const SwTxtPaintInfo &) const76 void SwMultiPortion::Paint( const SwTxtPaintInfo & ) const
77 {
78 	ASSERT( sal_False,
79 	"Don't try SwMultiPortion::Paint, try SwTxtPainter::PaintMultiPortion" );
80 }
81 
82 /*-----------------13.10.00 16:21-------------------
83  * Summarize the internal lines to calculate the (external) size.
84  * The internal line has to calculate first.
85  * --------------------------------------------------*/
86 
CalcSize(SwTxtFormatter & rLine,SwTxtFormatInfo & rInf)87 void SwMultiPortion::CalcSize( SwTxtFormatter& rLine, SwTxtFormatInfo &rInf )
88 {
89 	Width( 0 );
90 	Height( 0 );
91 	SetAscent( 0 );
92 	SetFlyInCntnt( sal_False );
93 	SwLineLayout *pLay = &GetRoot();
94 	do
95 	{
96 		pLay->CalcLine( rLine, rInf );
97 		if( rLine.IsFlyInCntBase() )
98 			SetFlyInCntnt( sal_True );
99 		if( IsRuby() && ( OnTop() == ( pLay == &GetRoot() ) ) )
100 		{
101 			// An empty phonetic line doesn't need an ascent or a height.
102 			if( !pLay->Width() )
103 			{
104 				pLay->SetAscent( 0 );
105 				pLay->Height( 0 );
106 			}
107 			if( OnTop() )
108 				SetAscent( GetAscent() + pLay->Height() );
109 		}
110 		else
111 			SetAscent( GetAscent() + pLay->GetAscent() );
112 		Height( Height() + pLay->Height() );
113 		if( Width() < pLay->Width() )
114 			Width( pLay->Width() );
115 		pLay = pLay->GetNext();
116 	} while ( pLay );
117 	if( HasBrackets() )
118 	{
119 		KSHORT nTmp = ((SwDoubleLinePortion*)this)->GetBrackets()->nHeight;
120 		if( nTmp > Height() )
121 		{
122 			KSHORT nAdd = ( nTmp - Height() ) / 2;
123 			GetRoot().SetAscent( GetRoot().GetAscent() + nAdd );
124 			GetRoot().Height( GetRoot().Height() + nAdd );
125 			Height( nTmp );
126 		}
127 		nTmp = ((SwDoubleLinePortion*)this)->GetBrackets()->nAscent;
128 		if( nTmp > GetAscent() )
129 			SetAscent( nTmp );
130 	}
131 }
132 
CalcSpacing(long,const SwTxtSizeInfo &) const133 long SwMultiPortion::CalcSpacing( long , const SwTxtSizeInfo & ) const
134 {
135 	return 0;
136 }
137 
ChgSpaceAdd(SwLineLayout *,long) const138 sal_Bool SwMultiPortion::ChgSpaceAdd( SwLineLayout*, long ) const
139 {
140 	return sal_False;
141 }
142 
143 /*************************************************************************
144  * virtual SwMultiPortion::HandlePortion()
145  *************************************************************************/
146 
HandlePortion(SwPortionHandler & rPH) const147 void SwMultiPortion::HandlePortion( SwPortionHandler& rPH ) const
148 {
149 	rPH.Text( GetLen(), GetWhichPor() );
150 }
151 
152 /*-----------------01.11.00 14:21-------------------
153  * SwMultiPortion::ActualizeTabulator()
154  * sets the tabulator-flag, if there's any tabulator-portion inside.
155  * --------------------------------------------------*/
156 
ActualizeTabulator()157 void SwMultiPortion::ActualizeTabulator()
158 {
159 	SwLinePortion* pPor = GetRoot().GetFirstPortion();
160 	// First line
161 	for( bTab1 = bTab2 = sal_False; pPor; pPor = pPor->GetPortion() )
162 		if( pPor->InTabGrp() )
163 			SetTab1( sal_True );
164 	if( GetRoot().GetNext() )
165 	{
166 		// Second line
167 		pPor = GetRoot().GetNext()->GetFirstPortion();
168 		do
169 		{
170 			if( pPor->InTabGrp() )
171 				SetTab2( sal_True );
172 			pPor = pPor->GetPortion();
173 		} while ( pPor );
174 	}
175 }
176 
177 /*-----------------16.02.01 12:07-------------------
178  * SwRotatedPortion::SwRotatedPortion(..)
179  * --------------------------------------------------*/
180 
SwRotatedPortion(const SwMultiCreator & rCreate,xub_StrLen nEnd,sal_Bool bRTL)181 SwRotatedPortion::SwRotatedPortion( const SwMultiCreator& rCreate,
182 	xub_StrLen nEnd, sal_Bool bRTL ) : SwMultiPortion( nEnd )
183 {
184 	const SvxCharRotateItem* pRot = (SvxCharRotateItem*)rCreate.pItem;
185 	if( !pRot )
186 	{
187 		const SwTxtAttr& rAttr = *rCreate.pAttr;
188 		const SfxPoolItem *const pItem =
189 				CharFmt::GetItem(rAttr, RES_CHRATR_ROTATE);
190 		if ( pItem )
191 		{
192 			pRot = static_cast<const SvxCharRotateItem*>(pItem);
193 		}
194 	}
195 	if( pRot )
196 	{
197 		sal_uInt8 nDir;
198 		if ( bRTL )
199 			nDir = pRot->IsBottomToTop() ? 3 : 1;
200 		else
201 			nDir = pRot->IsBottomToTop() ? 1 : 3;
202 
203 		SetDirection( nDir );
204 	}
205 }
206 
207 /*---------------------------------------------------
208  * SwBidiPortion::SwBidiPortion(..)
209  * --------------------------------------------------*/
210 
SwBidiPortion(xub_StrLen nEnd,sal_uInt8 nLv)211 SwBidiPortion::SwBidiPortion( xub_StrLen nEnd, sal_uInt8 nLv )
212 	: SwMultiPortion( nEnd ), nLevel( nLv )
213 {
214 	SetBidi();
215 
216 	if ( nLevel % 2 )
217 		SetDirection( DIR_RIGHT2LEFT );
218 	else
219 		SetDirection( DIR_LEFT2RIGHT );
220 }
221 
222 
CalcSpacing(long nSpaceAdd,const SwTxtSizeInfo & rInf) const223 long SwBidiPortion::CalcSpacing( long nSpaceAdd, const SwTxtSizeInfo& rInf ) const
224 {
225 	return HasTabulator() ? 0 : GetSpaceCnt(rInf) * nSpaceAdd / SPACING_PRECISION_FACTOR;
226 }
227 
ChgSpaceAdd(SwLineLayout * pCurr,long nSpaceAdd) const228 sal_Bool SwBidiPortion::ChgSpaceAdd( SwLineLayout* pCurr, long nSpaceAdd ) const
229 {
230 	sal_Bool bRet = sal_False;
231 	if( !HasTabulator() && nSpaceAdd > 0 && !pCurr->IsSpaceAdd() )
232 	{
233 		pCurr->CreateSpaceAdd();
234 		pCurr->SetLLSpaceAdd( nSpaceAdd, 0 );
235 		bRet = sal_True;
236 	}
237 
238 	return bRet;
239 }
240 
GetSpaceCnt(const SwTxtSizeInfo & rInf) const241 xub_StrLen SwBidiPortion::GetSpaceCnt( const SwTxtSizeInfo &rInf ) const
242 {
243 	// Calculate number of blanks for justified alignment
244 	SwLinePortion* pPor = GetRoot().GetFirstPortion();
245 	xub_StrLen nTmpStart = rInf.GetIdx();
246 	xub_StrLen nNull = 0;
247 	xub_StrLen nBlanks;
248 
249 	for( nBlanks = 0; pPor; pPor = pPor->GetPortion() )
250 	{
251 		if( pPor->InTxtGrp() )
252 			nBlanks = nBlanks + ((SwTxtPortion*)pPor)->GetSpaceCnt( rInf, nNull );
253 		else if ( pPor->IsMultiPortion() &&
254 				  ((SwMultiPortion*)pPor)->IsBidi() )
255 			nBlanks = nBlanks + ((SwBidiPortion*)pPor)->GetSpaceCnt( rInf );
256 
257 		((SwTxtSizeInfo &)rInf).SetIdx( rInf.GetIdx() + pPor->GetLen() );
258 	}
259 	((SwTxtSizeInfo &)rInf).SetIdx( nTmpStart );
260 	return nBlanks;
261 }
262 
263 /*-----------------01.11.00 14:22-------------------
264  * SwDoubleLinePortion::SwDoubleLinePortion(..)
265  * This constructor is for the continuation of a doubleline portion
266  * in the next line.
267  * It takes the same brackets and if the original has no content except
268  * brackets, these will be deleted.
269  * --------------------------------------------------*/
270 
SwDoubleLinePortion(SwDoubleLinePortion & rDouble,xub_StrLen nEnd)271 SwDoubleLinePortion::SwDoubleLinePortion( SwDoubleLinePortion& rDouble,
272 										  xub_StrLen nEnd ) :
273 	SwMultiPortion( nEnd ),
274 	pBracket( 0 )
275 {
276 	SetDirection( rDouble.GetDirection() );
277 	SetDouble();
278 	if( rDouble.GetBrackets() )
279 	{
280 		SetBrackets( rDouble );
281 		// An empty multiportion needs no brackets.
282 		// Notice: GetLen() might be zero, if the multiportion contains
283 		// the second part of a field and the width might be zero, if
284 		// it contains a note only. In this cases the brackets are okay.
285 		// But if the length and the width are both zero, the portion
286 		// is really empty.
287 		if( rDouble.Width() ==	rDouble.BracketWidth() )
288 			rDouble.ClearBrackets();
289 	}
290 }
291 
292 /*-----------------01.11.00 14:22-------------------
293  * SwDoubleLinePortion::SwDoubleLinePortion(..)
294  * This constructor uses the textattribut to get the right brackets.
295  * The textattribut could be a 2-line-attribute or a character- or
296  * internetstyle, which contains the 2-line-attribute.
297  * --------------------------------------------------*/
298 
SwDoubleLinePortion(const SwMultiCreator & rCreate,xub_StrLen nEnd)299 SwDoubleLinePortion::SwDoubleLinePortion( const SwMultiCreator& rCreate,
300 	xub_StrLen nEnd ) : SwMultiPortion( nEnd ), pBracket( new SwBracket() )
301 {
302 	SetDouble();
303 	const SvxTwoLinesItem* pTwo = (SvxTwoLinesItem*)rCreate.pItem;
304 	if( pTwo )
305 		pBracket->nStart = 0;
306 	else
307 	{
308 		const SwTxtAttr& rAttr = *rCreate.pAttr;
309 		pBracket->nStart = *rAttr.GetStart();
310 
311 		const SfxPoolItem * const pItem =
312 			CharFmt::GetItem( rAttr, RES_CHRATR_TWO_LINES );
313 		if ( pItem )
314 		{
315 			pTwo = static_cast<const SvxTwoLinesItem*>(pItem);
316 		}
317 	}
318 	if( pTwo )
319 	{
320 		pBracket->cPre = pTwo->GetStartBracket();
321 		pBracket->cPost = pTwo->GetEndBracket();
322 	}
323 	else
324 	{
325 		pBracket->cPre = 0;
326 		pBracket->cPost = 0;
327 	}
328 	sal_uInt8 nTmp = SW_SCRIPTS;
329 	if( pBracket->cPre > 255 )
330 	{
331 		String aTxt( pBracket->cPre );
332 		nTmp = SwScriptInfo::WhichFont( 0, &aTxt, 0 );
333 	}
334 	pBracket->nPreScript = nTmp;
335 	nTmp = SW_SCRIPTS;
336 	if( pBracket->cPost > 255 )
337 	{
338 		String aTxt( pBracket->cPost );
339 		nTmp = SwScriptInfo::WhichFont( 0, &aTxt, 0 );
340 	}
341 	pBracket->nPostScript = nTmp;
342 
343 	if( !pBracket->cPre && !pBracket->cPost )
344 	{
345 		delete pBracket;
346 		pBracket = 0;
347 	}
348 
349 	// double line portions have the same direction as the frame directions
350 	if ( rCreate.nLevel % 2 )
351 		SetDirection( DIR_RIGHT2LEFT );
352 	else
353 		SetDirection( DIR_LEFT2RIGHT );
354 }
355 
356 
357 /*-----------------25.10.00 09:51-------------------
358  * SwMultiPortion::PaintBracket paints the wished bracket,
359  * if the multiportion has surrounding brackets.
360  * The X-position of the SwTxtPaintInfo will be modified:
361  * the open bracket sets position behind itself,
362  * the close bracket in front of itself.
363  * --------------------------------------------------*/
364 
PaintBracket(SwTxtPaintInfo & rInf,long nSpaceAdd,sal_Bool bOpen) const365 void SwDoubleLinePortion::PaintBracket( SwTxtPaintInfo &rInf,
366 										long nSpaceAdd,
367 										sal_Bool bOpen ) const
368 {
369 	sal_Unicode cCh = bOpen ? pBracket->cPre : pBracket->cPost;
370 	if( !cCh )
371 		return;
372 	KSHORT nChWidth = bOpen ? PreWidth() : PostWidth();
373 	if( !nChWidth )
374 		return;
375 	if( !bOpen )
376 		rInf.X( rInf.X() + Width() - PostWidth() +
377 			( nSpaceAdd > 0 ? CalcSpacing( nSpaceAdd, rInf ) : 0 ) );
378 
379 	SwBlankPortion aBlank( cCh, sal_True );
380 	aBlank.SetAscent( pBracket->nAscent );
381 	aBlank.Width( nChWidth );
382 	aBlank.Height( pBracket->nHeight );
383 	{
384 		SwFont* pTmpFnt = new SwFont( *rInf.GetFont() );
385 		sal_uInt8 nAct = bOpen ? pBracket->nPreScript : pBracket->nPostScript;
386 		if( SW_SCRIPTS > nAct )
387 			pTmpFnt->SetActual( nAct );
388 		pTmpFnt->SetProportion( 100 );
389 		SwFontSave aSave( rInf, pTmpFnt );
390 		aBlank.Paint( rInf );
391 		delete pTmpFnt;
392 	}
393 	if( bOpen )
394 		rInf.X( rInf.X() + PreWidth() );
395 }
396 
397 /*-----------------25.10.00 16:26-------------------
398  * SwDoubleLinePortion::SetBrackets creates the bracket-structure
399  * and fills it, if not both characters are 0x00.
400  * --------------------------------------------------*/
401 
SetBrackets(const SwDoubleLinePortion & rDouble)402 void SwDoubleLinePortion::SetBrackets( const SwDoubleLinePortion& rDouble )
403 {
404 	if( rDouble.pBracket )
405 	{
406 		pBracket = new SwBracket;
407 		pBracket->cPre = rDouble.pBracket->cPre;
408 		pBracket->cPost = rDouble.pBracket->cPost;
409 		pBracket->nPreScript = rDouble.pBracket->nPreScript;
410 		pBracket->nPostScript = rDouble.pBracket->nPostScript;
411 		pBracket->nStart = rDouble.pBracket->nStart;
412 	}
413 }
414 
415 /*-----------------25.10.00 16:29-------------------
416  * SwDoubleLinePortion::FormatBrackets
417  * calculates the size of the brackets => pBracket,
418  * reduces the nMaxWidth-parameter ( minus bracket-width )
419  * and moves the rInf-x-position behind the opening bracket.
420  * --------------------------------------------------*/
421 
FormatBrackets(SwTxtFormatInfo & rInf,SwTwips & nMaxWidth)422 void SwDoubleLinePortion::FormatBrackets( SwTxtFormatInfo &rInf, SwTwips& nMaxWidth )
423 {
424 	nMaxWidth -= rInf.X();
425 	SwFont* pTmpFnt = new SwFont( *rInf.GetFont() );
426 	pTmpFnt->SetProportion( 100 );
427 	pBracket->nAscent = 0;
428 	pBracket->nHeight = 0;
429 	if( pBracket->cPre )
430 	{
431 		String aStr( pBracket->cPre );
432 		sal_uInt8 nActualScr = pTmpFnt->GetActual();
433 		if( SW_SCRIPTS > pBracket->nPreScript )
434 			pTmpFnt->SetActual( pBracket->nPreScript );
435 		SwFontSave aSave( rInf, pTmpFnt );
436 		SwPosSize aSize = rInf.GetTxtSize( aStr );
437 		pBracket->nAscent = rInf.GetAscent();
438 		pBracket->nHeight = aSize.Height();
439 		pTmpFnt->SetActual( nActualScr );
440 		if( nMaxWidth > aSize.Width() )
441 		{
442 			pBracket->nPreWidth = aSize.Width();
443 			nMaxWidth -= aSize.Width();
444 			rInf.X( rInf.X() + aSize.Width() );
445 		}
446 		else
447 		{
448 			pBracket->nPreWidth = 0;
449 			nMaxWidth = 0;
450 		}
451 	}
452 	else
453 		pBracket->nPreWidth = 0;
454 	if( pBracket->cPost )
455 	{
456 		String aStr( pBracket->cPost );
457 		if( SW_SCRIPTS > pBracket->nPostScript )
458 			pTmpFnt->SetActual( pBracket->nPostScript );
459 		SwFontSave aSave( rInf, pTmpFnt );
460 		SwPosSize aSize = rInf.GetTxtSize( aStr );
461 		KSHORT nTmpAsc = rInf.GetAscent();
462 		if( nTmpAsc > pBracket->nAscent )
463 		{
464 			pBracket->nHeight += nTmpAsc - pBracket->nAscent;
465 			pBracket->nAscent = nTmpAsc;
466 		}
467 		if( aSize.Height() > pBracket->nHeight )
468 			pBracket->nHeight = aSize.Height();
469 		if( nMaxWidth > aSize.Width() )
470 		{
471 			pBracket->nPostWidth = aSize.Width();
472 			nMaxWidth -= aSize.Width();
473 		}
474 		else
475 		{
476 			pBracket->nPostWidth = 0;
477 			nMaxWidth = 0;
478 		}
479 	}
480 	else
481 		pBracket->nPostWidth = 0;
482 	nMaxWidth += rInf.X();
483 }
484 
485 /*-----------------26.10.00 10:36-------------------
486  * SwDoubleLinePortion::CalcBlanks
487  * calculates the number of blanks in each line and
488  * the difference of the width of the two lines.
489  * These results are used from the text adjustment.
490  * --------------------------------------------------*/
491 
CalcBlanks(SwTxtFormatInfo & rInf)492 void SwDoubleLinePortion::CalcBlanks( SwTxtFormatInfo &rInf )
493 {
494 	SwLinePortion* pPor = GetRoot().GetFirstPortion();
495 	xub_StrLen nNull = 0;
496 	xub_StrLen nStart = rInf.GetIdx();
497 	SetTab1( sal_False );
498 	SetTab2( sal_False );
499 	for( nBlank1 = 0; pPor; pPor = pPor->GetPortion() )
500 	{
501 		if( pPor->InTxtGrp() )
502 			nBlank1 = nBlank1 + ((SwTxtPortion*)pPor)->GetSpaceCnt( rInf, nNull );
503 		rInf.SetIdx( rInf.GetIdx() + pPor->GetLen() );
504 		if( pPor->InTabGrp() )
505 			SetTab1( sal_True );
506 	}
507 	nLineDiff = GetRoot().Width();
508 	if( GetRoot().GetNext() )
509 	{
510 		pPor = GetRoot().GetNext()->GetFirstPortion();
511 		nLineDiff -= GetRoot().GetNext()->Width();
512 	}
513 	for( nBlank2 = 0; pPor; pPor = pPor->GetPortion() )
514 	{
515 		if( pPor->InTxtGrp() )
516 			nBlank2 = nBlank2 + ((SwTxtPortion*)pPor)->GetSpaceCnt( rInf, nNull );
517 		rInf.SetIdx( rInf.GetIdx() + pPor->GetLen() );
518 		if( pPor->InTabGrp() )
519 			SetTab2( sal_True );
520 	}
521 	rInf.SetIdx( nStart );
522 }
523 
CalcSpacing(long nSpaceAdd,const SwTxtSizeInfo &) const524 long SwDoubleLinePortion::CalcSpacing( long nSpaceAdd, const SwTxtSizeInfo & ) const
525 {
526 	return HasTabulator() ? 0 : GetSpaceCnt() * nSpaceAdd / SPACING_PRECISION_FACTOR;
527 }
528 
529 /*-----------------01.11.00 14:29-------------------
530  * SwDoubleLinePortion::ChangeSpaceAdd(..)
531  * merges the spaces for text adjustment from the inner and outer part.
532  * Inside the doubleline portion the wider line has no spaceadd-array, the
533  * smaller line has such an array to reach width of the wider line.
534  * If the surrounding line has text adjustment and the doubleline portion
535  * contains no tabulator, it is necessary to create/manipulate the inner
536  * space arrays.
537  * --------------------------------------------------*/
538 
ChgSpaceAdd(SwLineLayout * pCurr,long nSpaceAdd) const539 sal_Bool SwDoubleLinePortion::ChgSpaceAdd( SwLineLayout* pCurr,
540 										   long nSpaceAdd ) const
541 {
542 	sal_Bool bRet = sal_False;
543 	if( !HasTabulator() && nSpaceAdd > 0 )
544 	{
545 		if( !pCurr->IsSpaceAdd() )
546 		{
547 			// The wider line gets the spaceadd from the surrounding line direct
548 			pCurr->CreateSpaceAdd();
549 			pCurr->SetLLSpaceAdd( nSpaceAdd, 0 );
550 			bRet = sal_True;
551 		}
552 		else
553 		{
554 			xub_StrLen nMyBlank = GetSmallerSpaceCnt();
555 			xub_StrLen nOther = GetSpaceCnt();
556 			SwTwips nMultiSpace = pCurr->GetLLSpaceAdd( 0 ) * nMyBlank + nOther * nSpaceAdd;
557 
558 			if( nMyBlank )
559 				nMultiSpace /= nMyBlank;
560 
561 			if( nMultiSpace < KSHRT_MAX * SPACING_PRECISION_FACTOR )
562 			{
563 //				pCurr->SetLLSpaceAdd( nMultiSpace, 0 );
564 				// --> FME 2006-07-11 #i65711# SetLLSpaceAdd replaces the first value,
565 				// instead we want to insert a new first value:
566 				std::vector<long>* pVec = pCurr->GetpLLSpaceAdd();
567 				pVec->insert( pVec->begin(), nMultiSpace );
568 				// <--
569 				bRet = sal_True;
570 			}
571 		}
572 	}
573 	return bRet;
574 }
575 /*-----------------01.11.00 14:29-------------------
576  * SwDoubleLinePortion::ResetSpaceAdd(..)
577  * cancels the manipulation from SwDoubleLinePortion::ChangeSpaceAdd(..)
578  * --------------------------------------------------*/
579 
ResetSpaceAdd(SwLineLayout * pCurr)580 void SwDoubleLinePortion::ResetSpaceAdd( SwLineLayout* pCurr )
581 {
582 	pCurr->RemoveFirstLLSpaceAdd();;
583 	if( !pCurr->GetLLSpaceAddCount() )
584 		pCurr->FinishSpaceAdd();
585 }
586 
~SwDoubleLinePortion()587 SwDoubleLinePortion::~SwDoubleLinePortion()
588 {
589 	delete pBracket;
590 }
591 
592 /*-----------------13.11.00 14:50-------------------
593  * SwRubyPortion::SwRubyPortion(..)
594  * constructs a ruby portion, i.e. an additional text is displayed
595  * beside the main text, e.g. phonetic characters.
596  * --------------------------------------------------*/
597 
598 
SwRubyPortion(const SwRubyPortion & rRuby,xub_StrLen nEnd)599 SwRubyPortion::SwRubyPortion( const SwRubyPortion& rRuby, xub_StrLen nEnd ) :
600 	SwMultiPortion( nEnd ),
601 	nRubyOffset( rRuby.GetRubyOffset() ),
602 	nAdjustment( rRuby.GetAdjustment() )
603 {
604 	SetDirection( rRuby.GetDirection() ),
605 	SetTop( rRuby.OnTop() );
606 	SetRuby();
607 }
608 
609 /*-----------------13.11.00 14:50-------------------
610  * SwRubyPortion::SwRubyPortion(..)
611  * constructs a ruby portion, i.e. an additional text is displayed
612  * beside the main text, e.g. phonetic characters.
613  * --------------------------------------------------*/
614 
SwRubyPortion(const SwMultiCreator & rCreate,const SwFont & rFnt,const IDocumentSettingAccess & rIDocumentSettingAccess,xub_StrLen nEnd,xub_StrLen nOffs,const sal_Bool * pForceRubyPos)615 SwRubyPortion::SwRubyPortion( const SwMultiCreator& rCreate, const SwFont& rFnt,
616 							  const IDocumentSettingAccess& rIDocumentSettingAccess,
617 							   xub_StrLen nEnd, xub_StrLen nOffs,
618 							  const sal_Bool* pForceRubyPos )
619 	: SwMultiPortion( nEnd )
620 {
621 	SetRuby();
622 	ASSERT( SW_MC_RUBY == rCreate.nId, "Ruby expected" );
623 	ASSERT( RES_TXTATR_CJK_RUBY == rCreate.pAttr->Which(), "Wrong attribute" );
624 	const SwFmtRuby& rRuby = rCreate.pAttr->GetRuby();
625 	nAdjustment = rRuby.GetAdjustment();
626 	nRubyOffset = nOffs;
627 
628 	// in grid mode we force the ruby text to the upper or lower line
629 	if ( pForceRubyPos )
630 		SetTop( *pForceRubyPos );
631 	else
632 		SetTop( ! rRuby.GetPosition() );
633 
634 	const SwCharFmt* pFmt = ((SwTxtRuby*)rCreate.pAttr)->GetCharFmt();
635 	SwFont *pRubyFont;
636 	if( pFmt )
637 	{
638 		const SwAttrSet& rSet = pFmt->GetAttrSet();
639 	 	pRubyFont = new SwFont( rFnt );
640 		pRubyFont->SetDiffFnt( &rSet, &rIDocumentSettingAccess );
641 
642 		// we do not allow a vertical font for the ruby text
643 		pRubyFont->SetVertical( rFnt.GetOrientation() );
644 	}
645 	else
646 		pRubyFont = NULL;
647 
648 	String aStr( rRuby.GetText(), nOffs, STRING_LEN );
649 	SwFldPortion *pFld = new SwFldPortion( aStr, pRubyFont );
650 	pFld->SetNextOffset( nOffs );
651 	pFld->SetFollow( sal_True );
652 
653 	if( OnTop() )
654 		GetRoot().SetPortion( pFld );
655 	else
656 	{
657 		GetRoot().SetNext( new SwLineLayout() );
658 		GetRoot().GetNext()->SetPortion( pFld );
659 	}
660 
661 	// ruby portions have the same direction as the frame directions
662 	if ( rCreate.nLevel % 2 )
663 	{
664 		// switch right and left ruby adjustment in rtl environment
665 		if ( 0 == nAdjustment )
666 			nAdjustment = 2;
667 		else if ( 2 == nAdjustment )
668 			nAdjustment = 0;
669 
670 		SetDirection( DIR_RIGHT2LEFT );
671 	}
672 	else
673 		SetDirection( DIR_LEFT2RIGHT );
674 }
675 
676 /*-----------------13.11.00 14:56-------------------
677  * SwRubyPortion::_Adjust(..)
678  * In ruby portion there are different alignments for
679  * the ruby text and the main text.
680  * Left, right, centered and two possibilities of block adjustment
681  * The block adjustment is realized by spacing between the characters,
682  * either with a half space or no space in front of the first letter and
683  * a half space at the end of the last letter.
684  * Notice: the smaller line will be manipulated, normally it's the ruby line,
685  * but it could be the main text, too.
686  * If there is a tabulator in smaller line, no adjustment is possible.
687  * --------------------------------------------------*/
688 
_Adjust(SwTxtFormatInfo & rInf)689 void SwRubyPortion::_Adjust( SwTxtFormatInfo &rInf )
690 {
691 	SwTwips nLineDiff = GetRoot().Width() - GetRoot().GetNext()->Width();
692 	xub_StrLen nOldIdx = rInf.GetIdx();
693 	if( !nLineDiff )
694 		return;
695 	SwLineLayout *pCurr;
696 	if( nLineDiff < 0 )
697 	{ // The first line has to be adjusted.
698 		if( GetTab1() )
699 			return;
700 		pCurr = &GetRoot();
701 		nLineDiff = -nLineDiff;
702 	}
703 	else
704 	{ // The second line has to be adjusted.
705 		if( GetTab2() )
706 			return;
707 		pCurr = GetRoot().GetNext();
708 		rInf.SetIdx( nOldIdx + GetRoot().GetLen() );
709 	}
710 	KSHORT nLeft = 0;	// the space in front of the first letter
711 	KSHORT nRight = 0;	// the space at the end of the last letter
712 	sal_uInt16 nSub = 0;
713 	switch ( nAdjustment )
714 	{
715 		case 1: nRight = static_cast<sal_uInt16>(nLineDiff / 2); // no break
716 		case 2: nLeft  = static_cast<sal_uInt16>(nLineDiff - nRight); break;
717 		case 3: nSub   = 1; // no break
718 		case 4:
719 		{
720 			xub_StrLen nCharCnt = 0;
721 			SwLinePortion *pPor;
722 			for( pPor = pCurr->GetFirstPortion(); pPor; pPor = pPor->GetPortion() )
723 			{
724 				if( pPor->InTxtGrp() )
725 					((SwTxtPortion*)pPor)->GetSpaceCnt( rInf, nCharCnt );
726 				rInf.SetIdx( rInf.GetIdx() + pPor->GetLen() );
727 			}
728 			if( nCharCnt > nSub )
729 			{
730 				SwTwips nCalc = nLineDiff / ( nCharCnt - nSub );
731 				short nTmp;
732 				if( nCalc < SHRT_MAX )
733 					nTmp = -short(nCalc);
734 				else
735 					nTmp = SHRT_MIN;
736 
737 				pCurr->CreateSpaceAdd( SPACING_PRECISION_FACTOR * nTmp );
738 				nLineDiff -= nCalc * ( nCharCnt - 1 );
739 			}
740 			if( nLineDiff > 1 )
741 			{
742 				nRight = static_cast<sal_uInt16>(nLineDiff / 2);
743 				nLeft  = static_cast<sal_uInt16>(nLineDiff - nRight);
744 			}
745 			break;
746 		}
747 		default: ASSERT( sal_False, "New ruby adjustment" );
748 	}
749 	if( nLeft || nRight )
750 	{
751 		if( !pCurr->GetPortion() )
752 			pCurr->SetPortion( new SwTxtPortion( *pCurr ) );
753 		SwMarginPortion *pMarg = new SwMarginPortion( 0 );
754 		if( nLeft )
755 		{
756 			pMarg->AddPrtWidth( nLeft );
757 			pMarg->SetPortion( pCurr->GetPortion() );
758 			pCurr->SetPortion( pMarg );
759 		}
760 		if( nRight )
761 		{
762 			pMarg = new SwMarginPortion( 0 );
763 			pMarg->AddPrtWidth( nRight );
764 			pCurr->FindLastPortion()->Append( pMarg );
765 		}
766 	}
767 
768 	pCurr->Width( Width() );
769 	rInf.SetIdx( nOldIdx );
770 }
771 
772 /*-----------------08.11.00 14:14-------------------
773  * CalcRubyOffset()
774  * has to change the nRubyOffset, if there's a fieldportion
775  * in the phonetic line.
776  * The nRubyOffset is the position in the rubystring, where the
777  * next SwRubyPortion has start the displaying of the phonetics.
778  * --------------------------------------------------*/
779 
CalcRubyOffset()780 void SwRubyPortion::CalcRubyOffset()
781 {
782 	const SwLineLayout *pCurr = &GetRoot();
783 	if( !OnTop() )
784 	{
785 		pCurr = pCurr->GetNext();
786 		if( !pCurr )
787 			return;
788 	}
789 	const SwLinePortion *pPor = pCurr->GetFirstPortion();
790 	const SwFldPortion *pFld = NULL;
791 	while( pPor )
792 	{
793 		if( pPor->InFldGrp() )
794 			pFld = (SwFldPortion*)pPor;
795 		pPor = pPor->GetPortion();
796 	}
797 	if( pFld )
798 	{
799 		if( pFld->HasFollow() )
800 			nRubyOffset = pFld->GetNextOffset();
801 		else
802 			nRubyOffset = STRING_LEN;
803 	}
804 }
805 
806 /*-----------------13.10.00 16:22-------------------
807  * SwTxtSizeInfo::GetMultiCreator(..)
808  * If we (e.g. the position rPos) are inside a two-line-attribute or
809  * a ruby-attribute, the attribute will be returned in a SwMultiCreator-struct,
810  * otherwise the function returns zero.
811  * The rPos parameter is set to the end of the multiportion,
812  * normally this is the end of the attribute,
813  * but sometimes it is the start of another attribute, which finished or
814  * interrupts the first attribute.
815  * E.g. a ruby portion interrupts a 2-line-attribute, a 2-line-attribute
816  * with different brackets interrupts another 2-line-attribute.
817  * --------------------------------------------------*/
818 
819 /*-----------------13.11.00 15:38-------------------
820  * lcl_Has2Lines(..)
821  * is a little help function for GetMultiCreator(..)
822  * It extracts the 2-line-format from a 2-line-attribute or a character style.
823  * The rValue is set to sal_True, if the 2-line-attribute's value is set and
824  * no 2-line-format reference is passed. If there is a 2-line-format reference,
825  * then the rValue is set only, if the 2-line-attribute's value is set _and_
826  * the 2-line-formats has the same brackets.
827  * --------------------------------------------------*/
828 
lcl_Has2Lines(const SwTxtAttr & rAttr,const SvxTwoLinesItem * & rpRef,sal_Bool & rValue)829 sal_Bool lcl_Has2Lines( const SwTxtAttr& rAttr, const SvxTwoLinesItem* &rpRef,
830 	sal_Bool &rValue )
831 {
832 	const SfxPoolItem* pItem = CharFmt::GetItem( rAttr, RES_CHRATR_TWO_LINES );
833 	if( pItem )
834 	{
835 		rValue = ((SvxTwoLinesItem*)pItem)->GetValue();
836 		if( !rpRef )
837 			rpRef = (SvxTwoLinesItem*)pItem;
838 		else if( ((SvxTwoLinesItem*)pItem)->GetEndBracket() !=
839 					rpRef->GetEndBracket() ||
840 					((SvxTwoLinesItem*)pItem)->GetStartBracket() !=
841 					rpRef->GetStartBracket() )
842 			rValue = sal_False;
843 		return sal_True;
844 	}
845 	return sal_False;
846 }
847 
848 /*-----------------16.02.01 16:39-------------------
849  * lcl_HasRotation(..)
850  * is a little help function for GetMultiCreator(..)
851  * It extracts the charrotation from a charrotate-attribute or a character style.
852  * The rValue is set to sal_True, if the charrotate-attribute's value is set and
853  * no charrotate-format reference is passed.
854  * If there is a charrotate-format reference, then the rValue is set only,
855  * if the charrotate-attribute's value is set _and_ identical
856  * to the charrotate-format's value.
857  * --------------------------------------------------*/
858 
lcl_HasRotation(const SwTxtAttr & rAttr,const SvxCharRotateItem * & rpRef,sal_Bool & rValue)859 sal_Bool lcl_HasRotation( const SwTxtAttr& rAttr,
860 	const SvxCharRotateItem* &rpRef, sal_Bool &rValue )
861 {
862 	const SfxPoolItem* pItem = CharFmt::GetItem( rAttr, RES_CHRATR_ROTATE );
863 	if ( pItem )
864 	{
865 		rValue = 0 != ((SvxCharRotateItem*)pItem)->GetValue();
866 		if( !rpRef )
867 			rpRef = (SvxCharRotateItem*)pItem;
868 		else if( ((SvxCharRotateItem*)pItem)->GetValue() !=
869 					rpRef->GetValue() )
870 			rValue = sal_False;
871 		return sal_True;
872 	}
873 
874 	return sal_False;
875 }
876 
GetMultiCreator(xub_StrLen & rPos,SwMultiPortion * pMulti) const877 SwMultiCreator* SwTxtSizeInfo::GetMultiCreator( xub_StrLen &rPos,
878 												SwMultiPortion* pMulti ) const
879 {
880 	SwScriptInfo& rSI = ((SwParaPortion*)GetParaPortion())->GetScriptInfo();
881 
882 	// get the last embedding level
883 	sal_uInt8 nCurrLevel;
884 	if ( pMulti )
885 	{
886 		ASSERT( pMulti->IsBidi(), "Nested MultiPortion is not BidiPortion" )
887 		// level associated with bidi-portion;
888 		nCurrLevel = ((SwBidiPortion*)pMulti)->GetLevel();
889 	}
890 	else
891 		// no nested bidi portion required
892 		nCurrLevel = GetTxtFrm()->IsRightToLeft() ? 1 : 0;
893 
894 	// check if there is a field at rPos:
895 	sal_uInt8 nNextLevel = nCurrLevel;
896 	sal_Bool bFldBidi = sal_False;
897 
898 	if ( CH_TXTATR_BREAKWORD == GetChar( rPos ) )
899 	{
900 		bFldBidi = sal_True;
901 /*
902 		// examining the script of the field text should be sufficient
903 		// for 99% of all cases
904 		XubString aTxt = GetTxtFrm()->GetTxtNode()->GetExpandTxt( rPos, 1 );
905 
906 		if ( pBreakIt->GetBreakIter().is() && aTxt.Len() )
907 		{
908 			sal_Bool bFldDir = ( i18n::ScriptType::COMPLEX ==
909 								 pBreakIt->GetRealScriptOfText( aTxt, 0 ) );
910 			sal_Bool bCurrDir = ( 0 != ( nCurrLevel % 2 ) );
911 			if ( bFldDir != bCurrDir )
912 			{
913 				nNextLevel = nCurrLevel + 1;
914 				bFldBidi = sal_True;
915 			}
916 		}*/
917 	}
918 	else
919 		nNextLevel = rSI.DirType( rPos );
920 
921 	if ( GetTxt().Len() != rPos && nNextLevel > nCurrLevel )
922 	{
923 		rPos = bFldBidi ? rPos + 1 : rSI.NextDirChg( rPos, &nCurrLevel );
924 		if ( STRING_LEN == rPos )
925 			return NULL;
926 		SwMultiCreator *pRet = new SwMultiCreator;
927 		pRet->pItem = NULL;
928 		pRet->pAttr = NULL;
929 		pRet->nId = SW_MC_BIDI;
930 		pRet->nLevel = nCurrLevel + 1;
931 		return pRet;
932 	}
933 
934 	// a bidi portion can only contain other bidi portions
935 	if ( pMulti )
936 		return NULL;
937 
938 	const SvxCharRotateItem* pRotate = NULL;
939 	const SfxPoolItem* pRotItem;
940 	if( SFX_ITEM_SET == pFrm->GetTxtNode()->GetSwAttrSet().
941 		GetItemState( RES_CHRATR_ROTATE, sal_True, &pRotItem ) &&
942 		((SvxCharRotateItem*)pRotItem)->GetValue() )
943 		pRotate = (SvxCharRotateItem*)pRotItem;
944 	else
945 		pRotItem = NULL;
946 	const SvxTwoLinesItem* p2Lines = NULL;
947 	const SfxPoolItem* pItem;
948 	if( SFX_ITEM_SET == pFrm->GetTxtNode()->GetSwAttrSet().
949 		GetItemState( RES_CHRATR_TWO_LINES, sal_True, &pItem ) &&
950 		((SvxTwoLinesItem*)pItem)->GetValue() )
951 		p2Lines = (SvxTwoLinesItem*)pItem;
952 	else
953 		pItem = NULL;
954 
955 	const SwpHints *pHints = pFrm->GetTxtNode()->GetpSwpHints();
956 	if( !pHints && !p2Lines && !pRotate )
957 		return NULL;
958 	const SwTxtAttr *pRuby = NULL;
959 	sal_Bool bTwo = sal_False;
960 	sal_Bool bRot = sal_False;
961 	sal_uInt16 n2Lines = USHRT_MAX;
962 	sal_uInt16 nRotate = USHRT_MAX;
963 	sal_uInt16 nCount = pHints ? pHints->Count() : 0;
964 	sal_uInt16 i;
965 	for( i = 0; i < nCount; ++i )
966 	{
967 		const SwTxtAttr *pTmp = (*pHints)[i];
968 		xub_StrLen nStart = *pTmp->GetStart();
969 		if( rPos < nStart )
970 			break;
971 		if( *pTmp->GetAnyEnd() > rPos )
972 		{
973 			if( RES_TXTATR_CJK_RUBY == pTmp->Which() )
974 				pRuby = pTmp;
975 			else
976 			{
977 				const SvxCharRotateItem* pRoTmp = NULL;
978 				if( lcl_HasRotation( *pTmp, pRoTmp, bRot ) )
979 				{
980 					nRotate = bRot ? i : nCount;
981 					pRotate = pRoTmp;
982 				}
983 				const SvxTwoLinesItem* p2Tmp = NULL;
984 				if( lcl_Has2Lines( *pTmp, p2Tmp, bTwo ) )
985 				{
986 					n2Lines = bTwo ? i : nCount;
987 					p2Lines = p2Tmp;
988 				}
989 			}
990 		}
991 	}
992 	if( pRuby )
993 	{	// The winner is ... a ruby attribute and so
994 		// the end of the multiportion is the end of the ruby attribute.
995 		rPos = *pRuby->End();
996 		SwMultiCreator *pRet = new SwMultiCreator;
997 		pRet->pItem = NULL;
998 		pRet->pAttr = pRuby;
999 		pRet->nId = SW_MC_RUBY;
1000 		pRet->nLevel = GetTxtFrm()->IsRightToLeft() ? 1 : 0;
1001 		return pRet;
1002 	}
1003 	if( n2Lines < nCount || ( pItem && pItem == p2Lines &&
1004 		rPos < GetTxt().Len() ) )
1005 	{	// The winner is a 2-line-attribute,
1006 		// the end of the multiportion depends on the following attributes...
1007 		SwMultiCreator *pRet = new SwMultiCreator;
1008 
1009 		// We note the endpositions of the 2-line attributes in aEnd as stack
1010 		SvXub_StrLens aEnd;
1011 
1012 		// The bOn flag signs the state of the last 2-line attribute in the
1013 		// aEnd-stack, it is compatible with the winner-attribute or
1014 		// it interrupts the other attribute.
1015 		sal_Bool bOn = sal_True;
1016 
1017 		if( n2Lines < nCount )
1018 		{
1019 			pRet->pItem = NULL;
1020 			pRet->pAttr = (*pHints)[n2Lines];
1021 			aEnd.push_front( *pRet->pAttr->End() );
1022 			if( pItem )
1023 			{
1024 				aEnd.front() = GetTxt().Len();
1025 				bOn = ((SvxTwoLinesItem*)pItem)->GetEndBracket() ==
1026 						p2Lines->GetEndBracket() &&
1027 					  ((SvxTwoLinesItem*)pItem)->GetStartBracket() ==
1028 						p2Lines->GetStartBracket();
1029 			}
1030 		}
1031 		else
1032 		{
1033 			pRet->pItem = pItem;
1034 			pRet->pAttr = NULL;
1035 			aEnd.push_front( GetTxt().Len() );
1036 		}
1037 		pRet->nId = SW_MC_DOUBLE;
1038 		pRet->nLevel = GetTxtFrm()->IsRightToLeft() ? 1 : 0;
1039 
1040 		// n2Lines is the index of the last 2-line-attribute, which contains
1041 		// the actual position.
1042 		i = 0;
1043 		// At this moment we know that at position rPos the "winner"-attribute
1044 		// causes a 2-line-portion. The end of the attribute is the end of the
1045 		// portion, if there's no interrupting attribute.
1046 		// There are two kinds of interruptors:
1047 		// - ruby attributes stops the 2-line-attribute, the end of the
1048 		//	 multiline is the start of the ruby attribute
1049 		// - 2-line-attributes with value "Off" or with different brackets,
1050 		//	 these attributes may interrupt the winner, but they could be
1051 		//	 neutralized by another 2-line-attribute starting at the same
1052 		//	 position with the same brackets as the winner-attribute.
1053 
1054 		// In the following loop rPos is the critical position and it will be
1055 		// evaluated, if at rPos starts a interrupting or a maintaining
1056 		// continuity attribute.
1057 		while( i < nCount )
1058 		{
1059 			const SwTxtAttr *pTmp = (*pHints)[i++];
1060 			if( *pTmp->GetAnyEnd() <= rPos )
1061 				continue;
1062 			if( rPos < *pTmp->GetStart() )
1063 			{
1064 				// If bOn is sal_False and the next attribute starts later than rPos
1065 				// the winner attribute is interrupted at rPos.
1066 				// If the start of the next attribute is behind the end of
1067 				// the last attribute on the aEnd-stack, this is the endposition
1068 				// on the stack is the end of the 2-line portion.
1069 				if( !bOn || aEnd.back() < *pTmp->GetStart() )
1070 					break;
1071 				// At this moment, bOn is sal_True and the next attribute starts
1072 				// behind rPos, so we could move rPos to the next startpoint
1073 				rPos = *pTmp->GetStart();
1074 				// We clean up the aEnd-stack, endpositions equal to rPos are
1075 				// superfluous.
1076 				while( !aEnd.empty() && aEnd.back() <= rPos )
1077 				{
1078 					bOn = !bOn;
1079 					aEnd.pop_back();
1080 				}
1081 				// If the endstack is empty, we simulate an attribute with
1082 				// state sal_True and endposition rPos
1083 				if( aEnd.empty() )
1084 				{
1085 					aEnd.push_front( rPos );
1086 					bOn = sal_True;
1087 				}
1088 			}
1089 			// A ruby attribute stops the 2-line immediately
1090 			if( RES_TXTATR_CJK_RUBY == pTmp->Which() )
1091 				return pRet;
1092 			if( lcl_Has2Lines( *pTmp, p2Lines, bTwo ) )
1093 			{ // We have an interesting attribute..
1094 				if( bTwo == bOn )
1095 				{ // ...with the same state, so the last attribute could
1096 					// be continued.
1097 					if( aEnd.back() < *pTmp->End() )
1098 						aEnd.back() = *pTmp->End();
1099 				}
1100 				else
1101 				{ // ...with a different state.
1102 					bOn = bTwo;
1103 					// If this is smaller than the last on the stack, we put
1104 					// it on the stack. If it has the same endposition, the last
1105 					// could be removed.
1106 					if( aEnd.back() > *pTmp->End() )
1107 						aEnd.push_back( *pTmp->End() );
1108 					else if( aEnd.size() > 1 )
1109 						aEnd.pop_back();
1110 					else
1111 						aEnd.back() = *pTmp->End();
1112 				}
1113 			}
1114 		}
1115 		if( bOn && !aEnd.empty() )
1116 			rPos = aEnd.back();
1117 		return pRet;
1118 	}
1119 	if( nRotate < nCount || ( pRotItem && pRotItem == pRotate &&
1120 		rPos < GetTxt().Len() ) )
1121 	{	// The winner is a rotate-attribute,
1122 		// the end of the multiportion depends on the following attributes...
1123 		SwMultiCreator *pRet = new SwMultiCreator;
1124 		pRet->nId = SW_MC_ROTATE;
1125 
1126 		// We note the endpositions of the 2-line attributes in aEnd as stack
1127 		SvXub_StrLens aEnd;
1128 
1129 		// The bOn flag signs the state of the last 2-line attribute in the
1130 		// aEnd-stack, which could interrupts the winning rotation attribute.
1131 		sal_Bool bOn = pItem ? sal_True : sal_False;
1132 		aEnd.push_front( GetTxt().Len() );
1133 		// n2Lines is the index of the last 2-line-attribute, which contains
1134 		// the actual position.
1135 		i = 0;
1136 		xub_StrLen n2Start = rPos;
1137 		while( i < nCount )
1138 		{
1139 			const SwTxtAttr *pTmp = (*pHints)[i++];
1140 			if( *pTmp->GetAnyEnd() <= n2Start )
1141 				continue;
1142 			if( n2Start < *pTmp->GetStart() )
1143 			{
1144 				if( bOn || aEnd.back() < *pTmp->GetStart() )
1145 					break;
1146 				n2Start = *pTmp->GetStart();
1147 				while( !aEnd.empty() && aEnd.back() <= n2Start )
1148 				{
1149 					bOn = !bOn;
1150 					aEnd.pop_back();
1151 				}
1152 				if( aEnd.empty() )
1153 				{
1154 					aEnd.push_front( n2Start );
1155 					bOn = sal_False;
1156 				}
1157 			}
1158 			// A ruby attribute stops immediately
1159 			if( RES_TXTATR_CJK_RUBY == pTmp->Which() )
1160 			{
1161 				bOn = sal_True;
1162 				break;
1163 			}
1164 			p2Lines = NULL;
1165 			if( lcl_Has2Lines( *pTmp, p2Lines, bTwo ) )
1166 			{
1167 				if( bTwo == bOn )
1168 				{
1169 					if( aEnd.back() < *pTmp->End() )
1170 						aEnd.back() = *pTmp->End();
1171 				}
1172 				else
1173 				{
1174 					bOn = bTwo;
1175 					if( aEnd.back() > *pTmp->End() )
1176 						aEnd.push_back( *pTmp->End() );
1177 					else if( aEnd.size() > 1 )
1178 						aEnd.pop_back();
1179 					else
1180 						aEnd.back() = *pTmp->End();
1181 				}
1182 			}
1183 		}
1184 		if( !bOn && !aEnd.empty() )
1185 			n2Start = aEnd.back();
1186 
1187 		if( !aEnd.empty() )
1188 			aEnd.clear();
1189 
1190 		bOn = sal_True;
1191 		if( nRotate < nCount )
1192 		{
1193 			pRet->pItem = NULL;
1194 			pRet->pAttr = (*pHints)[nRotate];
1195 			aEnd.push_front( *pRet->pAttr->End() );
1196 			if( pRotItem )
1197 			{
1198 				aEnd.front() = GetTxt().Len();
1199 				bOn = ((SvxCharRotateItem*)pRotItem)->GetValue() ==
1200 						pRotate->GetValue();
1201 			}
1202 		}
1203 		else
1204 		{
1205 			pRet->pItem = pRotItem;
1206 			pRet->pAttr = NULL;
1207 			aEnd.push_front( GetTxt().Len() );
1208 		}
1209 		i = 0;
1210 		while( i < nCount )
1211 		{
1212 			const SwTxtAttr *pTmp = (*pHints)[i++];
1213 			if( *pTmp->GetAnyEnd() <= rPos )
1214 				continue;
1215 			if( rPos < *pTmp->GetStart() )
1216 			{
1217 				if( !bOn || aEnd.back() < *pTmp->GetStart() )
1218 					break;
1219 				rPos = *pTmp->GetStart();
1220 				while( !aEnd.empty() && aEnd.back() <= rPos )
1221 				{
1222 					bOn = !bOn;
1223 					aEnd.pop_back();
1224 				}
1225 				if( aEnd.empty() )
1226 				{
1227 					aEnd.push_front( rPos );
1228 					bOn = sal_True;
1229 				}
1230 			}
1231 			if( RES_TXTATR_CJK_RUBY == pTmp->Which() )
1232 			{
1233 				bOn = sal_False;
1234 				break;
1235 			}
1236 			if( lcl_HasRotation( *pTmp, pRotate, bTwo ) )
1237 			{
1238 				if( bTwo == bOn )
1239 				{
1240 					if( aEnd.back() < *pTmp->End() )
1241 						aEnd.back() = *pTmp->End();
1242 				}
1243 				else
1244 				{
1245 					bOn = bTwo;
1246 					if( aEnd.back() > *pTmp->End() )
1247 						aEnd.push_back( *pTmp->End() );
1248 					else if( aEnd.size() > 1 )
1249 						aEnd.pop_back();
1250 					else
1251 						aEnd.back() = *pTmp->End();
1252 				}
1253 			}
1254 		}
1255 		if( bOn && !aEnd.empty() )
1256 			rPos = aEnd.back();
1257 		if( rPos > n2Start )
1258 			rPos = n2Start;
1259 		return pRet;
1260 	}
1261 	return NULL;
1262 }
1263 
1264 /*-----------------01.11.00 14:52-------------------
1265  * SwSpaceManipulator
1266  * is a little helper class to manage the spaceadd-arrays of the text adjustment
1267  * during a PaintMultiPortion.
1268  * The constructor prepares the array for the first line of multiportion,
1269  * the SecondLine-function restores the values for the first line and prepares
1270  * the second line.
1271  * The destructor restores the values of the last manipulation.
1272  * --------------------------------------------------*/
1273 
1274 class SwSpaceManipulator
1275 {
1276 	SwTxtPaintInfo& rInfo;
1277 	SwMultiPortion& rMulti;
1278 	std::vector<long>* pOldSpaceAdd;
1279 	MSHORT nOldSpIdx;
1280 	long nSpaceAdd;
1281 	sal_Bool bSpaceChg	: 1;
1282 	sal_uInt8 nOldDir	: 2;
1283 public:
1284 	SwSpaceManipulator( SwTxtPaintInfo& rInf, SwMultiPortion& rMult );
1285 	~SwSpaceManipulator();
1286 	void SecondLine();
GetSpaceAdd() const1287 	inline long GetSpaceAdd() const { return nSpaceAdd; }
1288 };
1289 
SwSpaceManipulator(SwTxtPaintInfo & rInf,SwMultiPortion & rMult)1290 SwSpaceManipulator::SwSpaceManipulator( SwTxtPaintInfo& rInf,
1291 										SwMultiPortion& rMult ) :
1292 		rInfo( rInf ), rMulti( rMult )
1293 {
1294 	pOldSpaceAdd = rInfo.GetpSpaceAdd();
1295 	nOldSpIdx = rInfo.GetSpaceIdx();
1296 	nOldDir = rInfo.GetDirection();
1297 	rInfo.SetDirection( rMulti.GetDirection() );
1298 	bSpaceChg = sal_False;
1299 
1300 	if( rMulti.IsDouble() )
1301 	{
1302 		nSpaceAdd = ( pOldSpaceAdd && !rMulti.HasTabulator() ) ?
1303 					  rInfo.GetSpaceAdd() : 0;
1304 		if( rMulti.GetRoot().IsSpaceAdd() )
1305 		{
1306 			rInfo.SetpSpaceAdd( rMulti.GetRoot().GetpLLSpaceAdd() );
1307 			rInfo.ResetSpaceIdx();
1308 			bSpaceChg = rMulti.ChgSpaceAdd(	&rMulti.GetRoot(), nSpaceAdd );
1309 		}
1310 		else if( rMulti.HasTabulator() )
1311 			rInfo.SetpSpaceAdd( NULL );
1312 	}
1313 	else if ( ! rMulti.IsBidi() )
1314 	{
1315 		rInfo.SetpSpaceAdd( rMulti.GetRoot().GetpLLSpaceAdd() );
1316 		rInfo.ResetSpaceIdx();
1317 	}
1318 }
1319 
SecondLine()1320 void SwSpaceManipulator::SecondLine()
1321 {
1322 	if( bSpaceChg )
1323 	{
1324 		rInfo.RemoveFirstSpaceAdd();
1325 		bSpaceChg = sal_False;
1326 	}
1327 	SwLineLayout *pLay = rMulti.GetRoot().GetNext();
1328 	if( pLay->IsSpaceAdd() )
1329 	{
1330 		rInfo.SetpSpaceAdd( pLay->GetpLLSpaceAdd() );
1331 		rInfo.ResetSpaceIdx();
1332 		bSpaceChg = rMulti.ChgSpaceAdd( pLay, nSpaceAdd );
1333 	}
1334 	else
1335 	{
1336 		rInfo.SetpSpaceAdd( (!rMulti.IsDouble() || rMulti.HasTabulator() ) ?
1337 								0 : pOldSpaceAdd );
1338 		rInfo.SetSpaceIdx( nOldSpIdx);
1339 	}
1340 }
1341 
~SwSpaceManipulator()1342 SwSpaceManipulator::~SwSpaceManipulator()
1343 {
1344 	if( bSpaceChg )
1345 	{
1346 		rInfo.RemoveFirstSpaceAdd();
1347 		bSpaceChg = sal_False;
1348 	}
1349 	rInfo.SetpSpaceAdd( pOldSpaceAdd );
1350 	rInfo.SetSpaceIdx( nOldSpIdx);
1351 	rInfo.SetDirection( nOldDir );
1352 }
1353 
1354 /*-----------------13.10.00 16:24-------------------
1355  * SwTxtPainter::PaintMultiPortion manages the paint for a SwMultiPortion.
1356  * External, for the calling function, it seems to be a normal Paint-function,
1357  * internal it is like a SwTxtFrm::Paint with multiple DrawTextLines
1358  * --------------------------------------------------*/
1359 
PaintMultiPortion(const SwRect & rPaint,SwMultiPortion & rMulti,const SwMultiPortion * pEnvPor)1360 void SwTxtPainter::PaintMultiPortion( const SwRect &rPaint,
1361 	SwMultiPortion& rMulti, const SwMultiPortion* pEnvPor )
1362 {
1363 	GETGRID( pFrm->FindPageFrm() )
1364 	const sal_Bool bHasGrid = pGrid && GetInfo().SnapToGrid();
1365 	sal_uInt16 nGridWidth = 0;
1366 	sal_uInt16 nRubyHeight = 0;
1367 	sal_Bool bRubyTop = sal_False;
1368 
1369 	if ( bHasGrid )
1370 	{
1371 		nGridWidth = pGrid->GetBaseHeight();
1372 		nRubyHeight = pGrid->GetRubyHeight();
1373 		bRubyTop = ! pGrid->GetRubyTextBelow();
1374 	}
1375 
1376 	// do not allow grid mode for first line in ruby portion
1377 	const sal_Bool bRubyInGrid = bHasGrid && rMulti.IsRuby();
1378 
1379 	const sal_uInt16 nOldHeight = rMulti.Height();
1380 	const sal_Bool bOldGridModeAllowed = GetInfo().SnapToGrid();
1381 
1382 	if ( bRubyInGrid )
1383 	{
1384 		GetInfo().SetSnapToGrid( ! bRubyTop );
1385 		rMulti.Height( pCurr->Height() );
1386 	}
1387 
1388 	SwLayoutModeModifier aLayoutModeModifier( *GetInfo().GetOut() );
1389 	sal_uInt8 nEnvDir = 0;
1390 	sal_uInt8 nThisDir = 0;
1391 	sal_uInt8 nFrmDir = 0;
1392 	if ( rMulti.IsBidi() )
1393 	{
1394 		// these values are needed for the calculation of the x coordinate
1395 		// and the layout mode
1396 		ASSERT( ! pEnvPor || pEnvPor->IsBidi(), "I expected a BidiPortion" )
1397 		nFrmDir = GetInfo().GetTxtFrm()->IsRightToLeft() ? 1 : 0;
1398 		nEnvDir = pEnvPor ? ((SwBidiPortion*)pEnvPor)->GetLevel() % 2 : nFrmDir;
1399 		nThisDir = ((SwBidiPortion&)rMulti).GetLevel() % 2;
1400 	}
1401 
1402 #if OSL_DEBUG_LEVEL > 1
1403 	// only paint first level bidi portions
1404 	if( rMulti.Width() > 1 && ! pEnvPor )
1405 		GetInfo().DrawViewOpt( rMulti, POR_FLD );
1406 #endif
1407 
1408 	if ( bRubyInGrid )
1409 		rMulti.Height( nOldHeight );
1410 
1411 	// do we have to repaint a post it portion?
1412 	if( GetInfo().OnWin() && rMulti.GetPortion() &&
1413 		! rMulti.GetPortion()->Width() )
1414 		rMulti.GetPortion()->PrePaint( GetInfo(), &rMulti );
1415 
1416 	// old values must be saved and restored at the end
1417 	xub_StrLen nOldLen = GetInfo().GetLen();
1418 	KSHORT nOldX = KSHORT(GetInfo().X());
1419 	long nOldY = GetInfo().Y();
1420 	xub_StrLen nOldIdx = GetInfo().GetIdx();
1421 
1422 	SwSpaceManipulator aManip( GetInfo(), rMulti );
1423 
1424 	SwFontSave *pFontSave;
1425 	SwFont* pTmpFnt;
1426 
1427 	if( rMulti.IsDouble() )
1428 	{
1429 		pTmpFnt = new SwFont( *GetInfo().GetFont() );
1430 		if( rMulti.IsDouble() )
1431 		{
1432 			SetPropFont( 50 );
1433 			pTmpFnt->SetProportion( GetPropFont() );
1434 		}
1435 		pFontSave = new SwFontSave( GetInfo(), pTmpFnt, this );
1436 	}
1437 	else
1438 	{
1439 		pFontSave = NULL;
1440 		pTmpFnt = NULL;
1441 	}
1442 
1443 	if( rMulti.HasBrackets() )
1444 	{
1445 		xub_StrLen nTmpOldIdx = GetInfo().GetIdx();
1446 		GetInfo().SetIdx(((SwDoubleLinePortion&)rMulti).GetBrackets()->nStart);
1447 		SeekAndChg( GetInfo() );
1448 		((SwDoubleLinePortion&)rMulti).PaintBracket( GetInfo(), 0, sal_True );
1449 		GetInfo().SetIdx( nTmpOldIdx );
1450 	}
1451 
1452 	KSHORT nTmpX = KSHORT(GetInfo().X());
1453 
1454 	SwLineLayout* pLay = &rMulti.GetRoot();// the first line of the multiportion
1455 	SwLinePortion* pPor = pLay->GetFirstPortion();//first portion of these line
1456 	SwTwips nOfst = 0;
1457 
1458 	// GetInfo().Y() is the baseline from the surrounding line. We must switch
1459 	// this temporary to the baseline of the inner lines of the multiportion.
1460 	if( rMulti.HasRotation() )
1461 	{
1462 		if( rMulti.IsRevers() )
1463 		{
1464 			GetInfo().Y( nOldY - rMulti.GetAscent() );
1465 			nOfst = nTmpX + rMulti.Width();
1466 		}
1467 		else
1468 		{
1469 			GetInfo().Y( nOldY - rMulti.GetAscent() + rMulti.Height() );
1470 			nOfst = nTmpX;
1471 		}
1472 	}
1473 	else if ( rMulti.IsBidi() )
1474 	{
1475 		// does the current bidi portion has the same direction
1476 		// as its environment?
1477 		if ( nEnvDir != nThisDir )
1478 		{
1479 			// different directions, we have to adjust the x coordinate
1480 			SwTwips nMultiWidth = rMulti.Width() +
1481 					rMulti.CalcSpacing( GetInfo().GetSpaceAdd(), GetInfo() );
1482 
1483 			if ( nFrmDir == nThisDir )
1484 				GetInfo().X( GetInfo().X() - nMultiWidth );
1485 			else
1486 				GetInfo().X( GetInfo().X() + nMultiWidth );
1487 		}
1488 
1489 		nOfst = nOldY - rMulti.GetAscent();
1490 
1491 		// set layout mode
1492 		aLayoutModeModifier.Modify( nThisDir );
1493 	}
1494 	else
1495 		nOfst = nOldY - rMulti.GetAscent();
1496 
1497 	sal_Bool bRest = pLay->IsRest();
1498 	sal_Bool bFirst = sal_True;
1499 
1500 	ASSERT( 0 == GetInfo().GetUnderFnt() || rMulti.IsBidi(),
1501 			" Only BiDi portions are allowed to use the common underlining font" )
1502 
1503 	do
1504 	{
1505 		if ( bHasGrid )
1506 		{
1507 			if( rMulti.HasRotation() )
1508 			{
1509 				const sal_uInt16 nAdjustment = ( pLay->Height() - pPor->Height() ) / 2 +
1510 											pPor->GetAscent();
1511 				if( rMulti.IsRevers() )
1512 					GetInfo().X( nOfst - nAdjustment );
1513 				else
1514 					GetInfo().X( nOfst + nAdjustment );
1515 			}
1516 			else
1517 			{
1518 				// special treatment for ruby portions in grid mode
1519 				SwTwips nAdjustment = 0;
1520 				if ( rMulti.IsRuby() )
1521 				{
1522 					if ( bRubyTop != ( pLay == &rMulti.GetRoot() ) )
1523 						// adjust base text
1524 						nAdjustment = ( pCurr->Height() - nRubyHeight - pPor->Height() ) / 2;
1525 					else if ( bRubyTop )
1526 						// adjust upper ruby text
1527 						nAdjustment = nRubyHeight - pPor->Height();
1528 					// else adjust lower ruby text
1529 				}
1530 
1531 				GetInfo().Y( nOfst + nAdjustment + pPor->GetAscent() );
1532 			}
1533 		}
1534 		else if( rMulti.HasRotation() )
1535 		{
1536 			if( rMulti.IsRevers() )
1537 				GetInfo().X( nOfst - AdjustBaseLine( *pLay, pPor, 0, 0, sal_True ) );
1538 			else
1539 				GetInfo().X( nOfst + AdjustBaseLine( *pLay, pPor ) );
1540 		}
1541 		else
1542 			GetInfo().Y( nOfst + AdjustBaseLine( *pLay, pPor ) );
1543 
1544 		sal_Bool bSeeked = sal_True;
1545 		GetInfo().SetLen( pPor->GetLen() );
1546 
1547 		if( bRest && pPor->InFldGrp() && !pPor->GetLen() )
1548 		{
1549 			if(	((SwFldPortion*)pPor)->HasFont() )
1550 		 		bSeeked = sal_False;
1551 			else
1552 				SeekAndChgBefore( GetInfo() );
1553 		}
1554 		else if( pPor->InTxtGrp() || pPor->InFldGrp() || pPor->InTabGrp() )
1555 			SeekAndChg( GetInfo() );
1556 		else if ( !bFirst && pPor->IsBreakPortion() && GetInfo().GetOpt().IsParagraph() )
1557 		{
1558 			if( GetRedln() )
1559 				SeekAndChg( GetInfo() );
1560 			else
1561 				SeekAndChgBefore( GetInfo() );
1562 		}
1563 		else
1564 			bSeeked = sal_False;
1565 
1566 		SwLinePortion *pNext = pPor->GetPortion();
1567 		if(GetInfo().OnWin() && pNext && !pNext->Width() )
1568 		{
1569 			if ( !bSeeked )
1570 				SeekAndChg( GetInfo() );
1571 			pNext->PrePaint( GetInfo(), pPor );
1572 		}
1573 
1574 		CheckSpecialUnderline( pPor );
1575 		SwUnderlineFont* pUnderLineFnt = GetInfo().GetUnderFnt();
1576 		if ( pUnderLineFnt )
1577 		{
1578 			if ( rMulti.IsDouble() )
1579 				pUnderLineFnt->GetFont().SetProportion( 50 );
1580 			pUnderLineFnt->SetPos( GetInfo().GetPos() );
1581 		}
1582 
1583 		if ( rMulti.IsBidi() )
1584 		{
1585 			// we do not allow any rotation inside a bidi portion
1586 			SwFont* pTmpFont = GetInfo().GetFont();
1587 			pTmpFont->SetVertical( 0, GetInfo().GetTxtFrm()->IsVertical() );
1588 		}
1589 
1590 		if( pPor->IsMultiPortion() && ((SwMultiPortion*)pPor)->IsBidi() )
1591 		{
1592 			// but we do allow nested bidi portions
1593 			ASSERT( rMulti.IsBidi(), "Only nesting of bidi portions is allowed" )
1594 			PaintMultiPortion( rPaint, (SwMultiPortion&)*pPor, &rMulti );
1595 		}
1596 		else
1597 			pPor->Paint( GetInfo() );
1598 
1599 		if( GetFnt()->IsURL() && pPor->InTxtGrp() )
1600 			GetInfo().NotifyURL( *pPor );
1601 
1602 		bFirst &= !pPor->GetLen();
1603 		if( pNext || !pPor->IsMarginPortion() )
1604 			pPor->Move( GetInfo() );
1605 
1606 		pPor = pNext;
1607 
1608 		// If there's no portion left, we go to the next line
1609 		if( !pPor && pLay->GetNext() )
1610 		{
1611 			pLay = pLay->GetNext();
1612 			pPor = pLay->GetFirstPortion();
1613 			bRest = pLay->IsRest();
1614 			aManip.SecondLine();
1615 
1616 			// delete underline font
1617 			delete GetInfo().GetUnderFnt();
1618 			GetInfo().SetUnderFnt( 0 );
1619 
1620 			if( rMulti.HasRotation() )
1621 			{
1622 				if( rMulti.IsRevers() )
1623 				{
1624 					nOfst += pLay->Height();
1625 					GetInfo().Y( nOldY - rMulti.GetAscent() );
1626 				}
1627 				else
1628 				{
1629 					nOfst -= pLay->Height();
1630 					GetInfo().Y( nOldY - rMulti.GetAscent() + rMulti.Height() );
1631 				}
1632 			}
1633 			else if ( bHasGrid && rMulti.IsRuby() )
1634 			{
1635 				GetInfo().X( nTmpX );
1636 				if ( bRubyTop )
1637 				{
1638 					nOfst += nRubyHeight;
1639 					GetInfo().SetSnapToGrid( sal_True );
1640 				}
1641 				else
1642 				{
1643 					nOfst += pCurr->Height() - nRubyHeight;
1644 					GetInfo().SetSnapToGrid( sal_False );
1645 				}
1646 			} else
1647 			{
1648 				GetInfo().X( nTmpX );
1649 				// We switch to the baseline of the next inner line
1650 				nOfst += rMulti.GetRoot().Height();
1651 			}
1652 		}
1653 	} while( pPor );
1654 
1655 	if ( bRubyInGrid )
1656 		GetInfo().SetSnapToGrid( bOldGridModeAllowed );
1657 
1658 	// delete underline font
1659 	if ( ! rMulti.IsBidi() )
1660 	{
1661 		delete GetInfo().GetUnderFnt();
1662 		GetInfo().SetUnderFnt( 0 );
1663 	}
1664 
1665 	GetInfo().SetIdx( nOldIdx );
1666 	GetInfo().Y( nOldY );
1667 
1668 	if( rMulti.HasBrackets() )
1669 	{
1670 		xub_StrLen nTmpOldIdx = GetInfo().GetIdx();
1671 		GetInfo().SetIdx(((SwDoubleLinePortion&)rMulti).GetBrackets()->nStart);
1672 		SeekAndChg( GetInfo() );
1673 		GetInfo().X( nOldX );
1674 		((SwDoubleLinePortion&)rMulti).PaintBracket( GetInfo(),
1675 			aManip.GetSpaceAdd(), sal_False );
1676 		GetInfo().SetIdx( nTmpOldIdx );
1677 	}
1678 	// Restore the saved values
1679 	GetInfo().X( nOldX );
1680 	GetInfo().SetLen( nOldLen );
1681 	delete pFontSave;
1682 	delete pTmpFnt;
1683 	SetPropFont( 0 );
1684 }
1685 
lcl_ExtractFieldFollow(SwLineLayout * pLine,SwLinePortion * & rpFld)1686 sal_Bool lcl_ExtractFieldFollow( SwLineLayout* pLine, SwLinePortion* &rpFld )
1687 {
1688 	SwLinePortion* pLast = pLine;
1689 	rpFld = pLine->GetPortion();
1690 	while( rpFld && !rpFld->InFldGrp() )
1691 	{
1692 		pLast = rpFld;
1693 		rpFld = rpFld->GetPortion();
1694 	}
1695 	sal_Bool bRet = rpFld != 0;
1696 	if( bRet )
1697 	{
1698 		if( ((SwFldPortion*)rpFld)->IsFollow() )
1699 		{
1700 			rpFld->Truncate();
1701 			pLast->SetPortion( NULL );
1702 		}
1703 		else
1704 			rpFld = NULL;
1705 	}
1706 	pLine->Truncate();
1707 	return bRet;
1708 }
1709 
1710 /*----------------------------------------------------
1711  * lcl_TruncateMultiPortion
1712  * If a multi portion completely has to go to the
1713  * next line, this function is called to truncate
1714  * the rest of the remaining multi portion
1715  * --------------------------------------------------*/
1716 
lcl_TruncateMultiPortion(SwMultiPortion & rMulti,SwTxtFormatInfo & rInf,xub_StrLen nStartIdx)1717 void lcl_TruncateMultiPortion( SwMultiPortion& rMulti, SwTxtFormatInfo& rInf,
1718 							   xub_StrLen nStartIdx )
1719 {
1720 	rMulti.GetRoot().Truncate();
1721 	rMulti.GetRoot().SetLen(0);
1722 	rMulti.GetRoot().Width(0);
1723 //	rMulti.CalcSize( *this, aInf );
1724 	if ( rMulti.GetRoot().GetNext() )
1725 	{
1726 		rMulti.GetRoot().GetNext()->Truncate();
1727 		rMulti.GetRoot().GetNext()->SetLen( 0 );
1728 		rMulti.GetRoot().GetNext()->Width( 0 );
1729 	}
1730 	rMulti.Width( 0 );
1731 	rMulti.SetLen(0);
1732 	rInf.SetIdx( nStartIdx );
1733 }
1734 
1735 /*-----------------------------------------------------------------------------
1736  * SwTxtFormatter::BuildMultiPortion
1737  * manages the formatting of a SwMultiPortion. External, for the calling
1738  * function, it seems to be a normal Format-function, internal it is like a
1739  * SwTxtFrm::_Format with multiple BuildPortions
1740  *---------------------------------------------------------------------------*/
1741 
BuildMultiPortion(SwTxtFormatInfo & rInf,SwMultiPortion & rMulti)1742 sal_Bool SwTxtFormatter::BuildMultiPortion( SwTxtFormatInfo &rInf,
1743 	SwMultiPortion& rMulti )
1744 {
1745 	SwTwips nMaxWidth = rInf.Width();
1746 	KSHORT nOldX = 0;
1747 
1748 	if( rMulti.HasBrackets() )
1749 	{
1750 		xub_StrLen nOldIdx = rInf.GetIdx();
1751 		rInf.SetIdx( ((SwDoubleLinePortion&)rMulti).GetBrackets()->nStart );
1752 		SeekAndChg( rInf );
1753 		nOldX = KSHORT(GetInfo().X());
1754 		((SwDoubleLinePortion&)rMulti).FormatBrackets( rInf, nMaxWidth );
1755 		rInf.SetIdx( nOldIdx );
1756 	}
1757 
1758 	SeekAndChg( rInf );
1759 	SwFontSave *pFontSave;
1760 	if( rMulti.IsDouble() )
1761 	{
1762 		SwFont* pTmpFnt = new SwFont( *rInf.GetFont() );
1763 		if( rMulti.IsDouble() )
1764 		{
1765 			SetPropFont( 50 );
1766 			pTmpFnt->SetProportion( GetPropFont() );
1767 		}
1768 		pFontSave = new SwFontSave( rInf, pTmpFnt, this );
1769 	}
1770 	else
1771 		pFontSave = NULL;
1772 
1773 	SwLayoutModeModifier aLayoutModeModifier( *GetInfo().GetOut() );
1774 	if ( rMulti.IsBidi() )
1775 	{
1776 		// set layout mode
1777 		aLayoutModeModifier.Modify( ! rInf.GetTxtFrm()->IsRightToLeft() );
1778 	}
1779 
1780 	SwTwips nTmpX = 0;
1781 
1782 	if( rMulti.HasRotation() )
1783 	{
1784 		// For nMaxWidth we take the height of the body frame.
1785 		// #i25067#: If the current frame is inside a table, we restrict
1786 		// nMaxWidth to the current frame height, unless the frame size
1787 		// attribute is set to variable size:
1788 
1789 		// We set nTmpX (which is used for portion calculating) to the
1790 		// current Y value
1791 		const SwPageFrm* pPage = pFrm->FindPageFrm();
1792 		ASSERT( pPage, "No page in frame!");
1793 		const SwLayoutFrm* pUpperFrm = pPage;
1794 
1795 		if ( pFrm->IsInTab() )
1796 		{
1797 			pUpperFrm = pFrm->GetUpper();
1798 			while ( pUpperFrm && !pUpperFrm->IsCellFrm() )
1799 				pUpperFrm = pUpperFrm->GetUpper();
1800 			ASSERT( pUpperFrm, "pFrm is in table but does not have an upper cell frame" )
1801 			const SwTableLine* pLine = ((SwRowFrm*)pUpperFrm->GetUpper())->GetTabLine();
1802 			const SwFmtFrmSize& rFrmFmtSize = pLine->GetFrmFmt()->GetFrmSize();
1803 			if ( ATT_VAR_SIZE == rFrmFmtSize.GetHeightSizeType() )
1804 				pUpperFrm = pPage;
1805 		}
1806 		if ( pUpperFrm == pPage && !pFrm->IsInFtn() )
1807 			pUpperFrm = pPage->FindBodyCont();
1808 
1809 		nMaxWidth = pUpperFrm ?
1810 					( rInf.GetTxtFrm()->IsVertical() ?
1811 					  pUpperFrm->Prt().Width() :
1812 					  pUpperFrm->Prt().Height() ) :
1813 					USHRT_MAX;
1814 	}
1815 	else
1816 		nTmpX = rInf.X();
1817 
1818 	SwMultiPortion* pOldMulti = pMulti;
1819 
1820 	pMulti = &rMulti;
1821 	SwLineLayout *pOldCurr = pCurr;
1822 	xub_StrLen nOldStart = GetStart();
1823 	SwTwips nMinWidth = nTmpX + 1;
1824 	SwTwips nActWidth = nMaxWidth;
1825 	const xub_StrLen nStartIdx = rInf.GetIdx();
1826 	xub_StrLen nMultiLen = rMulti.GetLen();
1827 
1828 	SwLinePortion *pFirstRest;
1829 	SwLinePortion *pSecondRest;
1830 	if( rMulti.IsFormatted() )
1831 	{
1832 		if( !lcl_ExtractFieldFollow( &rMulti.GetRoot(), pFirstRest )
1833 			&& rMulti.IsDouble() && rMulti.GetRoot().GetNext() )
1834 			lcl_ExtractFieldFollow( rMulti.GetRoot().GetNext(), pFirstRest );
1835 		if( !rMulti.IsDouble() && rMulti.GetRoot().GetNext() )
1836 			lcl_ExtractFieldFollow( rMulti.GetRoot().GetNext(), pSecondRest );
1837 		else
1838 			pSecondRest = NULL;
1839 	}
1840 	else
1841 	{
1842 		pFirstRest = rMulti.GetRoot().GetPortion();
1843 		pSecondRest = rMulti.GetRoot().GetNext() ?
1844 					  rMulti.GetRoot().GetNext()->GetPortion() : NULL;
1845 		if( pFirstRest )
1846 			rMulti.GetRoot().SetPortion( NULL );
1847 		if( pSecondRest )
1848 			rMulti.GetRoot().GetNext()->SetPortion( NULL );
1849 		rMulti.SetFormatted();
1850 		nMultiLen = nMultiLen - rInf.GetIdx();
1851 	}
1852 
1853 	// save some values
1854 	const XubString* pOldTxt = &(rInf.GetTxt());
1855 	const SwTwips nOldPaintOfst = rInf.GetPaintOfst();
1856 
1857 	XubString aMultiStr( rInf.GetTxt(), 0, nMultiLen + rInf.GetIdx() );
1858 	rInf.SetTxt( aMultiStr );
1859 	SwTxtFormatInfo aInf( rInf, rMulti.GetRoot(), nActWidth );
1860 	// Do we allow break cuts? The FirstMulti-Flag is evaluated during
1861 	// line break determination.
1862 	sal_Bool bFirstMulti = rInf.GetIdx() != rInf.GetLineStart();
1863 
1864 	SwLinePortion *pNextFirst = NULL;
1865 	SwLinePortion *pNextSecond = NULL;
1866 	sal_Bool bRet = sal_False;
1867 
1868 	GETGRID( pFrm->FindPageFrm() )
1869 	const sal_Bool bHasGrid = pGrid && GRID_LINES_CHARS == pGrid->GetGridType();
1870 
1871 	sal_uInt16 nGridWidth = 0;
1872 	sal_uInt16 nRubyHeight = 0;
1873 	sal_Bool bRubyTop = sal_False;
1874 
1875 	if ( bHasGrid )
1876 	{
1877 		nGridWidth = pGrid->GetBaseHeight();
1878 		nRubyHeight = pGrid->GetRubyHeight();
1879 		bRubyTop = ! pGrid->GetRubyTextBelow();
1880 	}
1881 
1882 	do
1883 	{
1884 		pCurr = &rMulti.GetRoot();
1885 		nStart = nStartIdx;
1886 		bRet = sal_False;
1887 		FormatReset( aInf );
1888 		aInf.X( nTmpX );
1889 		aInf.Width( KSHORT(nActWidth) );
1890 		aInf.RealWidth( KSHORT(nActWidth) );
1891 		aInf.SetFirstMulti( bFirstMulti );
1892 		aInf.SetNumDone( rInf.IsNumDone() );
1893 		aInf.SetFtnDone( rInf.IsFtnDone() );
1894 
1895 		if( pFirstRest )
1896 		{
1897 			ASSERT( pFirstRest->InFldGrp(), "BuildMulti: Fieldrest expected");
1898 			SwFldPortion *pFld =
1899 				((SwFldPortion*)pFirstRest)->Clone(
1900 					((SwFldPortion*)pFirstRest)->GetExp() );
1901 			pFld->SetFollow( sal_True );
1902 			aInf.SetRest( pFld );
1903 		}
1904 		aInf.SetRuby( rMulti.IsRuby() && rMulti.OnTop() );
1905 
1906 		// in grid mode we temporarily have to disable the grid for the ruby line
1907 		const sal_Bool bOldGridModeAllowed = GetInfo().SnapToGrid();
1908 		if ( bHasGrid && aInf.IsRuby() && bRubyTop )
1909 			aInf.SetSnapToGrid( sal_False );
1910 
1911 		// If there's no more rubytext, then buildportion is forbidden
1912 		if( pFirstRest || !aInf.IsRuby() )
1913 			BuildPortions( aInf );
1914 
1915 		aInf.SetSnapToGrid( bOldGridModeAllowed );
1916 
1917 		rMulti.CalcSize( *this, aInf );
1918 		pCurr->SetRealHeight( pCurr->Height() );
1919 
1920 		if( rMulti.IsBidi() )
1921 		{
1922 			pNextFirst = aInf.GetRest();
1923 			break;
1924 		}
1925 
1926 		if( rMulti.HasRotation() && !rMulti.IsDouble() )
1927 			break;
1928 		// second line has to be formatted
1929 		else if( pCurr->GetLen()<nMultiLen || rMulti.IsRuby() || aInf.GetRest())
1930 		{
1931 			xub_StrLen nFirstLen = pCurr->GetLen();
1932 			delete pCurr->GetNext();
1933 			pCurr->SetNext( new SwLineLayout() );
1934 			pCurr = pCurr->GetNext();
1935 			nStart = aInf.GetIdx();
1936 			aInf.X( nTmpX );
1937 			SwTxtFormatInfo aTmp( aInf, *pCurr, nActWidth );
1938 			if( rMulti.IsRuby() )
1939 			{
1940 				aTmp.SetRuby( !rMulti.OnTop() );
1941 				pNextFirst = aInf.GetRest();
1942 				if( pSecondRest )
1943 				{
1944 					ASSERT( pSecondRest->InFldGrp(), "Fieldrest expected");
1945 					SwFldPortion *pFld = ((SwFldPortion*)pSecondRest)->Clone(
1946 									((SwFldPortion*)pSecondRest)->GetExp() );
1947 					pFld->SetFollow( sal_True );
1948 					aTmp.SetRest( pFld );
1949 				}
1950 				if( !rMulti.OnTop() && nFirstLen < nMultiLen )
1951 					bRet = sal_True;
1952 			}
1953 			else
1954 				aTmp.SetRest( aInf.GetRest() );
1955 			aInf.SetRest( NULL );
1956 
1957 			// in grid mode we temporarily have to disable the grid for the ruby line
1958 			if ( bHasGrid && aTmp.IsRuby() && ! bRubyTop )
1959 				aTmp.SetSnapToGrid( sal_False );
1960 
1961 			BuildPortions( aTmp );
1962 
1963 			aTmp.SetSnapToGrid( bOldGridModeAllowed );
1964 
1965 			rMulti.CalcSize( *this, aInf );
1966 			rMulti.GetRoot().SetRealHeight( rMulti.GetRoot().Height() );
1967 			pCurr->SetRealHeight( pCurr->Height() );
1968 			if( rMulti.IsRuby() )
1969 			{
1970 				pNextSecond = aTmp.GetRest();
1971 				if( pNextFirst )
1972 					bRet = sal_True;
1973 			}
1974 			else
1975 				pNextFirst = aTmp.GetRest();
1976 			if( ( !aTmp.IsRuby() && nFirstLen + pCurr->GetLen() < nMultiLen )
1977 				|| aTmp.GetRest() )
1978 				// our guess for width of multiportion was too small,
1979 				// text did not fit into multiportion
1980 				bRet = sal_True;
1981 		}
1982 		if( rMulti.IsRuby() )
1983 			break;
1984 		if( bRet )
1985 		{
1986 			// our guess for multiportion width was too small,
1987 			// we set min to act
1988 			nMinWidth = nActWidth;
1989 			nActWidth = ( 3 * nMaxWidth + nMinWidth + 3 ) / 4;
1990 			if ( nActWidth == nMaxWidth && rInf.GetLineStart() == rInf.GetIdx() )
1991 			// we have too less space, we must allow break cuts
1992 			// ( the first multi flag is considered during TxtPortion::_Format() )
1993 				bFirstMulti = sal_False;
1994 			if( nActWidth <= nMinWidth )
1995 				break;
1996 		}
1997 		else
1998 		{
1999 			// For Solaris, this optimization can causes trouble:
2000 			// Setting this to the portion width ( = rMulti.Width() )
2001 			// can make GetTextBreak inside SwTxtGuess::Guess return to small
2002 			// values. Therefore we add some extra twips.
2003 			if( nActWidth > nTmpX + rMulti.Width() + 6 )
2004 				nActWidth = nTmpX + rMulti.Width() + 6;
2005 			nMaxWidth = nActWidth;
2006 			nActWidth = ( 3 * nMaxWidth + nMinWidth + 3 ) / 4;
2007 			if( nActWidth >= nMaxWidth )
2008 				break;
2009 			// we do not allow break cuts during formatting
2010 			bFirstMulti = sal_True;
2011 		}
2012 		delete pNextFirst;
2013 		pNextFirst = NULL;
2014 	} while ( sal_True );
2015 
2016 	pMulti = pOldMulti;
2017 
2018 	pCurr = pOldCurr;
2019 	nStart = nOldStart;
2020 	SetPropFont( 0 );
2021 
2022 	rMulti.SetLen( rMulti.GetRoot().GetLen() + ( rMulti.GetRoot().GetNext() ?
2023 		rMulti.GetRoot().GetNext()->GetLen() : 0 ) );
2024 
2025 	if( rMulti.IsDouble() )
2026 	{
2027 		((SwDoubleLinePortion&)rMulti).CalcBlanks( rInf );
2028 		if( ((SwDoubleLinePortion&)rMulti).GetLineDiff() )
2029 		{
2030 			SwLineLayout* pLine = &rMulti.GetRoot();
2031 			if( ((SwDoubleLinePortion&)rMulti).GetLineDiff() > 0 )
2032 			{
2033 				rInf.SetIdx( nStartIdx + pLine->GetLen() );
2034 				pLine = pLine->GetNext();
2035 			}
2036 			if( pLine )
2037 			{
2038 				GetInfo().SetMulti( sal_True );
2039 				CalcNewBlock( pLine, NULL, rMulti.Width() );
2040 				GetInfo().SetMulti( sal_False );
2041 			}
2042 			rInf.SetIdx( nStartIdx );
2043 		}
2044 		if( ((SwDoubleLinePortion&)rMulti).GetBrackets() )
2045 		{
2046 			rMulti.Width( rMulti.Width() +
2047 					((SwDoubleLinePortion&)rMulti).BracketWidth() );
2048 			GetInfo().X( nOldX );
2049 		}
2050 	}
2051 	else
2052 	{
2053 		rMulti.ActualizeTabulator();
2054 		if( rMulti.IsRuby() )
2055 		{
2056 			((SwRubyPortion&)rMulti).Adjust( rInf );
2057 			((SwRubyPortion&)rMulti).CalcRubyOffset();
2058 		}
2059 	}
2060 	if( rMulti.HasRotation() )
2061 	{
2062 		SwTwips nH = rMulti.Width();
2063 		SwTwips nAsc = rMulti.GetAscent() + ( nH - rMulti.Height() )/2;
2064 		if( nAsc > nH )
2065 			nAsc = nH;
2066 		else if( nAsc < 0 )
2067 			nAsc = 0;
2068 		rMulti.Width( rMulti.Height() );
2069 		rMulti.Height( KSHORT(nH) );
2070 		rMulti.SetAscent( KSHORT(nAsc) );
2071 		bRet = ( rInf.GetPos().X() + rMulti.Width() > rInf.Width() ) &&
2072 				 nStartIdx != rInf.GetLineStart();
2073 	}
2074 	else if ( rMulti.IsBidi() )
2075 	{
2076 		bRet = rMulti.GetLen() < nMultiLen || pNextFirst;
2077 	}
2078 
2079 	// line break has to be performed!
2080 	if( bRet )
2081 	{
2082 		ASSERT( !pNextFirst || pNextFirst->InFldGrp(),
2083 			"BuildMultiPortion: Surprising restportion, field expected" );
2084 		SwMultiPortion *pTmp;
2085 		if( rMulti.IsDouble() )
2086 			pTmp = new SwDoubleLinePortion( ((SwDoubleLinePortion&)rMulti),
2087 											nMultiLen + rInf.GetIdx() );
2088 		else if( rMulti.IsRuby() )
2089 		{
2090 			ASSERT( !pNextSecond || pNextSecond->InFldGrp(),
2091 				"BuildMultiPortion: Surprising restportion, field expected" );
2092 
2093 			if ( rInf.GetIdx() == rInf.GetLineStart() )
2094 			{
2095 				// the ruby portion has to be split in two portions
2096 				pTmp = new SwRubyPortion( ((SwRubyPortion&)rMulti),
2097 										  nMultiLen + rInf.GetIdx() );
2098 
2099 				if( pNextSecond )
2100 				{
2101 					pTmp->GetRoot().SetNext( new SwLineLayout() );
2102 					pTmp->GetRoot().GetNext()->SetPortion( pNextSecond );
2103 				}
2104 				pTmp->SetFollowFld();
2105 			}
2106 			else
2107 			{
2108 				// we try to keep our ruby portion together
2109 				lcl_TruncateMultiPortion( rMulti, rInf, nStartIdx );
2110 				pTmp = 0;
2111 			}
2112 		}
2113 		else if( rMulti.HasRotation() )
2114 		{
2115 			// we try to keep our rotated portion together
2116 			lcl_TruncateMultiPortion( rMulti, rInf, nStartIdx );
2117 			pTmp = new SwRotatedPortion( nMultiLen + rInf.GetIdx(),
2118 										 rMulti.GetDirection() );
2119 		}
2120 		// during a recursion of BuildMultiPortions we may not build
2121 		// a new SwBidiPortion, this would cause a memory leak
2122 		else if( rMulti.IsBidi() && ! pMulti )
2123 		{
2124 			if ( ! rMulti.GetLen() )
2125 				lcl_TruncateMultiPortion( rMulti, rInf, nStartIdx );
2126 
2127 			// If there is a HolePortion at the end of the bidi portion,
2128 			// it has to be moved behind the bidi portion. Otherwise
2129 			// the visual cursor traveling gets into trouble.
2130 			SwLineLayout& aRoot = rMulti.GetRoot();
2131 			SwLinePortion* pPor = aRoot.GetFirstPortion();
2132 			while ( pPor )
2133 			{
2134 				if ( pPor->GetPortion() && pPor->GetPortion()->IsHolePortion() )
2135 				{
2136 					SwLinePortion* pHolePor = pPor->GetPortion();
2137 					pPor->SetPortion( NULL );
2138 					aRoot.SetLen( aRoot.GetLen() - pHolePor->GetLen() );
2139 					rMulti.SetLen( rMulti.GetLen() - pHolePor->GetLen() );
2140 					rMulti.SetPortion( pHolePor );
2141 					break;
2142 				}
2143 				pPor = pPor->GetPortion();
2144 			}
2145 
2146 			pTmp = new SwBidiPortion( nMultiLen + rInf.GetIdx(),
2147 									((SwBidiPortion&)rMulti).GetLevel() );
2148 		}
2149 		else
2150 			pTmp = NULL;
2151 
2152 		if ( ! rMulti.GetLen() && rInf.GetLast() )
2153 		{
2154 			SeekAndChgBefore( rInf );
2155 			rInf.GetLast()->FormatEOL( rInf );
2156 		}
2157 
2158 		if( pNextFirst && pTmp )
2159 		{
2160 			pTmp->SetFollowFld();
2161 			pTmp->GetRoot().SetPortion( pNextFirst );
2162 		}
2163 		else
2164 			// A follow field portion is still waiting. If nobody wants it,
2165 			// we delete it.
2166 			delete pNextFirst;
2167 
2168 		rInf.SetRest( pTmp );
2169 	}
2170 
2171 	rInf.SetTxt( *pOldTxt );
2172 	rInf.SetPaintOfst( nOldPaintOfst );
2173 	rInf.SetStop( aInf.IsStop() );
2174 	rInf.SetNumDone( sal_True );
2175 	rInf.SetFtnDone( sal_True );
2176 	SeekAndChg( rInf );
2177 	delete pFirstRest;
2178 	delete pSecondRest;
2179 	delete pFontSave;
2180 	return bRet;
2181 }
2182 
2183 /*-----------------08.11.00 09:29-------------------
2184  * SwTxtFormatter::MakeRestPortion(..)
2185  * When a fieldportion at the end of line breaks and needs a following
2186  * fieldportion in the next line, then the "restportion" of the formatinfo
2187  * has to be set. Normally this happens during the formatting of the first
2188  * part of the fieldportion.
2189  * But sometimes the formatting starts at the line with the following part,
2190  * especially when the following part is on the next page.
2191  * In this case the MakeRestPortion-function has to create the following part.
2192  * The first parameter is the line that contains possibly a first part
2193  * of a field. When the function finds such field part, it creates the right
2194  * restportion. This may be a multiportion, e.g. if the field is surrounded by
2195  * a doubleline- or ruby-portion.
2196  * The second parameter is the start index of the line.
2197  * --------------------------------------------------*/
2198 
MakeRestPortion(const SwLineLayout * pLine,xub_StrLen nPosition)2199 SwLinePortion* SwTxtFormatter::MakeRestPortion( const SwLineLayout* pLine,
2200 	xub_StrLen nPosition )
2201 {
2202 	if( !nPosition )
2203 		return NULL;
2204 	xub_StrLen nMultiPos = nPosition - pLine->GetLen();
2205 	const SwMultiPortion *pTmpMulti = NULL;
2206 	const SwMultiPortion *pHelpMulti = NULL;
2207 	const SwLinePortion* pPor = pLine->GetFirstPortion();
2208 	SwFldPortion *pFld = NULL;
2209 	while( pPor )
2210 	{
2211 		if( pPor->GetLen() )
2212 		{
2213 			if( !pHelpMulti )
2214 			{
2215 				nMultiPos = nMultiPos + pPor->GetLen();
2216 				pTmpMulti = NULL;
2217 			}
2218 		}
2219 		if( pPor->InFldGrp() )
2220 		{
2221 			if( !pHelpMulti )
2222 				pTmpMulti = NULL;
2223 			pFld = (SwFldPortion*)pPor;
2224 		}
2225 		else if( pPor->IsMultiPortion() )
2226 		{
2227 			ASSERT( !pHelpMulti || pHelpMulti->IsBidi(),
2228 					"Nested multiportions are forbidden." );
2229 
2230 			pFld = NULL;
2231 			pTmpMulti = (SwMultiPortion*)pPor;
2232 		}
2233 		pPor = pPor->GetPortion();
2234 		// If the last portion is a multi-portion, we enter it
2235 		// and look for a field portion inside.
2236 		// If we are already in a multiportion, we could change to the
2237 		// next line
2238 		if( !pPor && pTmpMulti )
2239 		{
2240 			if( pHelpMulti )
2241 			{   // We're already inside the multiportion, let's take the second
2242 				// line, if we are in a double line portion
2243 				if( !pHelpMulti->IsRuby() )
2244 					pPor = pHelpMulti->GetRoot().GetNext();
2245 				pTmpMulti = NULL;
2246 			}
2247 			else
2248 			{   // Now we enter a multiportion, in a ruby portion we take the
2249 				// main line, not the phonetic line, in a doublelineportion we
2250 				// starts with the first line.
2251 				pHelpMulti = pTmpMulti;
2252 				nMultiPos = nMultiPos - pHelpMulti->GetLen();
2253 				if( pHelpMulti->IsRuby() && pHelpMulti->OnTop() )
2254 					pPor = pHelpMulti->GetRoot().GetNext();
2255 				else
2256 					pPor = pHelpMulti->GetRoot().GetFirstPortion();
2257 			}
2258 		}
2259 	}
2260 	if( pFld && !pFld->HasFollow() )
2261 		pFld = NULL;
2262 
2263 	SwLinePortion *pRest = NULL;
2264 	if( pFld )
2265 	{
2266 		const SwTxtAttr *pHint = GetAttr( nPosition - 1 );
2267 		if ( pHint
2268 			 && ( pHint->Which() == RES_TXTATR_FIELD
2269 				  || pHint->Which() == RES_TXTATR_ANNOTATION ) )
2270 		{
2271 			pRest = NewFldPortion( GetInfo(), pHint );
2272 			if( pRest->InFldGrp() )
2273 				((SwFldPortion*)pRest)->TakeNextOffset( pFld );
2274 			else
2275 			{
2276 				delete pRest;
2277 				pRest = NULL;
2278 			}
2279 		}
2280 	}
2281 	if( !pHelpMulti )
2282 		return pRest;
2283 
2284 	nPosition = nMultiPos + pHelpMulti->GetLen();
2285 	SwMultiCreator* pCreate = GetInfo().GetMultiCreator( nMultiPos, 0 );
2286 
2287 	if ( !pCreate )
2288 	{
2289 		ASSERT( !pHelpMulti->GetLen(), "Multiportion without attribut?" );
2290 		if ( nMultiPos )
2291 			--nMultiPos;
2292 		pCreate = GetInfo().GetMultiCreator( --nMultiPos, 0 );
2293 	}
2294 
2295 	if( pRest || nMultiPos > nPosition || ( pHelpMulti->IsRuby() &&
2296 		((SwRubyPortion*)pHelpMulti)->GetRubyOffset() < STRING_LEN ) )
2297 	{
2298 		SwMultiPortion* pTmp;
2299 		if( pHelpMulti->IsDouble() )
2300 			pTmp = new SwDoubleLinePortion( *pCreate, nMultiPos );
2301 		else if( pHelpMulti->IsBidi() )
2302 			pTmp = new SwBidiPortion( nMultiPos, pCreate->nLevel );
2303 		else if( pHelpMulti->IsRuby() )
2304 		{
2305 			sal_Bool bRubyTop;
2306 			sal_Bool* pRubyPos = 0;
2307 
2308 			if ( GetInfo().SnapToGrid() )
2309 			{
2310 				GETGRID( pFrm->FindPageFrm() )
2311 				if ( pGrid )
2312 				{
2313 					bRubyTop = ! pGrid->GetRubyTextBelow();
2314 					pRubyPos = &bRubyTop;
2315 				}
2316 			}
2317 
2318 			pTmp = new SwRubyPortion( *pCreate, *GetInfo().GetFont(),
2319 									  *pFrm->GetTxtNode()->getIDocumentSettingAccess(),
2320 									  nMultiPos, ((SwRubyPortion*)pHelpMulti)->GetRubyOffset(),
2321 									  pRubyPos );
2322 		}
2323 		else if( pHelpMulti->HasRotation() )
2324 			pTmp = new SwRotatedPortion( nMultiPos, pHelpMulti->GetDirection() );
2325 		else
2326 		{
2327 			delete pCreate;
2328 			return pRest;
2329 		}
2330 		delete pCreate;
2331 		pTmp->SetFollowFld();
2332 		if( pRest )
2333 		{
2334 			SwLineLayout *pLay = &pTmp->GetRoot();
2335 			if( pTmp->IsRuby() && pTmp->OnTop() )
2336 			{
2337 				pLay->SetNext( new SwLineLayout() );
2338 				pLay = pLay->GetNext();
2339 			}
2340 			pLay->SetPortion( pRest );
2341 		}
2342 		return pTmp;
2343 	}
2344 	return pRest;
2345 }
2346 
2347 
2348 
2349 /*-----------------23.10.00 10:47-------------------
2350  * SwTxtCursorSave notes the start and current line of a SwTxtCursor,
2351  * sets them to the values for GetCrsrOfst inside a multiportion
2352  * and restores them in the destructor.
2353  * --------------------------------------------------*/
2354 
SwTxtCursorSave(SwTxtCursor * pTxtCursor,SwMultiPortion * pMulti,SwTwips nY,sal_uInt16 & nX,xub_StrLen nCurrStart,long nSpaceAdd)2355 SwTxtCursorSave::SwTxtCursorSave( SwTxtCursor* pTxtCursor,
2356 								  SwMultiPortion* pMulti,
2357 								  SwTwips nY,
2358 								  sal_uInt16& nX,
2359 								  xub_StrLen nCurrStart,
2360 								  long nSpaceAdd )
2361 {
2362 	pTxtCrsr = pTxtCursor;
2363 	nStart = pTxtCursor->nStart;
2364 	pTxtCursor->nStart = nCurrStart;
2365 	pCurr = pTxtCursor->pCurr;
2366 	pTxtCursor->pCurr = &pMulti->GetRoot();
2367 	while( pTxtCursor->Y() + pTxtCursor->GetLineHeight() < nY &&
2368 		pTxtCursor->Next() )
2369 		; // nothing
2370 	nWidth = pTxtCursor->pCurr->Width();
2371 	nOldProp = pTxtCursor->GetPropFont();
2372 
2373 	if ( pMulti->IsDouble() || pMulti->IsBidi() )
2374 	{
2375 		bSpaceChg = pMulti->ChgSpaceAdd( pTxtCursor->pCurr, nSpaceAdd );
2376 
2377 		sal_uInt16 nSpaceCnt;
2378 		if ( pMulti->IsDouble() )
2379 		{
2380 			pTxtCursor->SetPropFont( 50 );
2381 			nSpaceCnt = ((SwDoubleLinePortion*)pMulti)->GetSpaceCnt();
2382 		}
2383 		else
2384 		{
2385 			const xub_StrLen nOldIdx = pTxtCursor->GetInfo().GetIdx();
2386 			pTxtCursor->GetInfo().SetIdx ( nCurrStart );
2387 			nSpaceCnt = ((SwBidiPortion*)pMulti)->GetSpaceCnt(pTxtCursor->GetInfo());
2388 			pTxtCursor->GetInfo().SetIdx ( nOldIdx );
2389 		}
2390 
2391 		if( nSpaceAdd > 0 && !pMulti->HasTabulator() )
2392 			pTxtCursor->pCurr->Width( static_cast<sal_uInt16>(nWidth + nSpaceAdd * nSpaceCnt / SPACING_PRECISION_FACTOR ) );
2393 
2394 		// For a BidiPortion we have to calculate the offset from the
2395 		// end of the portion
2396 		if ( nX && pMulti->IsBidi() )
2397 			nX = pTxtCursor->pCurr->Width() - nX;
2398 	}
2399 	else
2400 		bSpaceChg = sal_False;
2401 }
2402 
~SwTxtCursorSave()2403 SwTxtCursorSave::~SwTxtCursorSave()
2404 {
2405 	if( bSpaceChg )
2406 		SwDoubleLinePortion::ResetSpaceAdd( pTxtCrsr->pCurr );
2407 	pTxtCrsr->pCurr->Width( KSHORT(nWidth) );
2408 	pTxtCrsr->pCurr = pCurr;
2409 	pTxtCrsr->nStart = nStart;
2410 	pTxtCrsr->SetPropFont( nOldProp );
2411 }
2412 
2413 /* vim: set noet sw=4 ts=4: */
2414