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