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