xref: /AOO41X/main/sw/source/core/text/itrform2.cxx (revision 69a743679e823ad8f875be547552acb607b8ada5)
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 #include "hintids.hxx"
28cdf0e10cSrcweir 
29cdf0e10cSrcweir #ifndef _COM_SUN_STAR_I18N_SCRIPTTYPE_HDL_
30cdf0e10cSrcweir #include <com/sun/star/i18n/ScriptType.hdl>
31cdf0e10cSrcweir #endif
32cdf0e10cSrcweir #include <editeng/lspcitem.hxx>
33cdf0e10cSrcweir #include <txtftn.hxx>
34cdf0e10cSrcweir #include <fmtftn.hxx>
35cdf0e10cSrcweir #include <ftninfo.hxx>
36cdf0e10cSrcweir #include <charfmt.hxx>
37cdf0e10cSrcweir #include <editeng/charrotateitem.hxx>
38cdf0e10cSrcweir #include <layfrm.hxx>		// GetFrmRstHeight, etc
39cdf0e10cSrcweir #include <viewsh.hxx>
40cdf0e10cSrcweir #include <viewopt.hxx>		// SwViewOptions
41cdf0e10cSrcweir #include <paratr.hxx>		// SwFmtDrop
42cdf0e10cSrcweir #include <txtcfg.hxx>
43cdf0e10cSrcweir #include <itrform2.hxx>
44cdf0e10cSrcweir #include <porrst.hxx>
45cdf0e10cSrcweir #include <portab.hxx>		// pLastTab->
46cdf0e10cSrcweir #include <porfly.hxx>		// CalcFlyWidth
47cdf0e10cSrcweir #include <portox.hxx>		// WhichTxtPortion
48cdf0e10cSrcweir #include <porref.hxx>		// WhichTxtPortion
49cdf0e10cSrcweir #include <porfld.hxx>		// SwNumberPortion fuer CalcAscent()
50cdf0e10cSrcweir #include <porftn.hxx>       // SwFtnPortion
51cdf0e10cSrcweir #include <porhyph.hxx>
52cdf0e10cSrcweir #include <guess.hxx>
53cdf0e10cSrcweir #include <blink.hxx>		// pBlink
54cdf0e10cSrcweir #include <ftnfrm.hxx>		// WhichFirstPortion() -> mal Verlagern.
55cdf0e10cSrcweir #include <redlnitr.hxx>		// SwRedlineItr
56cdf0e10cSrcweir #include <pagefrm.hxx>
57cdf0e10cSrcweir #include <pagedesc.hxx> // SwPageDesc
58cdf0e10cSrcweir #include <tgrditem.hxx>
59cdf0e10cSrcweir #include <doc.hxx>			// SwDoc
60cdf0e10cSrcweir #include <pormulti.hxx> 	// SwMultiPortion
61cdf0e10cSrcweir #define _SVSTDARR_LONGS
62cdf0e10cSrcweir #include <svl/svstdarr.hxx>
63cdf0e10cSrcweir #include <unotools/charclass.hxx>
64cdf0e10cSrcweir 
65cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1
66cdf0e10cSrcweir #include <ndtxt.hxx>		// pSwpHints, Ausgabeoperator
67cdf0e10cSrcweir #endif
68cdf0e10cSrcweir 
69cdf0e10cSrcweir using namespace ::com::sun::star;
70cdf0e10cSrcweir 
71cdf0e10cSrcweir extern sal_Bool IsUnderlineBreak( const SwLinePortion& rPor, const SwFont& rFnt );
72cdf0e10cSrcweir bool lcl_BuildHiddenPortion( const SwTxtSizeInfo& rInf, xub_StrLen &rPos );
73cdf0e10cSrcweir 
74cdf0e10cSrcweir #define MAX_TXTPORLEN 300
75cdf0e10cSrcweir 
ClearFly(SwTxtFormatInfo & rInf)76cdf0e10cSrcweir inline void ClearFly( SwTxtFormatInfo &rInf )
77cdf0e10cSrcweir {
78cdf0e10cSrcweir 	if( rInf.GetFly() )
79cdf0e10cSrcweir 	{
80cdf0e10cSrcweir 		delete rInf.GetFly();
81cdf0e10cSrcweir 		rInf.SetFly(0);
82cdf0e10cSrcweir 	}
83cdf0e10cSrcweir }
84cdf0e10cSrcweir 
85cdf0e10cSrcweir /*************************************************************************
86cdf0e10cSrcweir  *					SwTxtFormatter::CtorInitTxtFormatter()
87cdf0e10cSrcweir  *************************************************************************/
88cdf0e10cSrcweir 
CtorInitTxtFormatter(SwTxtFrm * pNewFrm,SwTxtFormatInfo * pNewInf)89cdf0e10cSrcweir void SwTxtFormatter::CtorInitTxtFormatter( SwTxtFrm *pNewFrm, SwTxtFormatInfo *pNewInf )
90cdf0e10cSrcweir {
91cdf0e10cSrcweir     CtorInitTxtPainter( pNewFrm, pNewInf );
92cdf0e10cSrcweir 	pInf = pNewInf;
93cdf0e10cSrcweir 	pDropFmt = GetInfo().GetDropFmt();
94cdf0e10cSrcweir 	pMulti = NULL;
95cdf0e10cSrcweir 
96cdf0e10cSrcweir 	bOnceMore = sal_False;
97cdf0e10cSrcweir     bFlyInCntBase = sal_False;
98cdf0e10cSrcweir 	bChanges = sal_False;
99cdf0e10cSrcweir 	bTruncLines = sal_False;
100cdf0e10cSrcweir 	nCntEndHyph = 0;
101cdf0e10cSrcweir 	nCntMidHyph = 0;
102cdf0e10cSrcweir 	nLeftScanIdx = STRING_LEN;
103cdf0e10cSrcweir 	nRightScanIdx = 0;
104cdf0e10cSrcweir     m_nHintEndIndex = 0;
105cdf0e10cSrcweir 
106cdf0e10cSrcweir 	if( nStart > GetInfo().GetTxt().Len() )
107cdf0e10cSrcweir 	{
108cdf0e10cSrcweir 		ASSERT( !this, "+SwTxtFormatter::CTOR: bad offset" );
109cdf0e10cSrcweir 		nStart = GetInfo().GetTxt().Len();
110cdf0e10cSrcweir 	}
111cdf0e10cSrcweir 
112cdf0e10cSrcweir }
113cdf0e10cSrcweir 
114cdf0e10cSrcweir /*************************************************************************
115cdf0e10cSrcweir  *						SwTxtFormatter::DTOR
116cdf0e10cSrcweir  *************************************************************************/
117cdf0e10cSrcweir 
~SwTxtFormatter()118cdf0e10cSrcweir SwTxtFormatter::~SwTxtFormatter()
119cdf0e10cSrcweir {
120cdf0e10cSrcweir 	// Auesserst unwahrscheinlich aber denkbar.
121cdf0e10cSrcweir 	// z.B.: Feld spaltet sich auf, Widows schlagen zu
122cdf0e10cSrcweir 	if( GetInfo().GetRest() )
123cdf0e10cSrcweir 	{
124cdf0e10cSrcweir 		delete GetInfo().GetRest();
125cdf0e10cSrcweir 		GetInfo().SetRest(0);
126cdf0e10cSrcweir 	}
127cdf0e10cSrcweir }
128cdf0e10cSrcweir 
129cdf0e10cSrcweir /*************************************************************************
130cdf0e10cSrcweir  *						SwTxtFormatter::Insert()
131cdf0e10cSrcweir  *************************************************************************/
132cdf0e10cSrcweir 
Insert(SwLineLayout * pLay)133cdf0e10cSrcweir void SwTxtFormatter::Insert( SwLineLayout *pLay )
134cdf0e10cSrcweir {
135cdf0e10cSrcweir 	// Einfuegen heute mal ausnahmsweise hinter dem aktuellen Element.
136cdf0e10cSrcweir 	if ( pCurr )
137cdf0e10cSrcweir 	{
138cdf0e10cSrcweir 		pLay->SetNext( pCurr->GetNext() );
139cdf0e10cSrcweir 		pCurr->SetNext( pLay );
140cdf0e10cSrcweir 	}
141cdf0e10cSrcweir 	else
142cdf0e10cSrcweir 		pCurr = pLay;
143cdf0e10cSrcweir }
144cdf0e10cSrcweir 
145cdf0e10cSrcweir /*************************************************************************
146cdf0e10cSrcweir  *					SwTxtFormatter::GetFrmRstHeight()
147cdf0e10cSrcweir  *************************************************************************/
148cdf0e10cSrcweir 
GetFrmRstHeight() const149cdf0e10cSrcweir KSHORT SwTxtFormatter::GetFrmRstHeight() const
150cdf0e10cSrcweir {
151cdf0e10cSrcweir 	// 8725: Uns interessiert die Resthoehe bezogen auf die Seite.
152cdf0e10cSrcweir 	// Wenn wir in einer Tabelle stehen, dann ist pFrm->GetUpper() nicht
153cdf0e10cSrcweir 	// die Seite. GetFrmRstHeight() wird im Zusammenhang mit den Ftn
154cdf0e10cSrcweir 	// gerufen.
155cdf0e10cSrcweir 	// Falsch: const SwFrm *pUpper = pFrm->GetUpper();
156cdf0e10cSrcweir 	const SwFrm *pPage = (const SwFrm*)pFrm->FindPageFrm();
157cdf0e10cSrcweir 	const SwTwips nHeight = pPage->Frm().Top()
158cdf0e10cSrcweir 						  + pPage->Prt().Top()
159cdf0e10cSrcweir 						  + pPage->Prt().Height() - Y();
160cdf0e10cSrcweir 	if( 0 > nHeight )
161cdf0e10cSrcweir 		return pCurr->Height();
162cdf0e10cSrcweir 	else
163cdf0e10cSrcweir 		return KSHORT( nHeight );
164cdf0e10cSrcweir }
165cdf0e10cSrcweir 
166cdf0e10cSrcweir /*************************************************************************
167cdf0e10cSrcweir  *					SwTxtFormatter::UnderFlow()
168cdf0e10cSrcweir  *************************************************************************/
169cdf0e10cSrcweir 
UnderFlow(SwTxtFormatInfo & rInf)170cdf0e10cSrcweir SwLinePortion *SwTxtFormatter::UnderFlow( SwTxtFormatInfo &rInf )
171cdf0e10cSrcweir {
172cdf0e10cSrcweir 	// Werte sichern und rInf initialisieren.
173cdf0e10cSrcweir 	SwLinePortion *pUnderFlow = rInf.GetUnderFlow();
174cdf0e10cSrcweir 	if( !pUnderFlow )
175cdf0e10cSrcweir 		return 0;
176cdf0e10cSrcweir 
177cdf0e10cSrcweir 	// Wir formatieren rueckwaerts, d.h. dass Attributwechsel in der
178cdf0e10cSrcweir 	// naechsten Zeile durchaus noch einmal drankommen koennen.
179cdf0e10cSrcweir 	// Zu beobachten in 8081.sdw, wenn man in der ersten Zeile Text eingibt.
180cdf0e10cSrcweir 
181cdf0e10cSrcweir 	const xub_StrLen nSoftHyphPos = rInf.GetSoftHyphPos();
182cdf0e10cSrcweir     const xub_StrLen nUnderScorePos = rInf.GetUnderScorePos();
183cdf0e10cSrcweir 
184cdf0e10cSrcweir 	// 8358, 8359: Flys sichern und auf 0 setzen, sonst GPF
185cdf0e10cSrcweir 	// 3983: Nicht ClearFly(rInf) !
186cdf0e10cSrcweir 	SwFlyPortion *pFly = rInf.GetFly();
187cdf0e10cSrcweir 	rInf.SetFly( 0 );
188cdf0e10cSrcweir 
189cdf0e10cSrcweir 	FeedInf( rInf );
190cdf0e10cSrcweir 	rInf.SetLast( pCurr );
191cdf0e10cSrcweir 	// pUnderFlow braucht nicht deletet werden, weil es im folgenden
192cdf0e10cSrcweir 	// Truncate() untergehen wird.
193cdf0e10cSrcweir 	rInf.SetUnderFlow(0);
194cdf0e10cSrcweir 	rInf.SetSoftHyphPos( nSoftHyphPos );
195cdf0e10cSrcweir     rInf.SetUnderScorePos( nUnderScorePos );
196cdf0e10cSrcweir     rInf.SetPaintOfst( GetLeftMargin() );
197cdf0e10cSrcweir 
198cdf0e10cSrcweir 	// Wir suchen die Portion mit der Unterlaufposition
199cdf0e10cSrcweir 	SwLinePortion *pPor = pCurr->GetFirstPortion();
200cdf0e10cSrcweir 	if( pPor != pUnderFlow )
201cdf0e10cSrcweir 	{
202cdf0e10cSrcweir 		// pPrev wird die letzte Portion vor pUnderFlow,
203cdf0e10cSrcweir 		// die noch eine echte Breite hat.
204cdf0e10cSrcweir 		// Ausnahme: SoftHyphPortions duerfen dabei natuerlich
205cdf0e10cSrcweir 		// nicht vergessen werden, obwohl sie keine Breite haben.
206cdf0e10cSrcweir         SwLinePortion *pTmpPrev = pPor;
207cdf0e10cSrcweir 		while( pPor && pPor != pUnderFlow )
208cdf0e10cSrcweir 		{
209cdf0e10cSrcweir 			DBG_LOOP;
210cdf0e10cSrcweir 			if( !pPor->IsKernPortion() &&
211cdf0e10cSrcweir 				( pPor->Width() || pPor->IsSoftHyphPortion() ) )
212cdf0e10cSrcweir 			{
213cdf0e10cSrcweir                 while( pTmpPrev != pPor )
214cdf0e10cSrcweir 				{
215cdf0e10cSrcweir                     pTmpPrev->Move( rInf );
216cdf0e10cSrcweir                     rInf.SetLast( pTmpPrev );
217cdf0e10cSrcweir                     pTmpPrev = pTmpPrev->GetPortion();
218cdf0e10cSrcweir                     ASSERT( pTmpPrev, "UnderFlow: Loosing control!" );
219cdf0e10cSrcweir 				};
220cdf0e10cSrcweir 			}
221cdf0e10cSrcweir 			pPor = pPor->GetPortion();
222cdf0e10cSrcweir 		}
223cdf0e10cSrcweir         pPor = pTmpPrev;
224cdf0e10cSrcweir 		if( pPor && // Flies + Initialen werden nicht beim UnderFlow mitgenommen
225cdf0e10cSrcweir 			( pPor->IsFlyPortion() || pPor->IsDropPortion() ||
226cdf0e10cSrcweir 			  pPor->IsFlyCntPortion() ) )
227cdf0e10cSrcweir 		{
228cdf0e10cSrcweir 			pPor->Move( rInf );
229cdf0e10cSrcweir 			rInf.SetLast( pPor );
230cdf0e10cSrcweir 			rInf.SetStopUnderFlow( sal_True );
231cdf0e10cSrcweir 			pPor = pUnderFlow;
232cdf0e10cSrcweir 		}
233cdf0e10cSrcweir 	}
234cdf0e10cSrcweir 
235cdf0e10cSrcweir 	// Was? Die Unterlaufsituation ist nicht in der Portion-Kette ?
236cdf0e10cSrcweir 	ASSERT( pPor, "SwTxtFormatter::UnderFlow: overflow but underflow" );
237cdf0e10cSrcweir 
238cdf0e10cSrcweir     // OD 2004-05-26 #i29529# - correction: no delete of footnotes
239cdf0e10cSrcweir //    if( rInf.IsFtnInside() && pPor && !rInf.IsQuick() )
240cdf0e10cSrcweir //    {
241cdf0e10cSrcweir //        SwLinePortion *pTmp = pPor->GetPortion();
242cdf0e10cSrcweir //        while( pTmp )
243cdf0e10cSrcweir //        {
244cdf0e10cSrcweir //            if( pTmp->IsFtnPortion() )
245cdf0e10cSrcweir //                ((SwFtnPortion*)pTmp)->ClearFtn();
246cdf0e10cSrcweir //            pTmp = pTmp->GetPortion();
247cdf0e10cSrcweir //        }
248cdf0e10cSrcweir //    }
249cdf0e10cSrcweir 
250cdf0e10cSrcweir 	/*-----------------14.12.94 09:45-------------------
251cdf0e10cSrcweir 	 * 9849: Schnellschuss
252cdf0e10cSrcweir 	 * --------------------------------------------------*/
253cdf0e10cSrcweir 	if ( pPor==rInf.GetLast() )
254cdf0e10cSrcweir 	{
255cdf0e10cSrcweir 		// Hier landen wir, wenn die UnderFlow-ausloesende Portion sich
256cdf0e10cSrcweir 		// ueber die ganze Zeile erstreckt, z. B. wenn ein Wort ueber
257cdf0e10cSrcweir 		// mehrere Zeilen geht und in der zweiten Zeile in einen Fly
258cdf0e10cSrcweir 		// hineinlaeuft!
259cdf0e10cSrcweir 		rInf.SetFly( pFly ); // wg. 28300
260cdf0e10cSrcweir 		pPor->Truncate();
261cdf0e10cSrcweir 		return pPor; // Reicht das?
262cdf0e10cSrcweir 	}
263cdf0e10cSrcweir 	/*---------------------------------------------------
264cdf0e10cSrcweir 	 * Ende des Schnellschusses wg. 9849
265cdf0e10cSrcweir 	 * --------------------------------------------------*/
266cdf0e10cSrcweir 
267cdf0e10cSrcweir 	// 4656: X + Width == 0 bei SoftHyph > Zeile ?!
268cdf0e10cSrcweir 	if( !pPor || !(rInf.X() + pPor->Width()) )
269cdf0e10cSrcweir 	{
270cdf0e10cSrcweir 		delete pFly;
271cdf0e10cSrcweir 		return 0;
272cdf0e10cSrcweir 	}
273cdf0e10cSrcweir 
274cdf0e10cSrcweir 	// Vorbereitungen auf's Format()
275cdf0e10cSrcweir 	// Wir muessen die Kette hinter pLast abknipsen, weil
276cdf0e10cSrcweir 	// nach dem Format() ein Insert erfolgt.
277cdf0e10cSrcweir 	SeekAndChg( rInf );
278cdf0e10cSrcweir 
279cdf0e10cSrcweir 	// line width is adjusted, so that pPor does not fit to current
280cdf0e10cSrcweir 	// line anymore
281cdf0e10cSrcweir     rInf.Width( (sal_uInt16)(rInf.X() + (pPor->Width() ? pPor->Width() - 1 : 0)) );
282cdf0e10cSrcweir 	rInf.SetLen( pPor->GetLen() );
283cdf0e10cSrcweir 	rInf.SetFull( sal_False );
284cdf0e10cSrcweir 	if( pFly )
285cdf0e10cSrcweir 	{
286cdf0e10cSrcweir 		// Aus folgendem Grund muss die FlyPortion neu berechnet werden:
287cdf0e10cSrcweir 		// Wenn durch einen grossen Font in der Mitte der Zeile die Grundlinie
288cdf0e10cSrcweir 		// abgesenkt wird und dadurch eine Ueberlappung mit eine Fly entsteht,
289cdf0e10cSrcweir 		// so hat die FlyPortion eine falsche Groesse/Fixsize.
290cdf0e10cSrcweir 		rInf.SetFly( pFly );
291cdf0e10cSrcweir 		CalcFlyWidth( rInf );
292cdf0e10cSrcweir 	}
293cdf0e10cSrcweir 	rInf.GetLast()->SetPortion(0);
294cdf0e10cSrcweir 
295cdf0e10cSrcweir 	// Eine Ausnahme bildet das SwLineLayout, dass sich beim
296cdf0e10cSrcweir 	// ersten Portionwechsel aufspaltet. Hier nun der umgekehrte Weg:
297cdf0e10cSrcweir 	if( rInf.GetLast() == pCurr )
298cdf0e10cSrcweir 	{
299cdf0e10cSrcweir 		if( pPor->InTxtGrp() && !pPor->InExpGrp() )
300cdf0e10cSrcweir 		{
301cdf0e10cSrcweir 			MSHORT nOldWhich = pCurr->GetWhichPor();
302cdf0e10cSrcweir 			*(SwLinePortion*)pCurr = *pPor;
303cdf0e10cSrcweir 			pCurr->SetPortion( pPor->GetPortion() );
304cdf0e10cSrcweir 			pCurr->SetWhichPor( nOldWhich );
305cdf0e10cSrcweir 			pPor->SetPortion( 0 );
306cdf0e10cSrcweir 			delete pPor;
307cdf0e10cSrcweir 			pPor = pCurr;
308cdf0e10cSrcweir 		}
309cdf0e10cSrcweir 	}
310cdf0e10cSrcweir 	pPor->Truncate();
311cdf0e10cSrcweir     SwLinePortion *const pRest( rInf.GetRest() );
312cdf0e10cSrcweir     if (pRest && pRest->InFldGrp() &&
313cdf0e10cSrcweir         static_cast<SwFldPortion*>(pRest)->IsNoLength())
314cdf0e10cSrcweir     {
315cdf0e10cSrcweir         // HACK: decrement again, so we pick up the suffix in next line!
316cdf0e10cSrcweir         --m_nHintEndIndex;
317cdf0e10cSrcweir     }
318cdf0e10cSrcweir     delete pRest;
319cdf0e10cSrcweir 	rInf.SetRest(0);
320cdf0e10cSrcweir 	return pPor;
321cdf0e10cSrcweir }
322cdf0e10cSrcweir 
323cdf0e10cSrcweir /*************************************************************************
324cdf0e10cSrcweir  *						SwTxtFormatter::InsertPortion()
325cdf0e10cSrcweir  *************************************************************************/
326cdf0e10cSrcweir 
InsertPortion(SwTxtFormatInfo & rInf,SwLinePortion * pPor) const327cdf0e10cSrcweir void SwTxtFormatter::InsertPortion( SwTxtFormatInfo &rInf,
328cdf0e10cSrcweir 									SwLinePortion *pPor ) const
329cdf0e10cSrcweir {
330cdf0e10cSrcweir 	// Die neue Portion wird eingefuegt,
331cdf0e10cSrcweir 	// bei dem LineLayout ist allerdings alles anders...
332cdf0e10cSrcweir     if( pPor == pCurr )
333cdf0e10cSrcweir     {
334cdf0e10cSrcweir         if ( pCurr->GetPortion() )
335cdf0e10cSrcweir         {
336cdf0e10cSrcweir             pPor = pCurr->GetPortion();
337cdf0e10cSrcweir         }
338cdf0e10cSrcweir 
339cdf0e10cSrcweir         // --> OD 2010-07-07 #i112181#
340cdf0e10cSrcweir         rInf.SetOtherThanFtnInside( rInf.IsOtherThanFtnInside() || !pPor->IsFtnPortion() );
341cdf0e10cSrcweir         // <--
342cdf0e10cSrcweir     }
343cdf0e10cSrcweir 	else
344cdf0e10cSrcweir 	{
345cdf0e10cSrcweir 		SwLinePortion *pLast = rInf.GetLast();
346cdf0e10cSrcweir 		if( pLast->GetPortion() )
347cdf0e10cSrcweir 		{
348cdf0e10cSrcweir 			while( pLast->GetPortion() )
349cdf0e10cSrcweir 				pLast = pLast->GetPortion();
350cdf0e10cSrcweir 			rInf.SetLast( pLast );
351cdf0e10cSrcweir 		}
352cdf0e10cSrcweir 		pLast->Insert( pPor );
353cdf0e10cSrcweir 
354cdf0e10cSrcweir         rInf.SetOtherThanFtnInside( rInf.IsOtherThanFtnInside() || !pPor->IsFtnPortion() );
355cdf0e10cSrcweir 
356cdf0e10cSrcweir         // Maxima anpassen:
357cdf0e10cSrcweir         if( pCurr->Height() < pPor->Height() )
358cdf0e10cSrcweir             pCurr->Height( pPor->Height() );
359cdf0e10cSrcweir         if( pCurr->GetAscent() < pPor->GetAscent() )
360cdf0e10cSrcweir             pCurr->SetAscent( pPor->GetAscent() );
361cdf0e10cSrcweir 	}
362cdf0e10cSrcweir 
363cdf0e10cSrcweir 	// manchmal werden ganze Ketten erzeugt (z.B. durch Hyphenate)
364cdf0e10cSrcweir 	rInf.SetLast( pPor );
365cdf0e10cSrcweir 	while( pPor )
366cdf0e10cSrcweir 	{
367cdf0e10cSrcweir 		DBG_LOOP;
368cdf0e10cSrcweir 		pPor->Move( rInf );
369cdf0e10cSrcweir 		rInf.SetLast( pPor );
370cdf0e10cSrcweir 		pPor = pPor->GetPortion();
371cdf0e10cSrcweir 	}
372cdf0e10cSrcweir }
373cdf0e10cSrcweir 
374cdf0e10cSrcweir /*************************************************************************
375cdf0e10cSrcweir  *						SwTxtFormatter::BuildPortion()
376cdf0e10cSrcweir  *************************************************************************/
377cdf0e10cSrcweir 
BuildPortions(SwTxtFormatInfo & rInf)378cdf0e10cSrcweir void SwTxtFormatter::BuildPortions( SwTxtFormatInfo &rInf )
379cdf0e10cSrcweir {
380cdf0e10cSrcweir 	ASSERT( rInf.GetTxt().Len() < STRING_LEN,
381cdf0e10cSrcweir 			"SwTxtFormatter::BuildPortions: bad text length in info" );
382cdf0e10cSrcweir 
383cdf0e10cSrcweir 	rInf.ChkNoHyph( CntEndHyph(), CntMidHyph() );
384cdf0e10cSrcweir 
385cdf0e10cSrcweir 	// Erst NewTxtPortion() entscheidet, ob pCurr in pPor landet.
386cdf0e10cSrcweir 	// Wir muessen in jedem Fall dafuer sorgen, dass der Font eingestellt
387cdf0e10cSrcweir 	// wird. In CalcAscent geschieht dies automatisch.
388cdf0e10cSrcweir     rInf.SetLast( pCurr );
389cdf0e10cSrcweir 	rInf.ForcedLeftMargin( 0 );
390cdf0e10cSrcweir 
391cdf0e10cSrcweir     ASSERT( pCurr->FindLastPortion() == pCurr, "pLast supposed to equal pCurr" );
392cdf0e10cSrcweir 
393cdf0e10cSrcweir     if( !pCurr->GetAscent() && !pCurr->Height() )
394cdf0e10cSrcweir         CalcAscent( rInf, pCurr );
395cdf0e10cSrcweir 
396cdf0e10cSrcweir     SeekAndChg( rInf );
397cdf0e10cSrcweir 
398cdf0e10cSrcweir     // In CalcFlyWidth wird Width() verkuerzt, wenn eine FlyPortion vorliegt.
399cdf0e10cSrcweir     ASSERT( !rInf.X() || pMulti, "SwTxtFormatter::BuildPortion X=0?" );
400cdf0e10cSrcweir     CalcFlyWidth( rInf );
401cdf0e10cSrcweir     SwFlyPortion *pFly = rInf.GetFly();
402cdf0e10cSrcweir     if( pFly )
403cdf0e10cSrcweir     {
404cdf0e10cSrcweir         if ( 0 < pFly->Fix() )
405cdf0e10cSrcweir             ClearFly( rInf );
406cdf0e10cSrcweir         else
407cdf0e10cSrcweir             rInf.SetFull(sal_True);
408cdf0e10cSrcweir     }
409cdf0e10cSrcweir 
410cdf0e10cSrcweir 	SwLinePortion *pPor = NewPortion( rInf );
411cdf0e10cSrcweir 
412cdf0e10cSrcweir     // Asian grid stuff
413cdf0e10cSrcweir     GETGRID( pFrm->FindPageFrm() )
414cdf0e10cSrcweir     const sal_Bool bHasGrid = pGrid && rInf.SnapToGrid() &&
415cdf0e10cSrcweir                               GRID_LINES_CHARS == pGrid->GetGridType();
416cdf0e10cSrcweir 
417cdf0e10cSrcweir 	const SwDoc *pDoc = rInf.GetTxtFrm()->GetNode()->GetDoc();
418cdf0e10cSrcweir     const sal_uInt16 nGridWidth = bHasGrid ?
419cdf0e10cSrcweir                                 GETGRIDWIDTH(pGrid,pDoc) : 0;	//for textgrid refactor
420cdf0e10cSrcweir 
421cdf0e10cSrcweir     // used for grid mode only:
422cdf0e10cSrcweir     // the pointer is stored, because after formatting of non-asian text,
423cdf0e10cSrcweir     // the width of the kerning portion has to be adjusted
424cdf0e10cSrcweir     SwKernPortion* pGridKernPortion = 0;
425cdf0e10cSrcweir 
426cdf0e10cSrcweir 	sal_Bool bFull;
427cdf0e10cSrcweir     SwTwips nUnderLineStart = 0;
428cdf0e10cSrcweir 	rInf.Y( Y() );
429cdf0e10cSrcweir 
430cdf0e10cSrcweir 	while( pPor && !rInf.IsStop() )
431cdf0e10cSrcweir 	{
432cdf0e10cSrcweir 		ASSERT( rInf.GetLen() < STRING_LEN &&
433cdf0e10cSrcweir 				rInf.GetIdx() <= rInf.GetTxt().Len(),
434cdf0e10cSrcweir 				"SwTxtFormatter::BuildPortions: bad length in info" );
435cdf0e10cSrcweir 		DBG_LOOP;
436cdf0e10cSrcweir 
437cdf0e10cSrcweir         // We have to check the script for fields in order to set the
438cdf0e10cSrcweir         // correct nActual value for the font.
439cdf0e10cSrcweir         if( pPor->InFldGrp() )
440cdf0e10cSrcweir             ((SwFldPortion*)pPor)->CheckScript( rInf );
441cdf0e10cSrcweir 
442cdf0e10cSrcweir         if( ! bHasGrid && rInf.HasScriptSpace() &&
443cdf0e10cSrcweir             rInf.GetLast() && rInf.GetLast()->InTxtGrp() &&
444cdf0e10cSrcweir             rInf.GetLast()->Width() && !rInf.GetLast()->InNumberGrp() )
445cdf0e10cSrcweir         {
446cdf0e10cSrcweir             sal_uInt8 nNxtActual = rInf.GetFont()->GetActual();
447cdf0e10cSrcweir             sal_uInt8 nLstActual = nNxtActual;
448cdf0e10cSrcweir             sal_uInt16 nLstHeight = (sal_uInt16)rInf.GetFont()->GetHeight();
449cdf0e10cSrcweir             sal_Bool bAllowBefore = sal_False;
450cdf0e10cSrcweir             sal_Bool bAllowBehind = sal_False;
451cdf0e10cSrcweir             const CharClass& rCC = GetAppCharClass();
452cdf0e10cSrcweir 
453cdf0e10cSrcweir             // are there any punctuation characters on both sides
454cdf0e10cSrcweir             // of the kerning portion?
455cdf0e10cSrcweir             if ( pPor->InFldGrp() )
456cdf0e10cSrcweir             {
457cdf0e10cSrcweir                 XubString aAltTxt;
458cdf0e10cSrcweir                 if ( ((SwFldPortion*)pPor)->GetExpTxt( rInf, aAltTxt ) &&
459cdf0e10cSrcweir                         aAltTxt.Len() )
460cdf0e10cSrcweir                 {
461cdf0e10cSrcweir                     bAllowBehind = rCC.isLetterNumeric( aAltTxt, 0 );
462cdf0e10cSrcweir 
463cdf0e10cSrcweir                     const SwFont* pTmpFnt = ((SwFldPortion*)pPor)->GetFont();
464cdf0e10cSrcweir                     if ( pTmpFnt )
465cdf0e10cSrcweir                         nNxtActual = pTmpFnt->GetActual();
466cdf0e10cSrcweir                 }
467cdf0e10cSrcweir             }
468cdf0e10cSrcweir             else
469cdf0e10cSrcweir                 bAllowBehind = rCC.isLetterNumeric( rInf.GetTxt(), rInf.GetIdx() );
470cdf0e10cSrcweir 
471cdf0e10cSrcweir             const SwLinePortion* pLast = rInf.GetLast();
472cdf0e10cSrcweir             if ( bAllowBehind && pLast )
473cdf0e10cSrcweir             {
474cdf0e10cSrcweir                 if ( pLast->InFldGrp() )
475cdf0e10cSrcweir                 {
476cdf0e10cSrcweir                     XubString aAltTxt;
477cdf0e10cSrcweir                     if ( ((SwFldPortion*)pLast)->GetExpTxt( rInf, aAltTxt ) &&
478cdf0e10cSrcweir                          aAltTxt.Len() )
479cdf0e10cSrcweir                     {
480cdf0e10cSrcweir                         bAllowBefore = rCC.isLetterNumeric( aAltTxt, aAltTxt.Len() - 1 );
481cdf0e10cSrcweir 
482cdf0e10cSrcweir                         const SwFont* pTmpFnt = ((SwFldPortion*)pLast)->GetFont();
483cdf0e10cSrcweir                         if ( pTmpFnt )
484cdf0e10cSrcweir                         {
485cdf0e10cSrcweir                             nLstActual = pTmpFnt->GetActual();
486cdf0e10cSrcweir                             nLstHeight = (sal_uInt16)pTmpFnt->GetHeight();
487cdf0e10cSrcweir                         }
488cdf0e10cSrcweir                     }
489cdf0e10cSrcweir                 }
490cdf0e10cSrcweir                 else if ( rInf.GetIdx() )
491cdf0e10cSrcweir                 {
492cdf0e10cSrcweir                     bAllowBefore = rCC.isLetterNumeric( rInf.GetTxt(), rInf.GetIdx() - 1 );
493cdf0e10cSrcweir                     // Note: ScriptType returns values in [1,4]
494cdf0e10cSrcweir                     if ( bAllowBefore )
495cdf0e10cSrcweir                         nLstActual = pScriptInfo->ScriptType( rInf.GetIdx() - 1 ) - 1;
496cdf0e10cSrcweir                 }
497cdf0e10cSrcweir 
498cdf0e10cSrcweir                 nLstHeight /= 5;
499cdf0e10cSrcweir                 // does the kerning portion still fit into the line?
500cdf0e10cSrcweir                 if( bAllowBefore && ( nLstActual != nNxtActual ) &&
501cdf0e10cSrcweir                     nLstHeight && rInf.X() + nLstHeight <= rInf.Width() )
502cdf0e10cSrcweir                 {
503cdf0e10cSrcweir                     SwKernPortion* pKrn =
504cdf0e10cSrcweir                         new SwKernPortion( *rInf.GetLast(), nLstHeight,
505cdf0e10cSrcweir                                            pLast->InFldGrp() && pPor->InFldGrp() );
506cdf0e10cSrcweir                     rInf.GetLast()->SetPortion( NULL );
507cdf0e10cSrcweir                     InsertPortion( rInf, pKrn );
508cdf0e10cSrcweir                 }
509cdf0e10cSrcweir             }
510cdf0e10cSrcweir         }
511cdf0e10cSrcweir         else if ( bHasGrid && ! pGridKernPortion && ! pMulti )
512cdf0e10cSrcweir         {
513cdf0e10cSrcweir             // insert a grid kerning portion
514cdf0e10cSrcweir             if ( ! pGridKernPortion )
515cdf0e10cSrcweir                 pGridKernPortion = pPor->IsKernPortion() ?
516cdf0e10cSrcweir                                    (SwKernPortion*)pPor :
517cdf0e10cSrcweir                                    new SwKernPortion( *pCurr );
518cdf0e10cSrcweir 
519cdf0e10cSrcweir             // if we have a new GridKernPortion, we initially calculate
520cdf0e10cSrcweir             // its size so that its ends on the grid
521cdf0e10cSrcweir             const SwPageFrm* pPageFrm = pFrm->FindPageFrm();
522cdf0e10cSrcweir             const SwLayoutFrm* pBody = pPageFrm->FindBodyCont();
523cdf0e10cSrcweir             SWRECTFN( pPageFrm )
524cdf0e10cSrcweir 
525cdf0e10cSrcweir             const long nGridOrigin = pBody ?
526cdf0e10cSrcweir                                     (pBody->*fnRect->fnGetPrtLeft)() :
527cdf0e10cSrcweir                                     (pPageFrm->*fnRect->fnGetPrtLeft)();
528cdf0e10cSrcweir 
529cdf0e10cSrcweir             SwTwips nStartX = rInf.X() + GetLeftMargin();
530cdf0e10cSrcweir             if ( bVert )
531cdf0e10cSrcweir             {
532cdf0e10cSrcweir                 Point aPoint( nStartX, 0 );
533cdf0e10cSrcweir                 pFrm->SwitchHorizontalToVertical( aPoint );
534cdf0e10cSrcweir                 nStartX = aPoint.Y();
535cdf0e10cSrcweir             }
536cdf0e10cSrcweir 
537cdf0e10cSrcweir             const SwTwips nOfst = nStartX - nGridOrigin;
538cdf0e10cSrcweir             if ( nOfst )
539cdf0e10cSrcweir             {
540cdf0e10cSrcweir                 const sal_uLong i = ( nOfst > 0 ) ?
541cdf0e10cSrcweir                                 ( ( nOfst - 1 ) / nGridWidth + 1 ) :
542cdf0e10cSrcweir                                 0;
543cdf0e10cSrcweir                 const SwTwips nKernWidth = i * nGridWidth - nOfst;
544cdf0e10cSrcweir                 const SwTwips nRestWidth = rInf.Width() - rInf.X();
545cdf0e10cSrcweir 
546cdf0e10cSrcweir                 if ( nKernWidth <= nRestWidth )
547cdf0e10cSrcweir                     pGridKernPortion->Width( (sal_uInt16)nKernWidth );
548cdf0e10cSrcweir             }
549cdf0e10cSrcweir 
550cdf0e10cSrcweir             if ( pGridKernPortion != pPor )
551cdf0e10cSrcweir                 InsertPortion( rInf, pGridKernPortion );
552cdf0e10cSrcweir         }
553cdf0e10cSrcweir 
554cdf0e10cSrcweir 		// the multi-portion has it's own format function
555cdf0e10cSrcweir         if( pPor->IsMultiPortion() && ( !pMulti || pMulti->IsBidi() ) )
556cdf0e10cSrcweir 			bFull = BuildMultiPortion( rInf, *((SwMultiPortion*)pPor) );
557cdf0e10cSrcweir 		else
558cdf0e10cSrcweir 			bFull = pPor->Format( rInf );
559cdf0e10cSrcweir 
560cdf0e10cSrcweir 		if( rInf.IsRuby() && !rInf.GetRest() )
561cdf0e10cSrcweir 			bFull = sal_True;
562cdf0e10cSrcweir 
563cdf0e10cSrcweir         // if we are underlined, we store the beginning of this underlined
564cdf0e10cSrcweir         // segment for repaint optimization
565cdf0e10cSrcweir         if ( UNDERLINE_NONE != pFnt->GetUnderline() && ! nUnderLineStart )
566cdf0e10cSrcweir             nUnderLineStart = GetLeftMargin() + rInf.X();
567cdf0e10cSrcweir 
568cdf0e10cSrcweir         if ( pPor->IsFlyPortion() )
569cdf0e10cSrcweir             pCurr->SetFly( sal_True );
570cdf0e10cSrcweir         // some special cases, where we have to take care for the repaint
571cdf0e10cSrcweir         // offset:
572cdf0e10cSrcweir         // 1. Underlined portions due to special underline feature
573cdf0e10cSrcweir         // 2. Right Tab
574cdf0e10cSrcweir         // 3. BidiPortions
575cdf0e10cSrcweir         // 4. other Multiportions
576cdf0e10cSrcweir         // 5. DropCaps
577cdf0e10cSrcweir         // 6. Grid Mode
578cdf0e10cSrcweir         else if ( ( ! rInf.GetPaintOfst() || nUnderLineStart < rInf.GetPaintOfst() ) &&
579cdf0e10cSrcweir                   // 1. Underlined portions
580cdf0e10cSrcweir                   nUnderLineStart &&
581cdf0e10cSrcweir                      // reformat is at end of an underlined portion and next portion
582cdf0e10cSrcweir                      // is not underlined
583cdf0e10cSrcweir                   ( ( rInf.GetReformatStart() == rInf.GetIdx() &&
584cdf0e10cSrcweir                       UNDERLINE_NONE == pFnt->GetUnderline()
585cdf0e10cSrcweir                     ) ||
586cdf0e10cSrcweir                      // reformat is inside portion and portion is underlined
587cdf0e10cSrcweir                     ( rInf.GetReformatStart() >= rInf.GetIdx() &&
588cdf0e10cSrcweir                       rInf.GetReformatStart() <= rInf.GetIdx() + pPor->GetLen() &&
589cdf0e10cSrcweir                       UNDERLINE_NONE != pFnt->GetUnderline() ) ) )
590cdf0e10cSrcweir             rInf.SetPaintOfst( nUnderLineStart );
591cdf0e10cSrcweir         else if (  ! rInf.GetPaintOfst() &&
592cdf0e10cSrcweir                    // 2. Right Tab
593cdf0e10cSrcweir                    ( ( pPor->InTabGrp() && !pPor->IsTabLeftPortion() ) ||
594cdf0e10cSrcweir                    // 3. BidiPortions
595cdf0e10cSrcweir                      ( pPor->IsMultiPortion() && ((SwMultiPortion*)pPor)->IsBidi() ) ||
596cdf0e10cSrcweir                    // 4. Multi Portion and 5. Drop Caps
597cdf0e10cSrcweir                      ( ( pPor->IsDropPortion() || pPor->IsMultiPortion() ) &&
598cdf0e10cSrcweir                        rInf.GetReformatStart() >= rInf.GetIdx() &&
599cdf0e10cSrcweir                        rInf.GetReformatStart() <= rInf.GetIdx() + pPor->GetLen() )
600cdf0e10cSrcweir                    // 6. Grid Mode
601cdf0e10cSrcweir                      || ( bHasGrid && SW_CJK != pFnt->GetActual() )
602cdf0e10cSrcweir                    )
603cdf0e10cSrcweir                 )
604cdf0e10cSrcweir             // we store the beginning of the critical portion as our
605cdf0e10cSrcweir             // paint offset
606cdf0e10cSrcweir             rInf.SetPaintOfst( GetLeftMargin() + rInf.X() );
607cdf0e10cSrcweir 
608cdf0e10cSrcweir         // under one of these conditions we are allowed to delete the
609cdf0e10cSrcweir         // start of the underline portion
610cdf0e10cSrcweir         if ( IsUnderlineBreak( *pPor, *pFnt ) )
611cdf0e10cSrcweir             nUnderLineStart = 0;
612cdf0e10cSrcweir 
613cdf0e10cSrcweir         if( pPor->IsFlyCntPortion() || ( pPor->IsMultiPortion() &&
614cdf0e10cSrcweir 			((SwMultiPortion*)pPor)->HasFlyInCntnt() ) )
615cdf0e10cSrcweir 			SetFlyInCntBase();
616cdf0e10cSrcweir 		// 5964: bUnderFlow muss zurueckgesetzt werden, sonst wird beim
617cdf0e10cSrcweir 		// 		 naechsten Softhyphen wieder umgebrochen!
618cdf0e10cSrcweir 		if ( !bFull )
619cdf0e10cSrcweir 		{
620cdf0e10cSrcweir 			rInf.ClrUnderFlow();
621cdf0e10cSrcweir             if( ! bHasGrid && rInf.HasScriptSpace() && pPor->InTxtGrp() &&
622cdf0e10cSrcweir                 pPor->GetLen() && !pPor->InFldGrp() )
623cdf0e10cSrcweir 			{
624cdf0e10cSrcweir                 // The distance between two different scripts is set
625cdf0e10cSrcweir                 // to 20% of the fontheight.
626cdf0e10cSrcweir                 xub_StrLen nTmp = rInf.GetIdx() + pPor->GetLen();
627cdf0e10cSrcweir                 if( nTmp == pScriptInfo->NextScriptChg( nTmp - 1 ) &&
628cdf0e10cSrcweir                     nTmp != rInf.GetTxt().Len() )
629cdf0e10cSrcweir                 {
630cdf0e10cSrcweir                     sal_uInt16 nDist = (sal_uInt16)(rInf.GetFont()->GetHeight()/5);
631cdf0e10cSrcweir 
632cdf0e10cSrcweir                     if( nDist )
633cdf0e10cSrcweir                     {
634cdf0e10cSrcweir                         // we do not want a kerning portion if any end
635cdf0e10cSrcweir                         // would be a punctuation character
636cdf0e10cSrcweir                         const CharClass& rCC = GetAppCharClass();
637cdf0e10cSrcweir                         if ( rCC.isLetterNumeric( rInf.GetTxt(), nTmp - 1 ) &&
638cdf0e10cSrcweir                              rCC.isLetterNumeric( rInf.GetTxt(), nTmp ) )
639cdf0e10cSrcweir                         {
640cdf0e10cSrcweir                             // does the kerning portion still fit into the line?
641cdf0e10cSrcweir                             if ( rInf.X() + pPor->Width() + nDist <= rInf.Width() )
642cdf0e10cSrcweir                                 new SwKernPortion( *pPor, nDist );
643cdf0e10cSrcweir                             else
644cdf0e10cSrcweir                                 bFull = sal_True;
645cdf0e10cSrcweir                         }
646cdf0e10cSrcweir                     }
647cdf0e10cSrcweir                 }
648cdf0e10cSrcweir 			}
649cdf0e10cSrcweir 		}
650cdf0e10cSrcweir 
651cdf0e10cSrcweir         if ( bHasGrid && pPor != pGridKernPortion && ! pMulti )
652cdf0e10cSrcweir         {
653cdf0e10cSrcweir             xub_StrLen nTmp = rInf.GetIdx() + pPor->GetLen();
654cdf0e10cSrcweir             const SwTwips nRestWidth = rInf.Width() - rInf.X() - pPor->Width();
655cdf0e10cSrcweir 
656cdf0e10cSrcweir             const sal_uInt8 nCurrScript = pFnt->GetActual(); // pScriptInfo->ScriptType( rInf.GetIdx() );
657cdf0e10cSrcweir             const sal_uInt8 nNextScript = nTmp >= rInf.GetTxt().Len() ?
658cdf0e10cSrcweir                                      SW_CJK :
659cdf0e10cSrcweir                                      SwScriptInfo::WhichFont( nTmp, 0, pScriptInfo );
660cdf0e10cSrcweir 
661cdf0e10cSrcweir             // snap non-asian text to grid if next portion is ASIAN or
662cdf0e10cSrcweir             // there are no more portions in this line
663cdf0e10cSrcweir             // be careful when handling an underflow event: the gridkernportion
664cdf0e10cSrcweir             // could have been deleted
665cdf0e10cSrcweir             if ( nRestWidth > 0 && SW_CJK != nCurrScript &&
666cdf0e10cSrcweir                 ! rInf.IsUnderFlow() && ( bFull || SW_CJK == nNextScript ) )
667cdf0e10cSrcweir             {
668cdf0e10cSrcweir                 ASSERT( pGridKernPortion, "No GridKernPortion available" )
669cdf0e10cSrcweir 
670cdf0e10cSrcweir                 // calculate size
671cdf0e10cSrcweir                 SwLinePortion* pTmpPor = pGridKernPortion->GetPortion();
672cdf0e10cSrcweir                 sal_uInt16 nSumWidth = pPor->Width();
673cdf0e10cSrcweir                 while ( pTmpPor )
674cdf0e10cSrcweir                 {
675cdf0e10cSrcweir                     nSumWidth = nSumWidth + pTmpPor->Width();
676cdf0e10cSrcweir                     pTmpPor = pTmpPor->GetPortion();
677cdf0e10cSrcweir                 }
678cdf0e10cSrcweir 
679cdf0e10cSrcweir                 const sal_uInt16 i = nSumWidth ?
680cdf0e10cSrcweir                                  ( nSumWidth - 1 ) / nGridWidth + 1 :
681cdf0e10cSrcweir                                  0;
682cdf0e10cSrcweir                 const SwTwips nTmpWidth = i * nGridWidth;
683cdf0e10cSrcweir                 const SwTwips nKernWidth = Min( (SwTwips)(nTmpWidth - nSumWidth),
684cdf0e10cSrcweir                                                 nRestWidth );
685cdf0e10cSrcweir                 const sal_uInt16 nKernWidth_1 = (sal_uInt16)(nKernWidth / 2);
686cdf0e10cSrcweir 
687cdf0e10cSrcweir                 ASSERT( nKernWidth <= nRestWidth,
688cdf0e10cSrcweir                         "Not enough space left for adjusting non-asian text in grid mode" )
689cdf0e10cSrcweir 
690cdf0e10cSrcweir                 pGridKernPortion->Width( pGridKernPortion->Width() + nKernWidth_1 );
691cdf0e10cSrcweir                 rInf.X( rInf.X() + nKernWidth_1 );
692cdf0e10cSrcweir 
693cdf0e10cSrcweir                 if ( ! bFull )
694cdf0e10cSrcweir                     new SwKernPortion( *pPor, (short)(nKernWidth - nKernWidth_1),
695cdf0e10cSrcweir                                        sal_False, sal_True );
696cdf0e10cSrcweir 
697cdf0e10cSrcweir                 pGridKernPortion = 0;
698cdf0e10cSrcweir             }
699cdf0e10cSrcweir             else if ( pPor->IsMultiPortion() || pPor->InFixMargGrp() ||
700cdf0e10cSrcweir                       pPor->IsFlyCntPortion() || pPor->InNumberGrp() ||
701cdf0e10cSrcweir                       pPor->InFldGrp() || nCurrScript != nNextScript )
702cdf0e10cSrcweir                 // next portion should snap to grid
703cdf0e10cSrcweir                 pGridKernPortion = 0;
704cdf0e10cSrcweir         }
705cdf0e10cSrcweir 
706cdf0e10cSrcweir 		rInf.SetFull( bFull );
707cdf0e10cSrcweir 
708cdf0e10cSrcweir         // Restportions von mehrzeiligen Feldern haben bisher noch
709cdf0e10cSrcweir 		// nicht den richtigen Ascent.
710cdf0e10cSrcweir 		if ( !pPor->GetLen() && !pPor->IsFlyPortion()
711cdf0e10cSrcweir             && !pPor->IsGrfNumPortion() && ! pPor->InNumberGrp()
712cdf0e10cSrcweir             && !pPor->IsMultiPortion() )
713cdf0e10cSrcweir 			CalcAscent( rInf, pPor );
714cdf0e10cSrcweir 
715cdf0e10cSrcweir 		InsertPortion( rInf, pPor );
716cdf0e10cSrcweir 		pPor = NewPortion( rInf );
717cdf0e10cSrcweir 	}
718cdf0e10cSrcweir 
719cdf0e10cSrcweir 	if( !rInf.IsStop() )
720cdf0e10cSrcweir 	{
721cdf0e10cSrcweir 		// der letzte rechte, zentrierte, dezimale Tab
722cdf0e10cSrcweir 		SwTabPortion *pLastTab = rInf.GetLastTab();
723cdf0e10cSrcweir 		if( pLastTab )
724cdf0e10cSrcweir 			pLastTab->FormatEOL( rInf );
725cdf0e10cSrcweir 		else if( rInf.GetLast() && rInf.LastKernPortion() )
726cdf0e10cSrcweir 			rInf.GetLast()->FormatEOL( rInf );
727cdf0e10cSrcweir 	}
728cdf0e10cSrcweir 	if( pCurr->GetPortion() && pCurr->GetPortion()->InNumberGrp()
729cdf0e10cSrcweir 		&& ((SwNumberPortion*)pCurr->GetPortion())->IsHide() )
730cdf0e10cSrcweir 		rInf.SetNumDone( sal_False );
731cdf0e10cSrcweir 
732cdf0e10cSrcweir 	// 3260, 3860: Fly auf jeden Fall loeschen!
733cdf0e10cSrcweir 	ClearFly( rInf );
734cdf0e10cSrcweir }
735cdf0e10cSrcweir 
736cdf0e10cSrcweir /*************************************************************************
737cdf0e10cSrcweir  *				   SwTxtFormatter::CalcAdjustLine()
738cdf0e10cSrcweir  *************************************************************************/
739cdf0e10cSrcweir 
CalcAdjustLine(SwLineLayout * pCurrent)740cdf0e10cSrcweir void SwTxtFormatter::CalcAdjustLine( SwLineLayout *pCurrent )
741cdf0e10cSrcweir {
742cdf0e10cSrcweir     if( SVX_ADJUST_LEFT != GetAdjust() && !pMulti)
743cdf0e10cSrcweir 	{
744cdf0e10cSrcweir         pCurrent->SetFormatAdj(sal_True);
745cdf0e10cSrcweir 		if( IsFlyInCntBase() )
746cdf0e10cSrcweir 		{
747cdf0e10cSrcweir             CalcAdjLine( pCurrent );
748cdf0e10cSrcweir 			// 23348: z.B. bei zentrierten Flys muessen wir den RefPoint
749cdf0e10cSrcweir 			// auf jeden Fall umsetzen, deshalb bAllWays = sal_True
750cdf0e10cSrcweir             UpdatePos( pCurrent, GetTopLeft(), GetStart(), sal_True );
751cdf0e10cSrcweir 		}
752cdf0e10cSrcweir 	}
753cdf0e10cSrcweir }
754cdf0e10cSrcweir 
755cdf0e10cSrcweir /*************************************************************************
756cdf0e10cSrcweir  *						SwTxtFormatter::CalcAscent()
757cdf0e10cSrcweir  *************************************************************************/
758cdf0e10cSrcweir 
CalcAscent(SwTxtFormatInfo & rInf,SwLinePortion * pPor)759cdf0e10cSrcweir void SwTxtFormatter::CalcAscent( SwTxtFormatInfo &rInf, SwLinePortion *pPor )
760cdf0e10cSrcweir {
761cdf0e10cSrcweir 	if ( pPor->InFldGrp() && ((SwFldPortion*)pPor)->GetFont() )
762cdf0e10cSrcweir 	{
763cdf0e10cSrcweir 		// Numerierungen + InterNetFlds koennen einen eigenen Font beinhalten,
764cdf0e10cSrcweir 		// dann ist ihre Groesse unabhaengig von harten Attributierungen.
765cdf0e10cSrcweir 		SwFont* pFldFnt = ((SwFldPortion*)pPor)->pFnt;
766cdf0e10cSrcweir 		SwFontSave aSave( rInf, pFldFnt );
767cdf0e10cSrcweir         ((SwFldPortion*)pPor)->Height( pFldFnt->GetHeight( rInf.GetVsh(), *rInf.GetOut() ) );
768cdf0e10cSrcweir         ((SwFldPortion*)pPor)->SetAscent( pFldFnt->GetAscent( rInf.GetVsh(), *rInf.GetOut() ) );
769cdf0e10cSrcweir 	}
770cdf0e10cSrcweir     // --> OD 2008-06-05 #i89179#
771cdf0e10cSrcweir     // tab portion representing the list tab of a list label gets the
772cdf0e10cSrcweir     // same height and ascent as the corresponding number portion
773cdf0e10cSrcweir     else if ( pPor->InTabGrp() && pPor->GetLen() == 0 &&
774cdf0e10cSrcweir               rInf.GetLast() && rInf.GetLast()->InNumberGrp() &&
775cdf0e10cSrcweir               static_cast<const SwNumberPortion*>(rInf.GetLast())->HasFont() )
776cdf0e10cSrcweir     {
777cdf0e10cSrcweir         const SwLinePortion* pLast = rInf.GetLast();
778cdf0e10cSrcweir         pPor->Height( pLast->Height() );
779cdf0e10cSrcweir         pPor->SetAscent( pLast->GetAscent() );
780cdf0e10cSrcweir     }
781cdf0e10cSrcweir     // <--
782cdf0e10cSrcweir 	else
783cdf0e10cSrcweir 	{
784cdf0e10cSrcweir 		const SwLinePortion *pLast = rInf.GetLast();
785cdf0e10cSrcweir 		sal_Bool bChg;
786cdf0e10cSrcweir 
787cdf0e10cSrcweir 		// Fallunterscheidung: in leeren Zeilen werden die Attribute
788cdf0e10cSrcweir 		// per SeekStart angeschaltet.
789cdf0e10cSrcweir 		const sal_Bool bFirstPor = rInf.GetLineStart() == rInf.GetIdx();
790cdf0e10cSrcweir 		if ( pPor->IsQuoVadisPortion() )
791cdf0e10cSrcweir 			bChg = SeekStartAndChg( rInf, sal_True );
792cdf0e10cSrcweir 		else
793cdf0e10cSrcweir 		{
794cdf0e10cSrcweir 			if( bFirstPor )
795cdf0e10cSrcweir 			{
796cdf0e10cSrcweir 				if( rInf.GetTxt().Len() )
797cdf0e10cSrcweir 				{
798cdf0e10cSrcweir 					if ( pPor->GetLen() || !rInf.GetIdx()
799cdf0e10cSrcweir 						 || ( pCurr != pLast && !pLast->IsFlyPortion() )
800cdf0e10cSrcweir 						 || !pCurr->IsRest() ) // statt !rInf.GetRest()
801cdf0e10cSrcweir 						bChg = SeekAndChg( rInf );
802cdf0e10cSrcweir 					else
803cdf0e10cSrcweir 						bChg = SeekAndChgBefore( rInf );
804cdf0e10cSrcweir 				}
805cdf0e10cSrcweir                 else if ( pMulti )
806cdf0e10cSrcweir                     // do not open attributes starting at 0 in empty multi
807cdf0e10cSrcweir                     // portions (rotated numbering followed by a footnote
808cdf0e10cSrcweir                     // can cause trouble, because the footnote attribute
809cdf0e10cSrcweir                     // starts at 0, but if we open it, the attribute handler
810cdf0e10cSrcweir                     // cannot handle it.
811cdf0e10cSrcweir                     bChg = sal_False;
812cdf0e10cSrcweir                 else
813cdf0e10cSrcweir                     bChg = SeekStartAndChg( rInf );
814cdf0e10cSrcweir 			}
815cdf0e10cSrcweir 			else
816cdf0e10cSrcweir 				bChg = SeekAndChg( rInf );
817cdf0e10cSrcweir 		}
818cdf0e10cSrcweir 		if( bChg || bFirstPor || !pPor->GetAscent()
819cdf0e10cSrcweir 			|| !rInf.GetLast()->InTxtGrp() )
820cdf0e10cSrcweir 		{
821cdf0e10cSrcweir 			pPor->SetAscent( rInf.GetAscent()  );
822cdf0e10cSrcweir 			pPor->Height( rInf.GetTxtHeight() );
823cdf0e10cSrcweir 		}
824cdf0e10cSrcweir 		else
825cdf0e10cSrcweir 		{
826cdf0e10cSrcweir 			pPor->Height( pLast->Height() );
827cdf0e10cSrcweir 			pPor->SetAscent( pLast->GetAscent() );
828cdf0e10cSrcweir 		}
829cdf0e10cSrcweir 	}
830cdf0e10cSrcweir }
831cdf0e10cSrcweir 
832cdf0e10cSrcweir /*************************************************************************
833cdf0e10cSrcweir  *                      class SwMetaPortion
834cdf0e10cSrcweir  *************************************************************************/
835cdf0e10cSrcweir 
836cdf0e10cSrcweir class SwMetaPortion : public SwTxtPortion
837cdf0e10cSrcweir {
838cdf0e10cSrcweir public:
SwMetaPortion()839cdf0e10cSrcweir     inline  SwMetaPortion() { SetWhichPor( POR_META ); }
840cdf0e10cSrcweir     virtual void Paint( const SwTxtPaintInfo &rInf ) const;
841cdf0e10cSrcweir //    OUTPUT_OPERATOR
842cdf0e10cSrcweir };
843cdf0e10cSrcweir 
844cdf0e10cSrcweir //CLASSIO( SwMetaPortion )
845cdf0e10cSrcweir 
846cdf0e10cSrcweir /*************************************************************************
847cdf0e10cSrcweir  *               virtual SwMetaPortion::Paint()
848cdf0e10cSrcweir  *************************************************************************/
849cdf0e10cSrcweir 
Paint(const SwTxtPaintInfo & rInf) const850cdf0e10cSrcweir void SwMetaPortion::Paint( const SwTxtPaintInfo &rInf ) const
851cdf0e10cSrcweir {
852cdf0e10cSrcweir     if ( Width() )
853cdf0e10cSrcweir     {
854cdf0e10cSrcweir         rInf.DrawViewOpt( *this, POR_META );
855cdf0e10cSrcweir         SwTxtPortion::Paint( rInf );
856cdf0e10cSrcweir     }
857cdf0e10cSrcweir }
858cdf0e10cSrcweir 
859cdf0e10cSrcweir 
860cdf0e10cSrcweir /*************************************************************************
861cdf0e10cSrcweir  *						SwTxtFormatter::WhichTxtPor()
862cdf0e10cSrcweir  *************************************************************************/
863cdf0e10cSrcweir 
WhichTxtPor(SwTxtFormatInfo & rInf) const864cdf0e10cSrcweir SwTxtPortion *SwTxtFormatter::WhichTxtPor( SwTxtFormatInfo &rInf ) const
865cdf0e10cSrcweir {
866cdf0e10cSrcweir     SwTxtPortion *pPor = 0;
867cdf0e10cSrcweir     if( GetFnt()->IsTox() )
868*69a74367SOliver-Rainer Wittmann     {
869cdf0e10cSrcweir         pPor = new SwToxPortion;
870*69a74367SOliver-Rainer Wittmann     }
871*69a74367SOliver-Rainer Wittmann     else if ( GetFnt()->IsInputField() )
872*69a74367SOliver-Rainer Wittmann     {
873*69a74367SOliver-Rainer Wittmann         pPor = new SwTxtInputFldPortion();
874*69a74367SOliver-Rainer Wittmann     }
875cdf0e10cSrcweir     else
876cdf0e10cSrcweir     {
877cdf0e10cSrcweir         if( GetFnt()->IsRef() )
878cdf0e10cSrcweir             pPor = new SwRefPortion;
879cdf0e10cSrcweir         else if (GetFnt()->IsMeta())
880cdf0e10cSrcweir         {
881cdf0e10cSrcweir             pPor = new SwMetaPortion;
882cdf0e10cSrcweir         }
883cdf0e10cSrcweir         else
884cdf0e10cSrcweir         {
885cdf0e10cSrcweir             // Erst zum Schluss !
886cdf0e10cSrcweir             // Wenn pCurr keine Breite hat, kann sie trotzdem schon Inhalt haben,
887cdf0e10cSrcweir              // z.B. bei nicht darstellbaren Zeichen.
888cdf0e10cSrcweir             if( rInf.GetLen() > 0 )
889cdf0e10cSrcweir             {
890cdf0e10cSrcweir                 if( rInf.GetTxt().GetChar(rInf.GetIdx())==CH_TXT_ATR_FIELDSTART )
891cdf0e10cSrcweir                     pPor = new SwFieldMarkPortion();
892cdf0e10cSrcweir                 else if( rInf.GetTxt().GetChar(rInf.GetIdx())==CH_TXT_ATR_FIELDEND )
893cdf0e10cSrcweir                     pPor = new SwFieldMarkPortion();
894cdf0e10cSrcweir                 else if( rInf.GetTxt().GetChar(rInf.GetIdx())==CH_TXT_ATR_FORMELEMENT )
895cdf0e10cSrcweir                     pPor = new SwFieldFormPortion();
896cdf0e10cSrcweir             }
897cdf0e10cSrcweir             if( !pPor )
898cdf0e10cSrcweir             {
899cdf0e10cSrcweir                 if( !rInf.X() && !pCurr->GetPortion() && !pCurr->GetLen() && !GetFnt()->IsURL() )
900cdf0e10cSrcweir                     pPor = pCurr;
901cdf0e10cSrcweir                 else
902cdf0e10cSrcweir                 {
903cdf0e10cSrcweir                     pPor = new SwTxtPortion;
904cdf0e10cSrcweir                     if ( GetFnt()->IsURL() )
905*69a74367SOliver-Rainer Wittmann                     {
906cdf0e10cSrcweir                         pPor->SetWhichPor( POR_URL );
907cdf0e10cSrcweir                     }
908cdf0e10cSrcweir                 }
909cdf0e10cSrcweir             }
910cdf0e10cSrcweir 		}
911*69a74367SOliver-Rainer Wittmann 	}
912cdf0e10cSrcweir 	return pPor;
913cdf0e10cSrcweir }
914cdf0e10cSrcweir 
915cdf0e10cSrcweir /*************************************************************************
916cdf0e10cSrcweir  *						SwTxtFormatter::NewTxtPortion()
917cdf0e10cSrcweir  *************************************************************************/
918cdf0e10cSrcweir // Die Laenge wird ermittelt, folgende Portion-Grenzen sind definiert:
919cdf0e10cSrcweir // 1) Tabs
920cdf0e10cSrcweir // 2) Linebreaks
921cdf0e10cSrcweir // 3) CH_TXTATR_BREAKWORD / CH_TXTATR_INWORD
922cdf0e10cSrcweir // 4) naechster Attributwechsel
923cdf0e10cSrcweir 
NewTxtPortion(SwTxtFormatInfo & rInf)924cdf0e10cSrcweir SwTxtPortion *SwTxtFormatter::NewTxtPortion( SwTxtFormatInfo &rInf )
925cdf0e10cSrcweir {
926cdf0e10cSrcweir 	// Wenn wir am Zeilenbeginn stehen, nehmen wir pCurr
927cdf0e10cSrcweir 	// Wenn pCurr nicht von SwTxtPortion abgeleitet ist,
928cdf0e10cSrcweir 	// muessen wir duplizieren ...
929cdf0e10cSrcweir 	Seek( rInf.GetIdx() );
930cdf0e10cSrcweir 	SwTxtPortion *pPor = WhichTxtPor( rInf );
931cdf0e10cSrcweir 
932cdf0e10cSrcweir 	// until next attribute change:
933cdf0e10cSrcweir     const xub_StrLen nNextAttr = GetNextAttr();
934cdf0e10cSrcweir 	xub_StrLen nNextChg = Min( nNextAttr, rInf.GetTxt().Len() );
935cdf0e10cSrcweir 
936cdf0e10cSrcweir 	// end of script type:
937cdf0e10cSrcweir 	const xub_StrLen nNextScript = pScriptInfo->NextScriptChg( rInf.GetIdx() );
938cdf0e10cSrcweir 	nNextChg = Min( nNextChg, nNextScript );
939cdf0e10cSrcweir 
940cdf0e10cSrcweir 	// end of direction:
941cdf0e10cSrcweir     const xub_StrLen nNextDir = pScriptInfo->NextDirChg( rInf.GetIdx() );
942cdf0e10cSrcweir 	nNextChg = Min( nNextChg, nNextDir );
943cdf0e10cSrcweir 
944cdf0e10cSrcweir     // 7515, 7516, 3470, 6441 : Turbo-Boost
945cdf0e10cSrcweir 	// Es wird unterstellt, dass die Buchstaben eines Fonts nicht
946cdf0e10cSrcweir 	// groesser als doppelt so breit wie hoch sind.
947cdf0e10cSrcweir 	// 7659: Ganz verrueckt: man muss sich auf den Ascent beziehen.
948cdf0e10cSrcweir 	// Falle: GetSize() enthaelt die Wunschhoehe, die reale Hoehe
949cdf0e10cSrcweir 	// ergibt sich erst im CalcAscent!
950cdf0e10cSrcweir 	// 7697: Das Verhaeltnis ist noch krasser: ein Blank im Times
951cdf0e10cSrcweir 	// New Roman besitzt einen Ascent von 182, eine Hoehe von 200
952cdf0e10cSrcweir 	// und eine Breite von 53! Daraus folgt, dass eine Zeile mit
953cdf0e10cSrcweir 	// vielen Blanks falsch eingeschaetzt wird. Wir erhoehen von
954cdf0e10cSrcweir 	// Faktor 2 auf 8 (wg. negativen Kernings).
955cdf0e10cSrcweir 
956cdf0e10cSrcweir 	pPor->SetLen(1);
957cdf0e10cSrcweir 	CalcAscent( rInf, pPor );
958cdf0e10cSrcweir 
959cdf0e10cSrcweir     const SwFont* pTmpFnt = rInf.GetFont();
960cdf0e10cSrcweir     KSHORT nExpect = Min( KSHORT( ((Font *)pTmpFnt)->GetSize().Height() ),
961cdf0e10cSrcweir 						  KSHORT( pPor->GetAscent() ) ) / 8;
962cdf0e10cSrcweir 	if ( !nExpect )
963cdf0e10cSrcweir 		nExpect = 1;
964cdf0e10cSrcweir     nExpect = (sal_uInt16)(rInf.GetIdx() + ((rInf.Width() - rInf.X()) / nExpect));
965cdf0e10cSrcweir 	if( nExpect > rInf.GetIdx() && nNextChg > nExpect )
966cdf0e10cSrcweir 		nNextChg = Min( nExpect, rInf.GetTxt().Len() );
967cdf0e10cSrcweir 
968cdf0e10cSrcweir 	// we keep an invariant during method calls:
969cdf0e10cSrcweir 	// there are no portion ending characters like hard spaces
970cdf0e10cSrcweir 	// or tabs in [ nLeftScanIdx, nRightScanIdx ]
971cdf0e10cSrcweir     if ( nLeftScanIdx <= rInf.GetIdx() && rInf.GetIdx() <= nRightScanIdx )
972cdf0e10cSrcweir 	{
973cdf0e10cSrcweir 		if ( nNextChg > nRightScanIdx )
974cdf0e10cSrcweir             nNextChg = nRightScanIdx =
975cdf0e10cSrcweir                 rInf.ScanPortionEnd( nRightScanIdx, nNextChg );
976cdf0e10cSrcweir 	}
977cdf0e10cSrcweir 	else
978cdf0e10cSrcweir 	{
979cdf0e10cSrcweir 		nLeftScanIdx = rInf.GetIdx();
980cdf0e10cSrcweir         nNextChg = nRightScanIdx =
981cdf0e10cSrcweir                 rInf.ScanPortionEnd( rInf.GetIdx(), nNextChg );
982cdf0e10cSrcweir 	}
983cdf0e10cSrcweir 
984cdf0e10cSrcweir 	pPor->SetLen( nNextChg - rInf.GetIdx() );
985cdf0e10cSrcweir 	rInf.SetLen( pPor->GetLen() );
986cdf0e10cSrcweir 	return pPor;
987cdf0e10cSrcweir }
988cdf0e10cSrcweir 
989cdf0e10cSrcweir 
990cdf0e10cSrcweir /*************************************************************************
991cdf0e10cSrcweir  *				   SwTxtFormatter::WhichFirstPortion()
992cdf0e10cSrcweir  *************************************************************************/
993cdf0e10cSrcweir 
WhichFirstPortion(SwTxtFormatInfo & rInf)994cdf0e10cSrcweir SwLinePortion *SwTxtFormatter::WhichFirstPortion(SwTxtFormatInfo &rInf)
995cdf0e10cSrcweir {
996cdf0e10cSrcweir 	SwLinePortion *pPor = 0;
997cdf0e10cSrcweir 
998cdf0e10cSrcweir 	if( rInf.GetRest() )
999cdf0e10cSrcweir 	{
1000cdf0e10cSrcweir 		// 5010: Tabs und Felder
1001cdf0e10cSrcweir 		if( '\0' != rInf.GetHookChar() )
1002cdf0e10cSrcweir 			return 0;
1003cdf0e10cSrcweir 
1004cdf0e10cSrcweir 		pPor = rInf.GetRest();
1005cdf0e10cSrcweir 		if( pPor->IsErgoSumPortion() )
1006cdf0e10cSrcweir 			rInf.SetErgoDone(sal_True);
1007cdf0e10cSrcweir 		else
1008cdf0e10cSrcweir 			if( pPor->IsFtnNumPortion() )
1009cdf0e10cSrcweir 				rInf.SetFtnDone(sal_True);
1010cdf0e10cSrcweir 			else
1011cdf0e10cSrcweir 				if( pPor->InNumberGrp() )
1012cdf0e10cSrcweir 					rInf.SetNumDone(sal_True);
1013cdf0e10cSrcweir 		if( pPor )
1014cdf0e10cSrcweir 		{
1015cdf0e10cSrcweir 			rInf.SetRest(0);
1016cdf0e10cSrcweir 			pCurr->SetRest( sal_True );
1017cdf0e10cSrcweir 			return pPor;
1018cdf0e10cSrcweir 		}
1019cdf0e10cSrcweir 	}
1020cdf0e10cSrcweir 
1021cdf0e10cSrcweir 	// ???? und ????: im Follow duerfen wir schon stehen,
1022cdf0e10cSrcweir 	// entscheidend ist, ob pFrm->GetOfst() == 0 ist!
1023cdf0e10cSrcweir 	if( rInf.GetIdx() )
1024cdf0e10cSrcweir 	{
1025cdf0e10cSrcweir 		// Nun koennen auch FtnPortions und ErgoSumPortions
1026cdf0e10cSrcweir 		// verlaengert werden.
1027cdf0e10cSrcweir 
1028cdf0e10cSrcweir 		// 1) Die ErgoSumTexte
1029cdf0e10cSrcweir 		if( !rInf.IsErgoDone() )
1030cdf0e10cSrcweir 		{
1031cdf0e10cSrcweir 			if( pFrm->IsInFtn() && !pFrm->GetIndPrev() )
1032cdf0e10cSrcweir 				pPor = (SwLinePortion*)NewErgoSumPortion( rInf );
1033cdf0e10cSrcweir 			rInf.SetErgoDone( sal_True );
1034cdf0e10cSrcweir 		}
1035cdf0e10cSrcweir 
1036cdf0e10cSrcweir         // 2) Arrow portions
1037cdf0e10cSrcweir 		if( !pPor && !rInf.IsArrowDone() )
1038cdf0e10cSrcweir 		{
1039cdf0e10cSrcweir 			if( pFrm->GetOfst() && !pFrm->IsFollow() &&
1040cdf0e10cSrcweir 				rInf.GetIdx() == pFrm->GetOfst() )
1041cdf0e10cSrcweir 				pPor = new SwArrowPortion( *pCurr );
1042cdf0e10cSrcweir 			rInf.SetArrowDone( sal_True );
1043cdf0e10cSrcweir 		}
1044cdf0e10cSrcweir 
1045cdf0e10cSrcweir         // 3) Kerning portions at beginning of line in grid mode
1046cdf0e10cSrcweir         if ( ! pPor && ! pCurr->GetPortion() )
1047cdf0e10cSrcweir         {
1048cdf0e10cSrcweir             GETGRID( GetTxtFrm()->FindPageFrm() )
1049cdf0e10cSrcweir             if ( pGrid )
1050cdf0e10cSrcweir                 pPor = new SwKernPortion( *pCurr );
1051cdf0e10cSrcweir         }
1052cdf0e10cSrcweir 
1053cdf0e10cSrcweir 		// 4) Die Zeilenreste (mehrzeilige Felder)
1054cdf0e10cSrcweir 		if( !pPor )
1055cdf0e10cSrcweir 		{
1056cdf0e10cSrcweir 			pPor = rInf.GetRest();
1057cdf0e10cSrcweir 			// 6922: Nur bei pPor natuerlich.
1058cdf0e10cSrcweir 			if( pPor )
1059cdf0e10cSrcweir 			{
1060cdf0e10cSrcweir 				pCurr->SetRest( sal_True );
1061cdf0e10cSrcweir 				rInf.SetRest(0);
1062cdf0e10cSrcweir 			}
1063cdf0e10cSrcweir 		}
1064cdf0e10cSrcweir 	}
1065cdf0e10cSrcweir     else
1066cdf0e10cSrcweir 	{
1067cdf0e10cSrcweir 		// 5) Die Fussnotenzahlen
1068cdf0e10cSrcweir         if( !rInf.IsFtnDone() )
1069cdf0e10cSrcweir 		{
1070cdf0e10cSrcweir             ASSERT( ( ! rInf.IsMulti() && ! pMulti ) || pMulti->HasRotation(),
1071cdf0e10cSrcweir                      "Rotated number portion trouble" )
1072cdf0e10cSrcweir 
1073cdf0e10cSrcweir             sal_Bool bFtnNum = pFrm->IsFtnNumFrm();
1074cdf0e10cSrcweir 			rInf.GetParaPortion()->SetFtnNum( bFtnNum );
1075cdf0e10cSrcweir 			if( bFtnNum )
1076cdf0e10cSrcweir 				pPor = (SwLinePortion*)NewFtnNumPortion( rInf );
1077cdf0e10cSrcweir             rInf.SetFtnDone( sal_True );
1078cdf0e10cSrcweir 		}
1079cdf0e10cSrcweir 
1080cdf0e10cSrcweir 		// 6) Die ErgoSumTexte gibt es natuerlich auch im TextMaster,
1081cdf0e10cSrcweir 		// entscheidend ist, ob der SwFtnFrm ein Follow ist.
1082cdf0e10cSrcweir         if( !rInf.IsErgoDone() && !pPor && ! rInf.IsMulti() )
1083cdf0e10cSrcweir 		{
1084cdf0e10cSrcweir 			if( pFrm->IsInFtn() && !pFrm->GetIndPrev() )
1085cdf0e10cSrcweir 				pPor = (SwLinePortion*)NewErgoSumPortion( rInf );
1086cdf0e10cSrcweir 			rInf.SetErgoDone( sal_True );
1087cdf0e10cSrcweir 		}
1088cdf0e10cSrcweir 
1089cdf0e10cSrcweir 		// 7) Die Numerierungen
1090cdf0e10cSrcweir 		if( !rInf.IsNumDone() && !pPor )
1091cdf0e10cSrcweir 		{
1092cdf0e10cSrcweir             ASSERT( ( ! rInf.IsMulti() && ! pMulti ) || pMulti->HasRotation(),
1093cdf0e10cSrcweir                      "Rotated number portion trouble" )
1094cdf0e10cSrcweir 
1095cdf0e10cSrcweir 			// Wenn wir im Follow stehen, dann natuerlich nicht.
1096cdf0e10cSrcweir 			if( GetTxtFrm()->GetTxtNode()->GetNumRule() )
1097cdf0e10cSrcweir                 pPor = (SwLinePortion*)NewNumberPortion( rInf );
1098cdf0e10cSrcweir 			rInf.SetNumDone( sal_True );
1099cdf0e10cSrcweir 		}
1100cdf0e10cSrcweir         // 8) Die DropCaps
1101cdf0e10cSrcweir         if( !pPor && GetDropFmt() && ! rInf.IsMulti() )
1102cdf0e10cSrcweir 			pPor = (SwLinePortion*)NewDropPortion( rInf );
1103cdf0e10cSrcweir 
1104cdf0e10cSrcweir         // 9) Kerning portions at beginning of line in grid mode
1105cdf0e10cSrcweir         if ( !pPor && !pCurr->GetPortion() )
1106cdf0e10cSrcweir         {
1107cdf0e10cSrcweir             GETGRID( GetTxtFrm()->FindPageFrm() )
1108cdf0e10cSrcweir             if ( pGrid )
1109cdf0e10cSrcweir                 pPor = new SwKernPortion( *pCurr );
1110cdf0e10cSrcweir         }
1111cdf0e10cSrcweir     }
1112cdf0e10cSrcweir 
1113cdf0e10cSrcweir         // 10) Decimal tab portion at the beginning of each line in table cells
1114cdf0e10cSrcweir         if ( !pPor && !pCurr->GetPortion() &&
1115cdf0e10cSrcweir              GetTxtFrm()->IsInTab() &&
1116cdf0e10cSrcweir              GetTxtFrm()->GetTxtNode()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::TAB_COMPAT) )
1117cdf0e10cSrcweir         {
1118cdf0e10cSrcweir             pPor = NewTabPortion( rInf, true );
1119cdf0e10cSrcweir         }
1120cdf0e10cSrcweir 
1121cdf0e10cSrcweir         // 11) suffix of meta-field
1122cdf0e10cSrcweir         if (!pPor)
1123cdf0e10cSrcweir         {
1124cdf0e10cSrcweir             pPor = TryNewNoLengthPortion(rInf);
1125cdf0e10cSrcweir         }
1126cdf0e10cSrcweir 
1127cdf0e10cSrcweir 	return pPor;
1128cdf0e10cSrcweir }
1129cdf0e10cSrcweir 
lcl_OldFieldRest(const SwLineLayout * pCurr)1130cdf0e10cSrcweir sal_Bool lcl_OldFieldRest( const SwLineLayout* pCurr )
1131cdf0e10cSrcweir {
1132cdf0e10cSrcweir 	if( !pCurr->GetNext() )
1133cdf0e10cSrcweir 		return sal_False;
1134cdf0e10cSrcweir 	const SwLinePortion *pPor = pCurr->GetNext()->GetPortion();
1135cdf0e10cSrcweir 	sal_Bool bRet = sal_False;
1136cdf0e10cSrcweir 	while( pPor && !bRet )
1137cdf0e10cSrcweir 	{
1138cdf0e10cSrcweir 		bRet = (pPor->InFldGrp() && ((SwFldPortion*)pPor)->IsFollow()) ||
1139cdf0e10cSrcweir 			(pPor->IsMultiPortion() && ((SwMultiPortion*)pPor)->IsFollowFld());
1140cdf0e10cSrcweir 		if( !pPor->GetLen() )
1141cdf0e10cSrcweir 			break;
1142cdf0e10cSrcweir 		pPor = pPor->GetPortion();
1143cdf0e10cSrcweir 	}
1144cdf0e10cSrcweir 	return bRet;
1145cdf0e10cSrcweir }
1146cdf0e10cSrcweir 
1147cdf0e10cSrcweir /*************************************************************************
1148cdf0e10cSrcweir  *						SwTxtFormatter::NewPortion()
1149cdf0e10cSrcweir  *************************************************************************/
1150cdf0e10cSrcweir 
1151cdf0e10cSrcweir /* NewPortion stellt rInf.nLen ein.
1152cdf0e10cSrcweir  * Eine SwTxtPortion wird begrenzt durch ein tab, break, txtatr,
1153cdf0e10cSrcweir  * attrwechsel.
1154cdf0e10cSrcweir  * Drei Faelle koennen eintreten:
1155cdf0e10cSrcweir  * 1) Die Zeile ist voll und der Umbruch wurde nicht emuliert
1156cdf0e10cSrcweir  *	  -> return 0;
1157cdf0e10cSrcweir  * 2) Die Zeile ist voll und es wurde ein Umbruch emuliert
1158cdf0e10cSrcweir  *	  -> Breite neu einstellen und return new FlyPortion
1159cdf0e10cSrcweir  * 3) Es muss eine neue Portion gebaut werden.
1160cdf0e10cSrcweir  *	  -> CalcFlyWidth emuliert ggf. die Breite und return Portion
1161cdf0e10cSrcweir  */
1162cdf0e10cSrcweir 
NewPortion(SwTxtFormatInfo & rInf)1163cdf0e10cSrcweir SwLinePortion *SwTxtFormatter::NewPortion( SwTxtFormatInfo &rInf )
1164cdf0e10cSrcweir {
1165cdf0e10cSrcweir 	// Underflow hat Vorrang
1166cdf0e10cSrcweir 	rInf.SetStopUnderFlow( sal_False );
1167cdf0e10cSrcweir 	if( rInf.GetUnderFlow() )
1168cdf0e10cSrcweir 	{
1169cdf0e10cSrcweir 		ASSERT( rInf.IsFull(), "SwTxtFormatter::NewPortion: underflow but not full" );
1170cdf0e10cSrcweir 		return UnderFlow( rInf );
1171cdf0e10cSrcweir 	}
1172cdf0e10cSrcweir 
1173cdf0e10cSrcweir 	// Wenn die Zeile voll ist, koennten noch Flys oder
1174cdf0e10cSrcweir 	// UnderFlow-LinePortions warten ...
1175cdf0e10cSrcweir 	if( rInf.IsFull() )
1176cdf0e10cSrcweir 	{
1177cdf0e10cSrcweir 		// ????: LineBreaks und Flys (bug05.sdw)
1178cdf0e10cSrcweir 		// 8450: IsDummy()
1179cdf0e10cSrcweir 		if( rInf.IsNewLine() && (!rInf.GetFly() || !pCurr->IsDummy()) )
1180cdf0e10cSrcweir 			return 0;
1181cdf0e10cSrcweir 
1182cdf0e10cSrcweir 		// Wenn der Text an den Fly gestossen ist, oder wenn
1183cdf0e10cSrcweir 		// der Fly als erstes drankommt, weil er ueber dem linken
1184cdf0e10cSrcweir 		// Rand haengt, wird GetFly() returnt.
1185cdf0e10cSrcweir 		// Wenn IsFull() und kein GetFly() vorhanden ist, gibt's
1186cdf0e10cSrcweir 		// naturgemaesz eine 0.
1187cdf0e10cSrcweir 		if( rInf.GetFly() )
1188cdf0e10cSrcweir 		{
1189cdf0e10cSrcweir             if( rInf.GetLast()->IsBreakPortion() )
1190cdf0e10cSrcweir             {
1191cdf0e10cSrcweir                 delete rInf.GetFly();
1192cdf0e10cSrcweir                 rInf.SetFly( 0 );
1193cdf0e10cSrcweir             }
1194cdf0e10cSrcweir 
1195cdf0e10cSrcweir             return rInf.GetFly();
1196cdf0e10cSrcweir 		}
1197cdf0e10cSrcweir 		// Ein fieser Sonderfall: ein Rahmen ohne Umlauf kreuzt den
1198cdf0e10cSrcweir 		// Ftn-Bereich. Wir muessen die Ftn-Portion als Zeilenrest
1199cdf0e10cSrcweir 		// bekanntgeben, damit SwTxtFrm::Format nicht abbricht
1200cdf0e10cSrcweir 		// (die Textmasse wurde ja durchformatiert).
1201cdf0e10cSrcweir 		if( rInf.GetRest() )
1202cdf0e10cSrcweir 			rInf.SetNewLine( sal_True );
1203cdf0e10cSrcweir 		else
1204cdf0e10cSrcweir 		{
1205cdf0e10cSrcweir 			// Wenn die naechste Zeile mit einem Rest eines Feldes beginnt,
1206cdf0e10cSrcweir 			// jetzt aber kein Rest mehr anliegt,
1207cdf0e10cSrcweir 			// muss sie auf jeden Fall neu formatiert werden!
1208cdf0e10cSrcweir 			if( lcl_OldFieldRest( GetCurr() ) )
1209cdf0e10cSrcweir 				rInf.SetNewLine( sal_True );
1210cdf0e10cSrcweir 			else
1211cdf0e10cSrcweir 			{
1212cdf0e10cSrcweir 				SwLinePortion *pFirst = WhichFirstPortion( rInf );
1213cdf0e10cSrcweir 				if( pFirst )
1214cdf0e10cSrcweir 				{
1215cdf0e10cSrcweir 					rInf.SetNewLine( sal_True );
1216cdf0e10cSrcweir 					if( pFirst->InNumberGrp() )
1217cdf0e10cSrcweir 						rInf.SetNumDone( sal_False) ;
1218cdf0e10cSrcweir 					delete pFirst;
1219cdf0e10cSrcweir 				}
1220cdf0e10cSrcweir 			}
1221cdf0e10cSrcweir 		}
1222cdf0e10cSrcweir 
1223cdf0e10cSrcweir 		return 0;
1224cdf0e10cSrcweir 	}
1225cdf0e10cSrcweir 
1226cdf0e10cSrcweir 	SwLinePortion *pPor = WhichFirstPortion( rInf );
1227cdf0e10cSrcweir 
1228cdf0e10cSrcweir     // Check for Hidden Portion:
1229cdf0e10cSrcweir     if ( !pPor )
1230cdf0e10cSrcweir     {
1231cdf0e10cSrcweir     	xub_StrLen nEnd = rInf.GetIdx();
1232cdf0e10cSrcweir         if ( lcl_BuildHiddenPortion( rInf, nEnd ) )
1233cdf0e10cSrcweir             pPor = new SwHiddenTextPortion( nEnd - rInf.GetIdx() );
1234cdf0e10cSrcweir     }
1235cdf0e10cSrcweir 
1236cdf0e10cSrcweir 	if( !pPor )
1237cdf0e10cSrcweir 	{
1238cdf0e10cSrcweir         if( ( !pMulti || pMulti->IsBidi() ) &&
1239cdf0e10cSrcweir             // --> FME 2005-02-14 #i42734#
1240cdf0e10cSrcweir             // No multi portion if there is a hook character waiting:
1241cdf0e10cSrcweir             ( !rInf.GetRest() || '\0' == rInf.GetHookChar() ) )
1242cdf0e10cSrcweir             // <--
1243cdf0e10cSrcweir         {
1244cdf0e10cSrcweir             // We open a multiportion part, if we enter a multi-line part
1245cdf0e10cSrcweir 			// of the paragraph.
1246cdf0e10cSrcweir         	xub_StrLen nEnd = rInf.GetIdx();
1247cdf0e10cSrcweir             SwMultiCreator* pCreate = rInf.GetMultiCreator( nEnd, pMulti );
1248cdf0e10cSrcweir 			if( pCreate )
1249cdf0e10cSrcweir 			{
1250cdf0e10cSrcweir 				SwMultiPortion* pTmp = NULL;
1251cdf0e10cSrcweir 
1252cdf0e10cSrcweir                 if ( SW_MC_BIDI == pCreate->nId )
1253cdf0e10cSrcweir                     pTmp = new SwBidiPortion( nEnd, pCreate->nLevel );
1254cdf0e10cSrcweir                 else if ( SW_MC_RUBY == pCreate->nId )
1255cdf0e10cSrcweir                 {
1256cdf0e10cSrcweir                     Seek( rInf.GetIdx() );
1257cdf0e10cSrcweir                     sal_Bool bRubyTop;
1258cdf0e10cSrcweir                     sal_Bool* pRubyPos = 0;
1259cdf0e10cSrcweir 
1260cdf0e10cSrcweir                     if ( rInf.SnapToGrid() )
1261cdf0e10cSrcweir                     {
1262cdf0e10cSrcweir                         GETGRID( GetTxtFrm()->FindPageFrm() )
1263cdf0e10cSrcweir                         if ( pGrid )
1264cdf0e10cSrcweir                         {
1265cdf0e10cSrcweir                             bRubyTop = ! pGrid->GetRubyTextBelow();
1266cdf0e10cSrcweir                             pRubyPos = &bRubyTop;
1267cdf0e10cSrcweir                         }
1268cdf0e10cSrcweir                     }
1269cdf0e10cSrcweir 
1270cdf0e10cSrcweir                     pTmp = new SwRubyPortion( *pCreate, *rInf.GetFont(),
1271cdf0e10cSrcweir                                               *GetTxtFrm()->GetTxtNode()->getIDocumentSettingAccess(),
1272cdf0e10cSrcweir                                               nEnd, 0, pRubyPos );
1273cdf0e10cSrcweir                 }
1274cdf0e10cSrcweir 				else if( SW_MC_ROTATE == pCreate->nId )
1275cdf0e10cSrcweir                     pTmp = new SwRotatedPortion( *pCreate, nEnd,
1276cdf0e10cSrcweir                                                  GetTxtFrm()->IsRightToLeft() );
1277cdf0e10cSrcweir 				else
1278cdf0e10cSrcweir 					pTmp = new SwDoubleLinePortion( *pCreate, nEnd );
1279cdf0e10cSrcweir 
1280cdf0e10cSrcweir                 delete pCreate;
1281cdf0e10cSrcweir                 CalcFlyWidth( rInf );
1282cdf0e10cSrcweir 
1283cdf0e10cSrcweir 				return pTmp;
1284cdf0e10cSrcweir 			}
1285cdf0e10cSrcweir 		}
1286cdf0e10cSrcweir 		// 5010: Tabs und Felder
1287cdf0e10cSrcweir 		xub_Unicode cChar = rInf.GetHookChar();
1288cdf0e10cSrcweir 
1289cdf0e10cSrcweir 		if( cChar )
1290cdf0e10cSrcweir 		{
1291cdf0e10cSrcweir 			/* Wir holen uns nocheinmal cChar, um sicherzustellen, dass das
1292cdf0e10cSrcweir 			 * Tab jetzt wirklich ansteht und nicht auf die naechste Zeile
1293cdf0e10cSrcweir 			 * gewandert ist ( so geschehen hinter Rahmen ).
1294cdf0e10cSrcweir 			 * Wenn allerdings eine FldPortion im Rest wartet, muessen wir
1295cdf0e10cSrcweir 			 * das cChar natuerlich aus dem Feldinhalt holen, z.B. bei
1296cdf0e10cSrcweir 			 * DezimalTabs und Feldern (22615)
1297cdf0e10cSrcweir 			*/
1298cdf0e10cSrcweir 			if( !rInf.GetRest() || !rInf.GetRest()->InFldGrp() )
1299cdf0e10cSrcweir 				cChar = rInf.GetChar( rInf.GetIdx() );
1300cdf0e10cSrcweir 		    rInf.ClearHookChar();
1301cdf0e10cSrcweir 		}
1302cdf0e10cSrcweir 		else
1303cdf0e10cSrcweir 		{
1304cdf0e10cSrcweir 			if( rInf.GetIdx() >= rInf.GetTxt().Len() )
1305cdf0e10cSrcweir 			{
1306cdf0e10cSrcweir 				rInf.SetFull(sal_True);
1307cdf0e10cSrcweir                 CalcFlyWidth( rInf );
1308cdf0e10cSrcweir 				return pPor;
1309cdf0e10cSrcweir 			}
1310cdf0e10cSrcweir 			cChar = rInf.GetChar( rInf.GetIdx() );
1311cdf0e10cSrcweir 		}
1312cdf0e10cSrcweir 
1313cdf0e10cSrcweir         switch( cChar )
1314cdf0e10cSrcweir         {
1315cdf0e10cSrcweir             case CH_TAB:
1316cdf0e10cSrcweir                 pPor = NewTabPortion( rInf, false ); break;
1317cdf0e10cSrcweir 
1318cdf0e10cSrcweir             case CH_BREAK:
1319cdf0e10cSrcweir                 pPor = new SwBreakPortion( *rInf.GetLast() ); break;
1320cdf0e10cSrcweir 
1321cdf0e10cSrcweir             case CHAR_SOFTHYPHEN:					// soft hyphen
1322cdf0e10cSrcweir                 pPor = new SwSoftHyphPortion; break;
1323cdf0e10cSrcweir 
1324cdf0e10cSrcweir             case CHAR_HARDBLANK:					// no-break space
1325cdf0e10cSrcweir                 pPor = new SwBlankPortion( ' ' ); break;
1326cdf0e10cSrcweir 
1327cdf0e10cSrcweir             case CHAR_HARDHYPHEN:               // non-breaking hyphen
1328cdf0e10cSrcweir                 pPor = new SwBlankPortion( '-' ); break;
1329cdf0e10cSrcweir 
1330cdf0e10cSrcweir             case CHAR_ZWSP:                     // zero width space
1331cdf0e10cSrcweir             case CHAR_ZWNBSP :                  // word joiner
1332cdf0e10cSrcweir                 pPor = new SwControlCharPortion( cChar ); break;
1333cdf0e10cSrcweir 
1334cdf0e10cSrcweir             case CH_TXTATR_BREAKWORD:
1335cdf0e10cSrcweir             case CH_TXTATR_INWORD:
1336cdf0e10cSrcweir                 if( rInf.HasHint( rInf.GetIdx() ) )
1337cdf0e10cSrcweir                 {
1338cdf0e10cSrcweir                     pPor = NewExtraPortion( rInf );
1339cdf0e10cSrcweir                     break;
1340cdf0e10cSrcweir                 }
1341cdf0e10cSrcweir                 // No break
1342cdf0e10cSrcweir             default 	   :
1343cdf0e10cSrcweir                 {
1344cdf0e10cSrcweir                 SwTabPortion* pLastTabPortion = rInf.GetLastTab();
1345cdf0e10cSrcweir                 if ( pLastTabPortion && cChar == rInf.GetTabDecimal() )
1346cdf0e10cSrcweir                 {
1347cdf0e10cSrcweir                     // --> FME 2005-12-19 #127428# Abandon dec. tab position if line is full:
1348cdf0e10cSrcweir                     // We have a decimal tab portion in the line and the next character has to be
1349cdf0e10cSrcweir                     // aligned at the tab stop position. We store the width from the beginning of
1350cdf0e10cSrcweir                     // the tab stop portion up to the portion containint the decimal separator:
1351cdf0e10cSrcweir 				  if ( GetTxtFrm()->GetTxtNode()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::TAB_COMPAT) /*rInf.GetVsh()->IsTabCompat();*/ &&
1352cdf0e10cSrcweir 						 POR_TABDECIMAL == pLastTabPortion->GetWhichPor() )
1353cdf0e10cSrcweir                     {
1354cdf0e10cSrcweir                         ASSERT( rInf.X() >= pLastTabPortion->Fix(), "Decimal tab stop position cannot be calculated" )
1355cdf0e10cSrcweir                         const sal_uInt16 nWidthOfPortionsUpToDecimalPosition = (sal_uInt16)(rInf.X() - pLastTabPortion->Fix() );
1356cdf0e10cSrcweir                         static_cast<SwTabDecimalPortion*>(pLastTabPortion)->SetWidthOfPortionsUpToDecimalPosition( nWidthOfPortionsUpToDecimalPosition );
1357cdf0e10cSrcweir                         rInf.SetTabDecimal( 0 );
1358cdf0e10cSrcweir                     }
1359cdf0e10cSrcweir                     // <--
1360cdf0e10cSrcweir                     else
1361cdf0e10cSrcweir                         rInf.SetFull( rInf.GetLastTab()->Format( rInf ) );
1362cdf0e10cSrcweir                 }
1363cdf0e10cSrcweir 
1364cdf0e10cSrcweir 				if( rInf.GetRest() )
1365cdf0e10cSrcweir 				{
1366cdf0e10cSrcweir 					if( rInf.IsFull() )
1367cdf0e10cSrcweir 					{
1368cdf0e10cSrcweir 						rInf.SetNewLine(sal_True);
1369cdf0e10cSrcweir 						return 0;
1370cdf0e10cSrcweir 					}
1371cdf0e10cSrcweir 					pPor = rInf.GetRest();
1372cdf0e10cSrcweir 					rInf.SetRest(0);
1373cdf0e10cSrcweir 				}
1374cdf0e10cSrcweir 				else
1375cdf0e10cSrcweir 				{
1376cdf0e10cSrcweir 					if( rInf.IsFull() )
1377cdf0e10cSrcweir 						return 0;
1378cdf0e10cSrcweir 					pPor = NewTxtPortion( rInf );
1379cdf0e10cSrcweir 				}
1380cdf0e10cSrcweir 				break;
1381cdf0e10cSrcweir 			}
1382cdf0e10cSrcweir 		}
1383cdf0e10cSrcweir 
1384cdf0e10cSrcweir 		// Wenn eine Portion erzeugt wird, obwohl eine RestPortion ansteht,
1385cdf0e10cSrcweir 		// dann haben wir es mit einem Feld zu tun, das sich aufgesplittet
1386cdf0e10cSrcweir 		// hat, weil z.B. ein Tab enthalten ist.
1387cdf0e10cSrcweir 		if( pPor && rInf.GetRest() )
1388cdf0e10cSrcweir 			pPor->SetLen( 0 );
1389cdf0e10cSrcweir 
1390cdf0e10cSrcweir 		// robust:
1391cdf0e10cSrcweir 		if( !pPor || rInf.IsStop() )
1392cdf0e10cSrcweir 		{
1393cdf0e10cSrcweir 			delete pPor;
1394cdf0e10cSrcweir 			return 0;
1395cdf0e10cSrcweir 		}
1396cdf0e10cSrcweir 	}
1397cdf0e10cSrcweir 
1398cdf0e10cSrcweir     // Special portions containing numbers (footnote anchor, footnote number,
1399cdf0e10cSrcweir     // numbering) can be contained in a rotated portion, if the user
1400cdf0e10cSrcweir     // choose a rotated character attribute.
1401cdf0e10cSrcweir     if ( pPor && ! pMulti )
1402cdf0e10cSrcweir     {
1403cdf0e10cSrcweir         if ( pPor->IsFtnPortion() )
1404cdf0e10cSrcweir         {
1405cdf0e10cSrcweir             const SwTxtFtn* pTxtFtn = ((SwFtnPortion*)pPor)->GetTxtFtn();
1406cdf0e10cSrcweir 
1407cdf0e10cSrcweir             if ( pTxtFtn )
1408cdf0e10cSrcweir             {
1409cdf0e10cSrcweir                 SwFmtFtn& rFtn = (SwFmtFtn&)pTxtFtn->GetFtn();
1410cdf0e10cSrcweir                 const SwDoc *pDoc = rInf.GetTxtFrm()->GetNode()->GetDoc();
1411cdf0e10cSrcweir                 const SwEndNoteInfo* pInfo;
1412cdf0e10cSrcweir                 if( rFtn.IsEndNote() )
1413cdf0e10cSrcweir                     pInfo = &pDoc->GetEndNoteInfo();
1414cdf0e10cSrcweir                 else
1415cdf0e10cSrcweir                     pInfo = &pDoc->GetFtnInfo();
1416cdf0e10cSrcweir                 const SwAttrSet& rSet = pInfo->GetAnchorCharFmt((SwDoc&)*pDoc)->GetAttrSet();
1417cdf0e10cSrcweir 
1418cdf0e10cSrcweir                 const SfxPoolItem* pItem;
1419cdf0e10cSrcweir                 sal_uInt16 nDir = 0;
1420cdf0e10cSrcweir                 if( SFX_ITEM_SET == rSet.GetItemState( RES_CHRATR_ROTATE,
1421cdf0e10cSrcweir                     sal_True, &pItem ))
1422cdf0e10cSrcweir                     nDir = ((SvxCharRotateItem*)pItem)->GetValue();
1423cdf0e10cSrcweir 
1424cdf0e10cSrcweir                 if ( 0 != nDir )
1425cdf0e10cSrcweir                 {
1426cdf0e10cSrcweir                     delete pPor;
1427cdf0e10cSrcweir                     pPor = new SwRotatedPortion( rInf.GetIdx() + 1, 900 == nDir ?
1428cdf0e10cSrcweir                                                     DIR_BOTTOM2TOP :
1429cdf0e10cSrcweir                                                     DIR_TOP2BOTTOM );
1430cdf0e10cSrcweir                 }
1431cdf0e10cSrcweir             }
1432cdf0e10cSrcweir         }
1433cdf0e10cSrcweir         else if ( pPor->InNumberGrp() )
1434cdf0e10cSrcweir         {
1435cdf0e10cSrcweir             const SwFont* pNumFnt = ((SwFldPortion*)pPor)->GetFont();
1436cdf0e10cSrcweir 
1437cdf0e10cSrcweir             if ( pNumFnt )
1438cdf0e10cSrcweir             {
1439cdf0e10cSrcweir                 sal_uInt16 nDir = pNumFnt->GetOrientation( rInf.GetTxtFrm()->IsVertical() );
1440cdf0e10cSrcweir                 if ( 0 != nDir )
1441cdf0e10cSrcweir                 {
1442cdf0e10cSrcweir                     delete pPor;
1443cdf0e10cSrcweir                     pPor = new SwRotatedPortion( 0, 900 == nDir ?
1444cdf0e10cSrcweir                                                     DIR_BOTTOM2TOP :
1445cdf0e10cSrcweir                                                     DIR_TOP2BOTTOM );
1446cdf0e10cSrcweir 
1447cdf0e10cSrcweir                     rInf.SetNumDone( sal_False );
1448cdf0e10cSrcweir                     rInf.SetFtnDone( sal_False );
1449cdf0e10cSrcweir                 }
1450cdf0e10cSrcweir             }
1451cdf0e10cSrcweir         }
1452cdf0e10cSrcweir     }
1453cdf0e10cSrcweir 
1454cdf0e10cSrcweir     // Der Font wird im Outputdevice eingestellt,
1455cdf0e10cSrcweir 	// der Ascent und die Hoehe werden berechnet.
1456cdf0e10cSrcweir 	if( !pPor->GetAscent() && !pPor->Height() )
1457cdf0e10cSrcweir 		CalcAscent( rInf, pPor );
1458cdf0e10cSrcweir 	rInf.SetLen( pPor->GetLen() );
1459cdf0e10cSrcweir 
1460cdf0e10cSrcweir 	// In CalcFlyWidth wird Width() verkuerzt, wenn eine FlyPortion vorliegt.
1461cdf0e10cSrcweir     CalcFlyWidth( rInf );
1462cdf0e10cSrcweir 
1463cdf0e10cSrcweir 	// Man darf nicht vergessen, dass pCurr als GetLast() vernuenftige
1464cdf0e10cSrcweir 	// Werte bereithalten muss:
1465cdf0e10cSrcweir 	if( !pCurr->Height() )
1466cdf0e10cSrcweir 	{
1467cdf0e10cSrcweir 		ASSERT( pCurr->Height(), "SwTxtFormatter::NewPortion: limbo dance" );
1468cdf0e10cSrcweir 		pCurr->Height( pPor->Height() );
1469cdf0e10cSrcweir 		pCurr->SetAscent( pPor->GetAscent() );
1470cdf0e10cSrcweir 	}
1471cdf0e10cSrcweir 
1472cdf0e10cSrcweir 	ASSERT( !pPor || pPor->Height(),
1473cdf0e10cSrcweir 			"SwTxtFormatter::NewPortion: something went wrong");
1474cdf0e10cSrcweir 	if( pPor->IsPostItsPortion() && rInf.X() >= rInf.Width() && rInf.GetFly() )
1475cdf0e10cSrcweir 	{
1476cdf0e10cSrcweir 		delete pPor;
1477cdf0e10cSrcweir 		pPor = rInf.GetFly();
1478cdf0e10cSrcweir 	}
1479cdf0e10cSrcweir 	return pPor;
1480cdf0e10cSrcweir }
1481cdf0e10cSrcweir 
1482cdf0e10cSrcweir /*************************************************************************
1483cdf0e10cSrcweir  *						SwTxtFormatter::FormatLine()
1484cdf0e10cSrcweir  *************************************************************************/
1485cdf0e10cSrcweir 
FormatLine(const xub_StrLen nStartPos)1486cdf0e10cSrcweir xub_StrLen SwTxtFormatter::FormatLine( const xub_StrLen nStartPos )
1487cdf0e10cSrcweir {
1488cdf0e10cSrcweir     ASSERT( ! pFrm->IsVertical() || pFrm->IsSwapped(),
1489cdf0e10cSrcweir             "SwTxtFormatter::FormatLine( nStartPos ) with unswapped frame" );
1490cdf0e10cSrcweir 
1491cdf0e10cSrcweir     // For the formatting routines, we set pOut to the reference device.
1492cdf0e10cSrcweir     SwHookOut aHook( GetInfo() );
1493cdf0e10cSrcweir 	if( GetInfo().GetLen() < GetInfo().GetTxt().Len() )
1494cdf0e10cSrcweir 		GetInfo().SetLen( GetInfo().GetTxt().Len() );
1495cdf0e10cSrcweir 
1496cdf0e10cSrcweir 	sal_Bool bBuild = sal_True;
1497cdf0e10cSrcweir 	SetFlyInCntBase( sal_False );
1498cdf0e10cSrcweir 	GetInfo().SetLineHeight( 0 );
1499cdf0e10cSrcweir     GetInfo().SetLineNettoHeight( 0 );
1500cdf0e10cSrcweir 
1501cdf0e10cSrcweir 	// Recycling muss bei geaenderter Zeilenhoehe unterdrueckt werden
1502cdf0e10cSrcweir 	// und auch bei geaendertem Ascent (Absenken der Grundlinie).
1503cdf0e10cSrcweir 	const KSHORT nOldHeight = pCurr->Height();
1504cdf0e10cSrcweir 	const KSHORT nOldAscent = pCurr->GetAscent();
1505cdf0e10cSrcweir 
1506cdf0e10cSrcweir 	pCurr->SetEndHyph( sal_False );
1507cdf0e10cSrcweir 	pCurr->SetMidHyph( sal_False );
1508cdf0e10cSrcweir 
1509cdf0e10cSrcweir     // fly positioning can make it necessary format a line several times
1510cdf0e10cSrcweir     // for this, we have to keep a copy of our rest portion
1511cdf0e10cSrcweir     SwLinePortion* pFld = GetInfo().GetRest();
1512cdf0e10cSrcweir     SwFldPortion* pSaveFld = 0;
1513cdf0e10cSrcweir 
1514cdf0e10cSrcweir     if ( pFld && pFld->InFldGrp() && !pFld->IsFtnPortion() )
1515cdf0e10cSrcweir         pSaveFld = new SwFldPortion( *((SwFldPortion*)pFld) );
1516cdf0e10cSrcweir 
1517cdf0e10cSrcweir     // for an optimal repaint rectangle, we want to compare fly portions
1518cdf0e10cSrcweir     // before and after the BuildPortions call
1519cdf0e10cSrcweir     const sal_Bool bOptimizeRepaint = AllowRepaintOpt();
1520cdf0e10cSrcweir     const xub_StrLen nOldLineEnd = nStartPos + pCurr->GetLen();
1521cdf0e10cSrcweir     SvLongs* pFlyStart = 0;
1522cdf0e10cSrcweir 
1523cdf0e10cSrcweir     // these are the conditions for a fly position comparison
1524cdf0e10cSrcweir     if ( bOptimizeRepaint && pCurr->IsFly() )
1525cdf0e10cSrcweir     {
1526cdf0e10cSrcweir         pFlyStart = new SvLongs;
1527cdf0e10cSrcweir         SwLinePortion* pPor = pCurr->GetFirstPortion();
1528cdf0e10cSrcweir         long nPOfst = 0;
1529cdf0e10cSrcweir         sal_uInt16 nCnt = 0;
1530cdf0e10cSrcweir 
1531cdf0e10cSrcweir         while ( pPor )
1532cdf0e10cSrcweir         {
1533cdf0e10cSrcweir             if ( pPor->IsFlyPortion() )
1534cdf0e10cSrcweir                 // insert start value of fly portion
1535cdf0e10cSrcweir                 pFlyStart->Insert( nPOfst, nCnt++ );
1536cdf0e10cSrcweir 
1537cdf0e10cSrcweir             nPOfst += pPor->Width();
1538cdf0e10cSrcweir             pPor = pPor->GetPortion();
1539cdf0e10cSrcweir         }
1540cdf0e10cSrcweir     }
1541cdf0e10cSrcweir 
1542cdf0e10cSrcweir     // Hier folgt bald die Unterlaufpruefung.
1543cdf0e10cSrcweir 	while( bBuild )
1544cdf0e10cSrcweir 	{
1545cdf0e10cSrcweir 		GetInfo().SetFtnInside( sal_False );
1546cdf0e10cSrcweir         GetInfo().SetOtherThanFtnInside( sal_False );
1547cdf0e10cSrcweir 
1548cdf0e10cSrcweir 		// These values must not be reset by FormatReset();
1549cdf0e10cSrcweir 		sal_Bool bOldNumDone = GetInfo().IsNumDone();
1550cdf0e10cSrcweir 		sal_Bool bOldArrowDone = GetInfo().IsArrowDone();
1551cdf0e10cSrcweir 		sal_Bool bOldErgoDone = GetInfo().IsErgoDone();
1552cdf0e10cSrcweir 
1553cdf0e10cSrcweir         // besides other things, this sets the repaint offset to 0
1554cdf0e10cSrcweir         FormatReset( GetInfo() );
1555cdf0e10cSrcweir 
1556cdf0e10cSrcweir 		GetInfo().SetNumDone( bOldNumDone );
1557cdf0e10cSrcweir 		GetInfo().SetArrowDone( bOldArrowDone );
1558cdf0e10cSrcweir 		GetInfo().SetErgoDone( bOldErgoDone );
1559cdf0e10cSrcweir 
1560cdf0e10cSrcweir         // build new portions for this line
1561cdf0e10cSrcweir         BuildPortions( GetInfo() );
1562cdf0e10cSrcweir 
1563cdf0e10cSrcweir         if( GetInfo().IsStop() )
1564cdf0e10cSrcweir 		{
1565cdf0e10cSrcweir 			pCurr->SetLen( 0 );
1566cdf0e10cSrcweir 			pCurr->Height( GetFrmRstHeight() + 1 );
1567cdf0e10cSrcweir 			pCurr->SetRealHeight( GetFrmRstHeight() + 1 );
1568cdf0e10cSrcweir 			pCurr->Width(0);
1569cdf0e10cSrcweir 			pCurr->Truncate();
1570cdf0e10cSrcweir             return nStartPos;
1571cdf0e10cSrcweir 		}
1572cdf0e10cSrcweir 		else if( GetInfo().IsDropInit() )
1573cdf0e10cSrcweir 		{
1574cdf0e10cSrcweir 			DropInit();
1575cdf0e10cSrcweir 			GetInfo().SetDropInit( sal_False );
1576cdf0e10cSrcweir 		}
1577cdf0e10cSrcweir 
1578cdf0e10cSrcweir         pCurr->CalcLine( *this, GetInfo() );
1579cdf0e10cSrcweir 		CalcRealHeight( GetInfo().IsNewLine() );
1580cdf0e10cSrcweir 
1581201db44cSJian Hong Cheng 		//Bug 120864:For Special case that at the first caculation couldn't get correct height. And need to recaculate for the right height.
1582201db44cSJian Hong Cheng 		SwLinePortion* pPorTmp = pCurr->GetPortion();
1583201db44cSJian Hong Cheng 		if ( IsFlyInCntBase() && (!IsQuick() || (pPorTmp && pPorTmp->IsFlyCntPortion() && !pPorTmp->GetPortion() &&
1584201db44cSJian Hong Cheng 			pCurr->Height() > pPorTmp->Height())))
1585201db44cSJian Hong Cheng 		//Bug 120864(End)
1586cdf0e10cSrcweir 		{
1587cdf0e10cSrcweir 			KSHORT nTmpAscent, nTmpHeight;
1588cdf0e10cSrcweir 			CalcAscentAndHeight( nTmpAscent, nTmpHeight );
1589cdf0e10cSrcweir 			AlignFlyInCntBase( Y() + long( nTmpAscent ) );
1590cdf0e10cSrcweir 			pCurr->CalcLine( *this, GetInfo() );
1591cdf0e10cSrcweir 			CalcRealHeight();
1592cdf0e10cSrcweir 		}
1593cdf0e10cSrcweir 
1594cdf0e10cSrcweir 		// bBuild entscheidet, ob noch eine Ehrenrunde gedreht wird
1595cdf0e10cSrcweir         if ( pCurr->GetRealHeight() <= GetInfo().GetLineHeight() )
1596cdf0e10cSrcweir         {
1597cdf0e10cSrcweir             pCurr->SetRealHeight( GetInfo().GetLineHeight() );
1598cdf0e10cSrcweir             bBuild = sal_False;
1599cdf0e10cSrcweir         }
1600cdf0e10cSrcweir         else
1601cdf0e10cSrcweir         {
1602cdf0e10cSrcweir             bBuild = ( GetInfo().GetTxtFly()->IsOn() && ChkFlyUnderflow(GetInfo()) )
1603cdf0e10cSrcweir                      || GetInfo().CheckFtnPortion(pCurr);
1604cdf0e10cSrcweir             if( bBuild )
1605cdf0e10cSrcweir             {
1606cdf0e10cSrcweir                 GetInfo().SetNumDone( bOldNumDone );
1607cdf0e10cSrcweir                 GetInfo().ResetMaxWidthDiff();
1608cdf0e10cSrcweir 
1609cdf0e10cSrcweir                 // delete old rest
1610cdf0e10cSrcweir                 if ( GetInfo().GetRest() )
1611cdf0e10cSrcweir                 {
1612cdf0e10cSrcweir                     delete GetInfo().GetRest();
1613cdf0e10cSrcweir                     GetInfo().SetRest( 0 );
1614cdf0e10cSrcweir                 }
1615cdf0e10cSrcweir 
1616cdf0e10cSrcweir                 // set original rest portion
1617cdf0e10cSrcweir                 if ( pSaveFld )
1618cdf0e10cSrcweir                     GetInfo().SetRest( new SwFldPortion( *pSaveFld ) );
1619cdf0e10cSrcweir 
1620cdf0e10cSrcweir                 pCurr->SetLen( 0 );
1621cdf0e10cSrcweir                 pCurr->Width(0);
1622cdf0e10cSrcweir                 pCurr->Truncate();
1623cdf0e10cSrcweir             }
1624cdf0e10cSrcweir         }
1625cdf0e10cSrcweir 	}
1626cdf0e10cSrcweir 
1627cdf0e10cSrcweir     // calculate optimal repaint rectangle
1628cdf0e10cSrcweir     if ( bOptimizeRepaint )
1629cdf0e10cSrcweir     {
1630cdf0e10cSrcweir         GetInfo().SetPaintOfst( CalcOptRepaint( nOldLineEnd, pFlyStart ) );
1631cdf0e10cSrcweir         if ( pFlyStart )
1632cdf0e10cSrcweir             delete pFlyStart;
1633cdf0e10cSrcweir     }
1634cdf0e10cSrcweir     else
1635cdf0e10cSrcweir         // Special case: We do not allow an optimitation of the repaint
1636cdf0e10cSrcweir         // area, but during formatting the repaint offset is set to indicate
1637cdf0e10cSrcweir         // a maximum value for the offset. This value has to be reset:
1638cdf0e10cSrcweir         GetInfo().SetPaintOfst( 0 );
1639cdf0e10cSrcweir 
1640cdf0e10cSrcweir     // This corrects the start of the reformat range if something has
1641cdf0e10cSrcweir     // moved to the next line. Otherwise IsFirstReformat in AllowRepaintOpt
1642cdf0e10cSrcweir     // will give us a wrong result if we have to reformat another line
1643cdf0e10cSrcweir     GetInfo().GetParaPortion()->GetReformat()->LeftMove( GetInfo().GetIdx() );
1644cdf0e10cSrcweir 
1645cdf0e10cSrcweir     // delete master copy of rest portion
1646cdf0e10cSrcweir     if ( pSaveFld )
1647cdf0e10cSrcweir         delete pSaveFld;
1648cdf0e10cSrcweir 
1649cdf0e10cSrcweir     xub_StrLen nNewStart = nStartPos + pCurr->GetLen();
1650cdf0e10cSrcweir 
1651cdf0e10cSrcweir     // adjust text if kana compression is enabled
1652cdf0e10cSrcweir     if ( GetInfo().CompressLine() )
1653cdf0e10cSrcweir     {
1654cdf0e10cSrcweir         SwTwips nRepaintOfst = CalcKanaAdj( pCurr );
1655cdf0e10cSrcweir 
1656cdf0e10cSrcweir         // adjust repaint offset
1657cdf0e10cSrcweir         if ( nRepaintOfst < GetInfo().GetPaintOfst() )
1658cdf0e10cSrcweir             GetInfo().SetPaintOfst( nRepaintOfst );
1659cdf0e10cSrcweir     }
1660cdf0e10cSrcweir 
1661cdf0e10cSrcweir     CalcAdjustLine( pCurr );
1662cdf0e10cSrcweir 
1663cdf0e10cSrcweir 	if( nOldHeight != pCurr->Height() || nOldAscent != pCurr->GetAscent() )
1664cdf0e10cSrcweir 	{
1665cdf0e10cSrcweir 		SetFlyInCntBase();
1666cdf0e10cSrcweir 		GetInfo().SetPaintOfst( 0 ); //geaenderte Zeilenhoehe => kein Recycling
1667cdf0e10cSrcweir 		// alle weiteren Zeilen muessen gepaintet und, wenn Flys im Spiel sind
1668cdf0e10cSrcweir 		// auch formatiert werden.
1669cdf0e10cSrcweir 		GetInfo().SetShift( sal_True );
1670cdf0e10cSrcweir 	}
1671cdf0e10cSrcweir 
1672cdf0e10cSrcweir 	if ( IsFlyInCntBase() && !IsQuick() )
1673cdf0e10cSrcweir 		UpdatePos( pCurr, GetTopLeft(), GetStart() );
1674cdf0e10cSrcweir 
1675cdf0e10cSrcweir 	return nNewStart;
1676cdf0e10cSrcweir }
1677cdf0e10cSrcweir 
1678cdf0e10cSrcweir /*************************************************************************
1679cdf0e10cSrcweir  *                      SwTxtFormatter::RecalcRealHeight()
1680cdf0e10cSrcweir  *************************************************************************/
1681cdf0e10cSrcweir 
RecalcRealHeight()1682cdf0e10cSrcweir void SwTxtFormatter::RecalcRealHeight()
1683cdf0e10cSrcweir {
1684cdf0e10cSrcweir 	sal_Bool bMore = sal_True;
1685cdf0e10cSrcweir 	while(bMore)
1686cdf0e10cSrcweir 	{
1687cdf0e10cSrcweir 		DBG_LOOP;
1688cdf0e10cSrcweir 		CalcRealHeight();
1689cdf0e10cSrcweir 		bMore = Next() != 0;
1690cdf0e10cSrcweir 	}
1691cdf0e10cSrcweir }
1692cdf0e10cSrcweir 
1693cdf0e10cSrcweir /*************************************************************************
1694cdf0e10cSrcweir  *                    SwTxtFormatter::CalcRealHeight()
1695cdf0e10cSrcweir  *************************************************************************/
1696cdf0e10cSrcweir 
CalcRealHeight(sal_Bool bNewLine)1697cdf0e10cSrcweir void SwTxtFormatter::CalcRealHeight( sal_Bool bNewLine )
1698cdf0e10cSrcweir {
1699cdf0e10cSrcweir 	KSHORT nLineHeight = pCurr->Height();
1700cdf0e10cSrcweir 	pCurr->SetClipping( sal_False );
1701cdf0e10cSrcweir 
1702cdf0e10cSrcweir     GETGRID( pFrm->FindPageFrm() )
1703cdf0e10cSrcweir     if ( pGrid && GetInfo().SnapToGrid() )
1704cdf0e10cSrcweir     {
1705cdf0e10cSrcweir         const sal_uInt16 nGridWidth = pGrid->GetBaseHeight();
1706cdf0e10cSrcweir         const sal_uInt16 nRubyHeight = pGrid->GetRubyHeight();
1707cdf0e10cSrcweir         const sal_Bool bRubyTop = ! pGrid->GetRubyTextBelow();
1708cdf0e10cSrcweir 
1709cdf0e10cSrcweir         nLineHeight = nGridWidth + nRubyHeight;
1710cdf0e10cSrcweir         sal_uInt16 nLineDist = nLineHeight;
1711cdf0e10cSrcweir 
1712cdf0e10cSrcweir         while ( pCurr->Height() > nLineHeight )
1713cdf0e10cSrcweir             nLineHeight = nLineHeight + nLineDist;
1714cdf0e10cSrcweir 
1715cdf0e10cSrcweir         KSHORT nAsc = pCurr->GetAscent() +
1716cdf0e10cSrcweir                       ( bRubyTop ?
1717cdf0e10cSrcweir                        ( nLineHeight - pCurr->Height() + nRubyHeight ) / 2 :
1718cdf0e10cSrcweir                        ( nLineHeight - pCurr->Height() - nRubyHeight ) / 2 );
1719cdf0e10cSrcweir 
1720cdf0e10cSrcweir         pCurr->Height( nLineHeight );
1721cdf0e10cSrcweir         pCurr->SetAscent( nAsc );
1722cdf0e10cSrcweir         pInf->GetParaPortion()->SetFixLineHeight();
1723cdf0e10cSrcweir 
1724cdf0e10cSrcweir         // we ignore any line spacing options except from ...
1725cdf0e10cSrcweir         const SvxLineSpacingItem* pSpace = aLineInf.GetLineSpacing();
1726cdf0e10cSrcweir         if ( ! IsParaLine() && pSpace &&
1727cdf0e10cSrcweir              SVX_INTER_LINE_SPACE_PROP == pSpace->GetInterLineSpaceRule() )
1728cdf0e10cSrcweir         {
1729cdf0e10cSrcweir             sal_uLong nTmp = pSpace->GetPropLineSpace();
1730cdf0e10cSrcweir 
1731cdf0e10cSrcweir             if( nTmp < 100 )
1732cdf0e10cSrcweir                 nTmp = 100;
1733cdf0e10cSrcweir 
1734cdf0e10cSrcweir             nTmp *= nLineHeight;
1735cdf0e10cSrcweir             nLineHeight = (sal_uInt16)(nTmp / 100);
1736cdf0e10cSrcweir         }
1737cdf0e10cSrcweir 
1738cdf0e10cSrcweir         pCurr->SetRealHeight( nLineHeight );
1739cdf0e10cSrcweir         return;
1740cdf0e10cSrcweir     }
1741cdf0e10cSrcweir 
1742cdf0e10cSrcweir 	// Das Dummyflag besitzen Zeilen, die nur Flyportions enthalten, diese
1743cdf0e10cSrcweir 	// sollten kein Register etc. beachten. Dummerweise hat kann es eine leere
1744cdf0e10cSrcweir 	// Zeile am Absatzende geben (bei leeren Abs?tzen oder nach einem
1745cdf0e10cSrcweir 	// Shift-Return), die das Register durchaus beachten soll.
1746cdf0e10cSrcweir     if( !pCurr->IsDummy() || ( !pCurr->GetNext() &&
1747cdf0e10cSrcweir         GetStart() >= GetTxtFrm()->GetTxt().Len() && !bNewLine ) )
1748cdf0e10cSrcweir     {
1749cdf0e10cSrcweir         const SvxLineSpacingItem *pSpace = aLineInf.GetLineSpacing();
1750cdf0e10cSrcweir         if( pSpace )
1751cdf0e10cSrcweir         {
1752cdf0e10cSrcweir             switch( pSpace->GetLineSpaceRule() )
1753cdf0e10cSrcweir             {
1754cdf0e10cSrcweir                 case SVX_LINE_SPACE_AUTO:
1755cdf0e10cSrcweir                 break;
1756cdf0e10cSrcweir                 case SVX_LINE_SPACE_MIN:
1757cdf0e10cSrcweir                 {
1758cdf0e10cSrcweir                     if( nLineHeight < KSHORT( pSpace->GetLineHeight() ) )
1759cdf0e10cSrcweir                         nLineHeight = pSpace->GetLineHeight();
1760cdf0e10cSrcweir                     break;
1761cdf0e10cSrcweir                 }
1762cdf0e10cSrcweir                 case SVX_LINE_SPACE_FIX:
1763cdf0e10cSrcweir                 {
1764cdf0e10cSrcweir                     nLineHeight = pSpace->GetLineHeight();
1765cdf0e10cSrcweir                     KSHORT nAsc = ( 4 * nLineHeight ) / 5;  // 80%
1766cdf0e10cSrcweir                     if( nAsc < pCurr->GetAscent() ||
1767cdf0e10cSrcweir                         nLineHeight - nAsc < pCurr->Height() - pCurr->GetAscent() )
1768cdf0e10cSrcweir                         pCurr->SetClipping( sal_True );
1769cdf0e10cSrcweir                     pCurr->Height( nLineHeight );
1770cdf0e10cSrcweir                     pCurr->SetAscent( nAsc );
1771cdf0e10cSrcweir                     pInf->GetParaPortion()->SetFixLineHeight();
1772cdf0e10cSrcweir                 }
1773cdf0e10cSrcweir                 break;
1774cdf0e10cSrcweir                 default: ASSERT( sal_False, ": unknown LineSpaceRule" );
1775cdf0e10cSrcweir             }
1776cdf0e10cSrcweir             if( !IsParaLine() )
1777cdf0e10cSrcweir                 switch( pSpace->GetInterLineSpaceRule() )
1778cdf0e10cSrcweir                 {
1779cdf0e10cSrcweir                     case SVX_INTER_LINE_SPACE_OFF:
1780cdf0e10cSrcweir                     break;
1781cdf0e10cSrcweir                     case SVX_INTER_LINE_SPACE_PROP:
1782cdf0e10cSrcweir                     {
1783cdf0e10cSrcweir                         long nTmp = pSpace->GetPropLineSpace();
1784cdf0e10cSrcweir                         // 50% ist das Minimum, bei 0% schalten wir auf
1785cdf0e10cSrcweir                         // den Defaultwert 100% um ...
1786cdf0e10cSrcweir                         if( nTmp < 50 )
1787cdf0e10cSrcweir                             nTmp = nTmp ? 50 : 100;
1788cdf0e10cSrcweir 
1789cdf0e10cSrcweir                         nTmp *= nLineHeight;
1790cdf0e10cSrcweir                         nTmp /= 100;
1791cdf0e10cSrcweir                         if( !nTmp )
1792cdf0e10cSrcweir                             ++nTmp;
1793cdf0e10cSrcweir                         nLineHeight = (KSHORT)nTmp;
1794cdf0e10cSrcweir                         break;
1795cdf0e10cSrcweir                     }
1796cdf0e10cSrcweir                     case SVX_INTER_LINE_SPACE_FIX:
1797cdf0e10cSrcweir                     {
1798cdf0e10cSrcweir                         nLineHeight = nLineHeight + pSpace->GetInterLineSpace();
1799cdf0e10cSrcweir                         break;
1800cdf0e10cSrcweir                     }
1801cdf0e10cSrcweir                     default: ASSERT( sal_False, ": unknown InterLineSpaceRule" );
1802cdf0e10cSrcweir                 }
1803cdf0e10cSrcweir         }
1804cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1
1805cdf0e10cSrcweir         KSHORT nDummy = nLineHeight + 1;
1806cdf0e10cSrcweir         (void)nDummy;
1807cdf0e10cSrcweir #endif
1808cdf0e10cSrcweir 
1809cdf0e10cSrcweir         if( IsRegisterOn() )
1810cdf0e10cSrcweir         {
1811cdf0e10cSrcweir             SwTwips nTmpY = Y() + pCurr->GetAscent() + nLineHeight - pCurr->Height();
1812cdf0e10cSrcweir             SWRECTFN( pFrm )
1813cdf0e10cSrcweir             if ( bVert )
1814cdf0e10cSrcweir                 nTmpY = pFrm->SwitchHorizontalToVertical( nTmpY );
1815cdf0e10cSrcweir             nTmpY = (*fnRect->fnYDiff)( nTmpY, RegStart() );
1816cdf0e10cSrcweir             KSHORT nDiff = KSHORT( nTmpY % RegDiff() );
1817cdf0e10cSrcweir             if( nDiff )
1818cdf0e10cSrcweir                 nLineHeight += RegDiff() - nDiff;
1819cdf0e10cSrcweir         }
1820cdf0e10cSrcweir     }
1821cdf0e10cSrcweir 	pCurr->SetRealHeight( nLineHeight );
1822cdf0e10cSrcweir }
1823cdf0e10cSrcweir 
1824cdf0e10cSrcweir /*************************************************************************
1825cdf0e10cSrcweir  *						SwTxtFormatter::FeedInf()
1826cdf0e10cSrcweir  *************************************************************************/
1827cdf0e10cSrcweir 
FeedInf(SwTxtFormatInfo & rInf) const1828cdf0e10cSrcweir void SwTxtFormatter::FeedInf( SwTxtFormatInfo &rInf ) const
1829cdf0e10cSrcweir {
1830cdf0e10cSrcweir 	// 3260, 3860: Fly auf jeden Fall loeschen!
1831cdf0e10cSrcweir 	ClearFly( rInf );
1832cdf0e10cSrcweir 	rInf.Init();
1833cdf0e10cSrcweir 
1834cdf0e10cSrcweir 	rInf.ChkNoHyph( CntEndHyph(), CntMidHyph() );
1835cdf0e10cSrcweir 	rInf.SetRoot( pCurr );
1836cdf0e10cSrcweir 	rInf.SetLineStart( nStart );
1837cdf0e10cSrcweir 	rInf.SetIdx( nStart );
1838cdf0e10cSrcweir 
1839cdf0e10cSrcweir     // Handle overflows:
1840cdf0e10cSrcweir     // --> FME 2004-11-25 #i34348# Changed type from sal_uInt16 to SwTwips
1841cdf0e10cSrcweir     SwTwips nTmpLeft = Left();
1842cdf0e10cSrcweir     SwTwips nTmpRight = Right();
1843cdf0e10cSrcweir     SwTwips nTmpFirst = FirstLeft();
1844cdf0e10cSrcweir     // <--
1845cdf0e10cSrcweir 
1846cdf0e10cSrcweir     if ( nTmpLeft > USHRT_MAX ||
1847cdf0e10cSrcweir          nTmpRight > USHRT_MAX ||
1848cdf0e10cSrcweir          nTmpFirst > USHRT_MAX )
1849cdf0e10cSrcweir     {
1850cdf0e10cSrcweir         SWRECTFN( rInf.GetTxtFrm() )
1851cdf0e10cSrcweir         nTmpLeft = (rInf.GetTxtFrm()->Frm().*fnRect->fnGetLeft)();
1852cdf0e10cSrcweir         nTmpRight = (rInf.GetTxtFrm()->Frm().*fnRect->fnGetRight)();
1853cdf0e10cSrcweir         nTmpFirst = nTmpLeft;
1854cdf0e10cSrcweir     }
1855cdf0e10cSrcweir 
1856cdf0e10cSrcweir     rInf.Left(  nTmpLeft  );
1857cdf0e10cSrcweir     rInf.Right( nTmpRight );
1858cdf0e10cSrcweir     rInf.First( nTmpFirst );
1859cdf0e10cSrcweir 
1860cdf0e10cSrcweir 	rInf.RealWidth( KSHORT(rInf.Right()) - KSHORT(GetLeftMargin()) );
1861cdf0e10cSrcweir 	rInf.Width( rInf.RealWidth() );
1862cdf0e10cSrcweir 	if( ((SwTxtFormatter*)this)->GetRedln() )
1863cdf0e10cSrcweir 	{
1864cdf0e10cSrcweir 		((SwTxtFormatter*)this)->GetRedln()->Clear( ((SwTxtFormatter*)this)->GetFnt() );
1865cdf0e10cSrcweir 		((SwTxtFormatter*)this)->GetRedln()->Reset();
1866cdf0e10cSrcweir 	}
1867cdf0e10cSrcweir }
1868cdf0e10cSrcweir 
1869cdf0e10cSrcweir /*************************************************************************
1870cdf0e10cSrcweir  *						SwTxtFormatter::FormatReset()
1871cdf0e10cSrcweir  *************************************************************************/
1872cdf0e10cSrcweir 
FormatReset(SwTxtFormatInfo & rInf)1873cdf0e10cSrcweir void SwTxtFormatter::FormatReset( SwTxtFormatInfo &rInf )
1874cdf0e10cSrcweir {
1875cdf0e10cSrcweir 	pCurr->Truncate();
1876cdf0e10cSrcweir 	pCurr->Init();
1877cdf0e10cSrcweir 	if( pBlink && pCurr->IsBlinking() )
1878cdf0e10cSrcweir 		pBlink->Delete( pCurr );
1879cdf0e10cSrcweir 
1880cdf0e10cSrcweir     // delete pSpaceAdd und pKanaComp
1881cdf0e10cSrcweir     pCurr->FinishSpaceAdd();
1882cdf0e10cSrcweir     pCurr->FinishKanaComp();
1883cdf0e10cSrcweir 	pCurr->ResetFlags();
1884cdf0e10cSrcweir 	FeedInf( rInf );
1885cdf0e10cSrcweir }
1886cdf0e10cSrcweir 
1887cdf0e10cSrcweir /*************************************************************************
1888cdf0e10cSrcweir  *				  SwTxtFormatter::CalcOnceMore()
1889cdf0e10cSrcweir  *************************************************************************/
1890cdf0e10cSrcweir 
CalcOnceMore()1891cdf0e10cSrcweir sal_Bool SwTxtFormatter::CalcOnceMore()
1892cdf0e10cSrcweir {
1893cdf0e10cSrcweir 	if( pDropFmt )
1894cdf0e10cSrcweir 	{
1895cdf0e10cSrcweir 		const KSHORT nOldDrop = GetDropHeight();
1896cdf0e10cSrcweir 		CalcDropHeight( pDropFmt->GetLines() );
1897cdf0e10cSrcweir 		bOnceMore = nOldDrop != GetDropHeight();
1898cdf0e10cSrcweir 	}
1899cdf0e10cSrcweir 	else
1900cdf0e10cSrcweir 		bOnceMore = sal_False;
1901cdf0e10cSrcweir 	return bOnceMore;
1902cdf0e10cSrcweir }
1903cdf0e10cSrcweir 
1904cdf0e10cSrcweir /*************************************************************************
1905cdf0e10cSrcweir  *				  SwTxtFormatter::CalcBottomLine()
1906cdf0e10cSrcweir  *************************************************************************/
1907cdf0e10cSrcweir 
CalcBottomLine() const1908cdf0e10cSrcweir SwTwips SwTxtFormatter::CalcBottomLine() const
1909cdf0e10cSrcweir {
1910cdf0e10cSrcweir 	SwTwips nRet = Y() + GetLineHeight();
1911cdf0e10cSrcweir 	SwTwips nMin = GetInfo().GetTxtFly()->GetMinBottom();
1912cdf0e10cSrcweir 	if( nMin && ++nMin > nRet )
1913cdf0e10cSrcweir 	{
1914cdf0e10cSrcweir 		SwTwips nDist = pFrm->Frm().Height() - pFrm->Prt().Height()
1915cdf0e10cSrcweir 						- pFrm->Prt().Top();
1916cdf0e10cSrcweir 		if( nRet + nDist < nMin )
1917cdf0e10cSrcweir 		{
1918cdf0e10cSrcweir 			sal_Bool bRepaint = HasTruncLines() &&
1919cdf0e10cSrcweir 				GetInfo().GetParaPortion()->GetRepaint()->Bottom() == nRet-1;
1920cdf0e10cSrcweir 			nRet = nMin - nDist;
1921cdf0e10cSrcweir 			if( bRepaint )
1922cdf0e10cSrcweir 			{
1923cdf0e10cSrcweir 				((SwRepaint*)GetInfo().GetParaPortion()
1924cdf0e10cSrcweir 					->GetRepaint())->Bottom( nRet-1 );
1925cdf0e10cSrcweir 				((SwTxtFormatInfo&)GetInfo()).SetPaintOfst( 0 );
1926cdf0e10cSrcweir 			}
1927cdf0e10cSrcweir 		}
1928cdf0e10cSrcweir 	}
1929cdf0e10cSrcweir 	return nRet;
1930cdf0e10cSrcweir }
1931cdf0e10cSrcweir 
1932cdf0e10cSrcweir /*************************************************************************
1933cdf0e10cSrcweir  *				  SwTxtFormatter::_CalcFitToContent()
1934cdf0e10cSrcweir  *
1935cdf0e10cSrcweir  * FME/OD: This routine does a limited text formatting.
1936cdf0e10cSrcweir  *************************************************************************/
1937cdf0e10cSrcweir 
_CalcFitToContent()1938cdf0e10cSrcweir SwTwips SwTxtFormatter::_CalcFitToContent()
1939cdf0e10cSrcweir {
1940cdf0e10cSrcweir     FormatReset( GetInfo() );
1941cdf0e10cSrcweir     BuildPortions( GetInfo() );
1942cdf0e10cSrcweir     pCurr->CalcLine( *this, GetInfo() );
1943cdf0e10cSrcweir     return pCurr->Width();
1944cdf0e10cSrcweir }
1945cdf0e10cSrcweir 
1946cdf0e10cSrcweir /*************************************************************************
1947cdf0e10cSrcweir  *                      SwTxtFormatter::AllowRepaintOpt()
1948cdf0e10cSrcweir  *
1949cdf0e10cSrcweir  * determines if the calculation of a repaint offset is allowed
1950cdf0e10cSrcweir  * otherwise each line is painted from 0 (this is a copy of the beginning
1951cdf0e10cSrcweir  * of the former SwTxtFormatter::Recycle() function
1952cdf0e10cSrcweir  *************************************************************************/
AllowRepaintOpt() const1953cdf0e10cSrcweir sal_Bool SwTxtFormatter::AllowRepaintOpt() const
1954cdf0e10cSrcweir {
1955cdf0e10cSrcweir     // reformat position in front of current line? Only in this case
1956cdf0e10cSrcweir     // we want to set the repaint offset
1957cdf0e10cSrcweir     sal_Bool bOptimizeRepaint = nStart < GetInfo().GetReformatStart() &&
1958cdf0e10cSrcweir                                 pCurr->GetLen();
1959cdf0e10cSrcweir 
1960cdf0e10cSrcweir     // a special case is the last line of a block adjusted paragraph:
1961cdf0e10cSrcweir     if ( bOptimizeRepaint )
1962cdf0e10cSrcweir     {
1963cdf0e10cSrcweir         switch( GetAdjust() )
1964cdf0e10cSrcweir         {
1965cdf0e10cSrcweir         case SVX_ADJUST_BLOCK:
1966cdf0e10cSrcweir         {
1967cdf0e10cSrcweir             if( IsLastBlock() || IsLastCenter() )
1968cdf0e10cSrcweir                 bOptimizeRepaint = sal_False;
1969cdf0e10cSrcweir             else
1970cdf0e10cSrcweir             {
1971cdf0e10cSrcweir                 // ????: Blank in der letzten Masterzeile (blocksat.sdw)
1972cdf0e10cSrcweir                 bOptimizeRepaint = 0 == pCurr->GetNext() && !pFrm->GetFollow();
1973cdf0e10cSrcweir                 if ( bOptimizeRepaint )
1974cdf0e10cSrcweir                 {
1975cdf0e10cSrcweir                     SwLinePortion *pPos = pCurr->GetFirstPortion();
1976cdf0e10cSrcweir                     while ( pPos && !pPos->IsFlyPortion() )
1977cdf0e10cSrcweir                         pPos = pPos->GetPortion();
1978cdf0e10cSrcweir                     bOptimizeRepaint = !pPos;
1979cdf0e10cSrcweir                 }
1980cdf0e10cSrcweir             }
1981cdf0e10cSrcweir             break;
1982cdf0e10cSrcweir         }
1983cdf0e10cSrcweir         case SVX_ADJUST_CENTER:
1984cdf0e10cSrcweir         case SVX_ADJUST_RIGHT:
1985cdf0e10cSrcweir             bOptimizeRepaint = sal_False;
1986cdf0e10cSrcweir             break;
1987cdf0e10cSrcweir         default: ;
1988cdf0e10cSrcweir         }
1989cdf0e10cSrcweir     }
1990cdf0e10cSrcweir 
1991cdf0e10cSrcweir 	// Schon wieder ein Sonderfall: unsichtbare SoftHyphs
1992cdf0e10cSrcweir     const xub_StrLen nReformat = GetInfo().GetReformatStart();
1993cdf0e10cSrcweir     if( bOptimizeRepaint && STRING_LEN != nReformat )
1994cdf0e10cSrcweir 	{
1995cdf0e10cSrcweir         const xub_Unicode cCh = GetInfo().GetTxt().GetChar( nReformat );
1996cdf0e10cSrcweir         bOptimizeRepaint = ( CH_TXTATR_BREAKWORD != cCh && CH_TXTATR_INWORD != cCh )
1997cdf0e10cSrcweir                             || ! GetInfo().HasHint( nReformat );
1998cdf0e10cSrcweir 	}
1999cdf0e10cSrcweir 
2000cdf0e10cSrcweir     return bOptimizeRepaint;
2001cdf0e10cSrcweir }
2002cdf0e10cSrcweir 
2003cdf0e10cSrcweir /*************************************************************************
2004cdf0e10cSrcweir  *                      SwTxtFormatter::CalcOptRepaint()
2005cdf0e10cSrcweir  *
2006cdf0e10cSrcweir  * calculates an optimal repaint offset for the current line
2007cdf0e10cSrcweir  *************************************************************************/
CalcOptRepaint(xub_StrLen nOldLineEnd,const SvLongs * pFlyStart)2008cdf0e10cSrcweir long SwTxtFormatter::CalcOptRepaint( xub_StrLen nOldLineEnd,
2009cdf0e10cSrcweir                                      const SvLongs* pFlyStart )
2010cdf0e10cSrcweir {
2011cdf0e10cSrcweir     if ( GetInfo().GetIdx() < GetInfo().GetReformatStart() )
2012cdf0e10cSrcweir     // the reformat position is behind our new line, that means
2013cdf0e10cSrcweir     // something of our text has moved to the next line
2014cdf0e10cSrcweir         return 0;
2015cdf0e10cSrcweir 
2016cdf0e10cSrcweir     xub_StrLen nReformat = Min( GetInfo().GetReformatStart(), nOldLineEnd );
2017cdf0e10cSrcweir 
2018cdf0e10cSrcweir     // in case we do not have any fly in our line, our repaint position
2019cdf0e10cSrcweir     // is the changed position - 1
2020cdf0e10cSrcweir     if ( ! pFlyStart && ! pCurr->IsFly() )
2021cdf0e10cSrcweir     {
2022cdf0e10cSrcweir         // this is the maximum repaint offset determined during formatting
2023cdf0e10cSrcweir         // for example: the beginning of the first right tab stop
2024cdf0e10cSrcweir         // if this value is 0, this means that we do not have an upper
2025cdf0e10cSrcweir         // limit for the repaint offset
2026cdf0e10cSrcweir         const long nFormatRepaint = GetInfo().GetPaintOfst();
2027cdf0e10cSrcweir 
2028cdf0e10cSrcweir         if ( nReformat < GetInfo().GetLineStart() + 3 )
2029cdf0e10cSrcweir             return 0;
2030cdf0e10cSrcweir 
2031cdf0e10cSrcweir         // step back two positions for smoother repaint
2032cdf0e10cSrcweir         nReformat -= 2;
2033cdf0e10cSrcweir 
2034cdf0e10cSrcweir #ifndef QUARTZ
2035cdf0e10cSrcweir #ifndef ENABLE_GRAPHITE
2036cdf0e10cSrcweir         // --> FME 2004-09-27 #i28795#, #i34607#, #i38388#
2037cdf0e10cSrcweir         // step back six(!) more characters for complex scripts
2038cdf0e10cSrcweir         // this is required e.g., for Khmer (thank you, Javier!)
2039cdf0e10cSrcweir         const SwScriptInfo& rSI = GetInfo().GetParaPortion()->GetScriptInfo();
2040cdf0e10cSrcweir         xub_StrLen nMaxContext = 0;
2041cdf0e10cSrcweir         if( ::i18n::ScriptType::COMPLEX == rSI.ScriptType( nReformat ) )
2042cdf0e10cSrcweir             nMaxContext = 6;
2043cdf0e10cSrcweir #else
2044cdf0e10cSrcweir         // Some Graphite fonts need context for scripts not marked as complex
2045cdf0e10cSrcweir         static const xub_StrLen nMaxContext = 10;
2046cdf0e10cSrcweir #endif
2047cdf0e10cSrcweir #else
2048cdf0e10cSrcweir         // some fonts like Quartz's Zapfino need more context
2049cdf0e10cSrcweir         // TODO: query FontInfo for maximum unicode context
2050cdf0e10cSrcweir         static const xub_StrLen nMaxContext = 8;
2051cdf0e10cSrcweir #endif
2052cdf0e10cSrcweir         if( nMaxContext > 0 )
2053cdf0e10cSrcweir         {
2054cdf0e10cSrcweir             if ( nReformat > GetInfo().GetLineStart() + nMaxContext )
2055cdf0e10cSrcweir                 nReformat = nReformat - nMaxContext;
2056cdf0e10cSrcweir             else
2057cdf0e10cSrcweir                 nReformat = GetInfo().GetLineStart();
2058cdf0e10cSrcweir         }
2059cdf0e10cSrcweir         // <--
2060cdf0e10cSrcweir 
2061cdf0e10cSrcweir         // Weird situation: Our line used to end with a hole portion
2062cdf0e10cSrcweir         // and we delete some characters at the end of our line. We have
2063cdf0e10cSrcweir         // to take care for repainting the blanks which are not anymore
2064cdf0e10cSrcweir         // covered by the hole portion
2065cdf0e10cSrcweir         while ( nReformat > GetInfo().GetLineStart() &&
2066cdf0e10cSrcweir                 CH_BLANK == GetInfo().GetChar( nReformat ) )
2067cdf0e10cSrcweir             --nReformat;
2068cdf0e10cSrcweir 
2069cdf0e10cSrcweir         ASSERT( nReformat < GetInfo().GetIdx(), "Reformat too small for me!" );
2070cdf0e10cSrcweir         SwRect aRect;
2071cdf0e10cSrcweir 
2072cdf0e10cSrcweir         // Note: GetChareRect is not const. It definitely changes the
2073cdf0e10cSrcweir         // bMulti flag. We have to save and resore the old value.
2074cdf0e10cSrcweir         sal_Bool bOldMulti = GetInfo().IsMulti();
2075cdf0e10cSrcweir         GetCharRect( &aRect, nReformat );
2076cdf0e10cSrcweir         GetInfo().SetMulti( bOldMulti );
2077cdf0e10cSrcweir 
2078cdf0e10cSrcweir         return nFormatRepaint ? Min( aRect.Left(), nFormatRepaint ) :
2079cdf0e10cSrcweir                                 aRect.Left();
2080cdf0e10cSrcweir     }
2081cdf0e10cSrcweir     else
2082cdf0e10cSrcweir     {
2083cdf0e10cSrcweir         // nReformat may be wrong, if something around flys has changed:
2084cdf0e10cSrcweir         // we compare the former and the new fly positions in this line
2085cdf0e10cSrcweir         // if anything has changed, we carefully have to adjust the right
2086cdf0e10cSrcweir         // repaint position
2087cdf0e10cSrcweir         long nPOfst = 0;
2088cdf0e10cSrcweir         sal_uInt16 nCnt = 0;
2089cdf0e10cSrcweir         sal_uInt16 nX = 0;
2090cdf0e10cSrcweir         sal_uInt16 nIdx = GetInfo().GetLineStart();
2091cdf0e10cSrcweir         SwLinePortion* pPor = pCurr->GetFirstPortion();
2092cdf0e10cSrcweir 
2093cdf0e10cSrcweir         while ( pPor )
2094cdf0e10cSrcweir         {
2095cdf0e10cSrcweir             if ( pPor->IsFlyPortion() )
2096cdf0e10cSrcweir             {
2097cdf0e10cSrcweir                 // compare start of fly with former start of fly
2098cdf0e10cSrcweir                 if ( pFlyStart &&
2099cdf0e10cSrcweir                      nCnt < pFlyStart->Count() &&
2100cdf0e10cSrcweir                      nX == (*pFlyStart)[ nCnt ] &&
2101cdf0e10cSrcweir                      nIdx < nReformat
2102cdf0e10cSrcweir                    )
2103cdf0e10cSrcweir                     // found fix position, nothing has changed left from nX
2104cdf0e10cSrcweir                     nPOfst = nX + pPor->Width();
2105cdf0e10cSrcweir                 else
2106cdf0e10cSrcweir                     break;
2107cdf0e10cSrcweir 
2108cdf0e10cSrcweir                 nCnt++;
2109cdf0e10cSrcweir             }
2110cdf0e10cSrcweir             nX = nX + pPor->Width();
2111cdf0e10cSrcweir             nIdx = nIdx + pPor->GetLen();
2112cdf0e10cSrcweir             pPor = pPor->GetPortion();
2113cdf0e10cSrcweir         }
2114cdf0e10cSrcweir 
2115cdf0e10cSrcweir         return nPOfst + GetLeftMargin();
2116cdf0e10cSrcweir     }
2117cdf0e10cSrcweir }
2118cdf0e10cSrcweir 
lcl_BuildHiddenPortion(const SwTxtSizeInfo & rInf,xub_StrLen & rPos)2119cdf0e10cSrcweir bool lcl_BuildHiddenPortion( const SwTxtSizeInfo& rInf, xub_StrLen &rPos )
2120cdf0e10cSrcweir {
2121cdf0e10cSrcweir     // Only if hidden text should not be shown:
2122cdf0e10cSrcweir //    if ( rInf.GetVsh() && rInf.GetVsh()->GetWin() && rInf.GetOpt().IsShowHiddenChar() )
2123cdf0e10cSrcweir     const bool bShowInDocView = rInf.GetVsh() && rInf.GetVsh()->GetWin() && rInf.GetOpt().IsShowHiddenChar();
2124cdf0e10cSrcweir     const bool bShowForPrinting = rInf.GetOpt().IsShowHiddenChar( sal_True ) && rInf.GetOpt().IsPrinting();
2125cdf0e10cSrcweir     if (bShowInDocView || bShowForPrinting)
2126cdf0e10cSrcweir         return false;
2127cdf0e10cSrcweir 
2128cdf0e10cSrcweir     const SwScriptInfo& rSI = rInf.GetParaPortion()->GetScriptInfo();
2129cdf0e10cSrcweir     xub_StrLen nHiddenStart;
2130cdf0e10cSrcweir     xub_StrLen nHiddenEnd;
2131cdf0e10cSrcweir     rSI.GetBoundsOfHiddenRange( rPos, nHiddenStart, nHiddenEnd );
2132cdf0e10cSrcweir     if ( nHiddenEnd )
2133cdf0e10cSrcweir     {
2134cdf0e10cSrcweir         rPos = nHiddenEnd;
2135cdf0e10cSrcweir         return true;
2136cdf0e10cSrcweir     }
2137cdf0e10cSrcweir 
2138cdf0e10cSrcweir     return false;
2139cdf0e10cSrcweir }
2140