Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*************************************************************************
3 : : *
4 : : * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 : : *
6 : : * Copyright 2000, 2010 Oracle and/or its affiliates.
7 : : *
8 : : * OpenOffice.org - a multi-platform office productivity suite
9 : : *
10 : : * This file is part of OpenOffice.org.
11 : : *
12 : : * OpenOffice.org is free software: you can redistribute it and/or modify
13 : : * it under the terms of the GNU Lesser General Public License version 3
14 : : * only, as published by the Free Software Foundation.
15 : : *
16 : : * OpenOffice.org is distributed in the hope that it will be useful,
17 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : : * GNU Lesser General Public License version 3 for more details
20 : : * (a copy is included in the LICENSE file that accompanied this code).
21 : : *
22 : : * You should have received a copy of the GNU Lesser General Public License
23 : : * version 3 along with OpenOffice.org. If not, see
24 : : * <http://www.openoffice.org/license.html>
25 : : * for a copy of the LGPLv3 License.
26 : : *
27 : : ************************************************************************/
28 : :
29 : :
30 : : #include "hintids.hxx"
31 : :
32 : : #include <com/sun/star/i18n/ScriptType.hpp>
33 : : #include <editeng/lspcitem.hxx>
34 : : #include <txtflcnt.hxx>
35 : : #include <txtftn.hxx>
36 : : #include <flyfrms.hxx>
37 : : #include <fmtflcnt.hxx>
38 : : #include <fmtftn.hxx>
39 : : #include <ftninfo.hxx>
40 : : #include <charfmt.hxx>
41 : : #include <editeng/charrotateitem.hxx>
42 : : #include <layfrm.hxx> // GetFrmRstHeight, etc
43 : : #include <viewsh.hxx>
44 : : #include <viewopt.hxx> // SwViewOptions
45 : : #include <paratr.hxx> // SwFmtDrop
46 : : #include <itrform2.hxx>
47 : : #include <porrst.hxx>
48 : : #include <portab.hxx> // pLastTab->
49 : : #include <porfly.hxx> // CalcFlyWidth
50 : : #include <portox.hxx> // WhichTxtPortion
51 : : #include <porref.hxx> // WhichTxtPortion
52 : : #include <porfld.hxx> // SwNumberPortion for CalcAscent()
53 : : #include <porftn.hxx> // SwFtnPortion
54 : : #include <porhyph.hxx>
55 : : #include <guess.hxx>
56 : : #include <blink.hxx> // pBlink
57 : : #include <ftnfrm.hxx> // WhichFirstPortion() -> move it
58 : : #include <redlnitr.hxx> // SwRedlineItr
59 : : #include <pagefrm.hxx>
60 : : #include <pagedesc.hxx> // SwPageDesc
61 : : #include <tgrditem.hxx>
62 : : #include <doc.hxx> // SwDoc
63 : : #include <pormulti.hxx> // SwMultiPortion
64 : : #include <unotools/charclass.hxx>
65 : :
66 : : #include <vector>
67 : :
68 : : #if OSL_DEBUG_LEVEL > 1
69 : : #include <ndtxt.hxx> // pSwpHints, output operator
70 : : #endif
71 : :
72 : : using namespace ::com::sun::star;
73 : :
74 : : extern sal_Bool IsUnderlineBreak( const SwLinePortion& rPor, const SwFont& rFnt );
75 : :
76 : : namespace {
77 : : //! Calculates and sets optimal repaint offset for the current line
78 : : static long lcl_CalcOptRepaint( SwTxtFormatter &rThis,
79 : : SwLineLayout &rCurr,
80 : : const xub_StrLen nOldLineEnd,
81 : : const std::vector<long> &rFlyStarts );
82 : : //! Determine if we need to build hidden portions
83 : : static bool lcl_BuildHiddenPortion( const SwTxtSizeInfo& rInf, xub_StrLen &rPos );
84 : : }
85 : :
86 : 107496 : inline void ClearFly( SwTxtFormatInfo &rInf )
87 : : {
88 [ + + ]: 107496 : delete rInf.GetFly();
89 : 107496 : rInf.SetFly(0);
90 : 107496 : }
91 : :
92 : : /*************************************************************************
93 : : * SwTxtFormatter::CtorInitTxtFormatter()
94 : : *************************************************************************/
95 : :
96 : 14873 : void SwTxtFormatter::CtorInitTxtFormatter( SwTxtFrm *pNewFrm, SwTxtFormatInfo *pNewInf )
97 : : {
98 : 14873 : CtorInitTxtPainter( pNewFrm, pNewInf );
99 : 14873 : pInf = pNewInf;
100 : 14873 : pDropFmt = GetInfo().GetDropFmt();
101 : 14873 : pMulti = NULL;
102 : :
103 : 14873 : bOnceMore = sal_False;
104 : 14873 : bFlyInCntBase = sal_False;
105 : 14873 : bChanges = sal_False;
106 : 14873 : bTruncLines = sal_False;
107 : 14873 : nCntEndHyph = 0;
108 : 14873 : nCntMidHyph = 0;
109 : 14873 : nLeftScanIdx = STRING_LEN;
110 : 14873 : nRightScanIdx = 0;
111 : 14873 : m_nHintEndIndex = 0;
112 : :
113 [ - + ]: 14873 : if( nStart > GetInfo().GetTxt().Len() )
114 : : {
115 : : OSL_ENSURE( !this, "+SwTxtFormatter::CTOR: bad offset" );
116 : 0 : nStart = GetInfo().GetTxt().Len();
117 : : }
118 : :
119 : 14873 : }
120 : :
121 : : /*************************************************************************
122 : : * SwTxtFormatter::DTOR
123 : : *************************************************************************/
124 : :
125 : 14873 : SwTxtFormatter::~SwTxtFormatter()
126 : : {
127 : : // Extremly unlikely, but still possible
128 : : // e.g.: field splits up, widows start to matter
129 [ - + ]: 14873 : if( GetInfo().GetRest() )
130 : : {
131 [ # # ][ # # ]: 0 : delete GetInfo().GetRest();
132 : 0 : GetInfo().SetRest(0);
133 : : }
134 [ - + ]: 14873 : }
135 : :
136 : : /*************************************************************************
137 : : * SwTxtFormatter::Insert()
138 : : *************************************************************************/
139 : :
140 : 6910 : void SwTxtFormatter::Insert( SwLineLayout *pLay )
141 : : {
142 : : // Insert BEHIND the current element
143 [ + - ]: 6910 : if ( pCurr )
144 : : {
145 : 6910 : pLay->SetNext( pCurr->GetNext() );
146 : 6910 : pCurr->SetNext( pLay );
147 : : }
148 : : else
149 : 0 : pCurr = pLay;
150 : 6910 : }
151 : :
152 : : /*************************************************************************
153 : : * SwTxtFormatter::GetFrmRstHeight()
154 : : *************************************************************************/
155 : :
156 : 0 : KSHORT SwTxtFormatter::GetFrmRstHeight() const
157 : : {
158 : : // We want the rest height relative to the page.
159 : : // If we're in a table, then pFrm->GetUpper() is not the page.
160 : : //
161 : : // GetFrmRstHeight() is being called with Ftn.
162 : : // Wrong: const SwFrm *pUpper = pFrm->GetUpper();
163 : 0 : const SwFrm *pPage = (const SwFrm*)pFrm->FindPageFrm();
164 : 0 : const SwTwips nHeight = pPage->Frm().Top()
165 : 0 : + pPage->Prt().Top()
166 : 0 : + pPage->Prt().Height() - Y();
167 [ # # ]: 0 : if( 0 > nHeight )
168 : 0 : return pCurr->Height();
169 : : else
170 : 0 : return KSHORT( nHeight );
171 : : }
172 : :
173 : : /*************************************************************************
174 : : * SwTxtFormatter::UnderFlow()
175 : : *************************************************************************/
176 : :
177 : 0 : SwLinePortion *SwTxtFormatter::UnderFlow( SwTxtFormatInfo &rInf )
178 : : {
179 : : // Save values and initialize rInf
180 : 0 : SwLinePortion *pUnderFlow = rInf.GetUnderFlow();
181 [ # # ]: 0 : if( !pUnderFlow )
182 : 0 : return 0;
183 : :
184 : : // We format backwards, i.e. attribute changes can happen the next
185 : : // line again.
186 : : // Can be seen in 8081.sdw, if you enter text in the first line
187 : :
188 : 0 : const xub_StrLen nSoftHyphPos = rInf.GetSoftHyphPos();
189 : 0 : const xub_StrLen nUnderScorePos = rInf.GetUnderScorePos();
190 : :
191 : : // Save flys and set to 0, or else segmentation fault
192 : : // Not ClearFly(rInf) !
193 : 0 : SwFlyPortion *pFly = rInf.GetFly();
194 : 0 : rInf.SetFly( 0 );
195 : :
196 : 0 : FeedInf( rInf );
197 : 0 : rInf.SetLast( pCurr );
198 : : // pUnderFlow does not need to be deleted, because it will drown in the following
199 : : // Truncate()
200 : 0 : rInf.SetUnderFlow(0);
201 : 0 : rInf.SetSoftHyphPos( nSoftHyphPos );
202 : 0 : rInf.SetUnderScorePos( nUnderScorePos );
203 : 0 : rInf.SetPaintOfst( GetLeftMargin() );
204 : :
205 : : // We look for the portion with the under-flow position
206 : 0 : SwLinePortion *pPor = pCurr->GetFirstPortion();
207 [ # # ]: 0 : if( pPor != pUnderFlow )
208 : : {
209 : : // pPrev will be the last portion before pUnderFlow,
210 : : // which still has a real width.
211 : : // Exception: SoftHyphPortions must not be forgotten, of course!
212 : : // Although they don't have a width.
213 : 0 : SwLinePortion *pTmpPrev = pPor;
214 [ # # ][ # # ]: 0 : while( pPor && pPor != pUnderFlow )
[ # # ]
215 : : {
216 [ # # # # : 0 : if( !pPor->IsKernPortion() &&
# # ][ # # ]
217 : 0 : ( pPor->Width() || pPor->IsSoftHyphPortion() ) )
218 : : {
219 [ # # ]: 0 : while( pTmpPrev != pPor )
220 : : {
221 : 0 : pTmpPrev->Move( rInf );
222 : 0 : rInf.SetLast( pTmpPrev );
223 : 0 : pTmpPrev = pTmpPrev->GetPortion();
224 : : OSL_ENSURE( pTmpPrev, "UnderFlow: Loosing control!" );
225 : : };
226 : : }
227 : 0 : pPor = pPor->GetPortion();
228 : : }
229 : 0 : pPor = pTmpPrev;
230 [ # # # # : 0 : if( pPor && // Flies + Initialen werden nicht beim UnderFlow mitgenommen
# # # # ]
[ # # ]
231 : 0 : ( pPor->IsFlyPortion() || pPor->IsDropPortion() ||
232 : 0 : pPor->IsFlyCntPortion() ) )
233 : : {
234 : 0 : pPor->Move( rInf );
235 : 0 : rInf.SetLast( pPor );
236 : 0 : rInf.SetStopUnderFlow( sal_True );
237 : 0 : pPor = pUnderFlow;
238 : : }
239 : : }
240 : :
241 : : // What? The under-flow portion is not in the portion chain?
242 : : OSL_ENSURE( pPor, "SwTxtFormatter::UnderFlow: overflow but underflow" );
243 : :
244 : : // OD 2004-05-26 #i29529# - correction: no delete of footnotes
245 : : // if( rInf.IsFtnInside() && pPor && !rInf.IsQuick() )
246 : : // {
247 : : // SwLinePortion *pTmp = pPor->GetPortion();
248 : : // while( pTmp )
249 : : // {
250 : : // if( pTmp->IsFtnPortion() )
251 : : // ((SwFtnPortion*)pTmp)->ClearFtn();
252 : : // pTmp = pTmp->GetPortion();
253 : : // }
254 : : // }
255 : :
256 : : /*--------------------------------------------------
257 : : * Snapshot
258 : : * --------------------------------------------------*/
259 [ # # ]: 0 : if ( pPor==rInf.GetLast() )
260 : : {
261 : : // We end up here, if the portion triggering the under-flow
262 : : // spans over the whole line. E.g. if a word spans across
263 : : // multiple lines and flows into a fly in the second line.
264 : 0 : rInf.SetFly( pFly );
265 : 0 : pPor->Truncate();
266 : 0 : return pPor; // Is that enough?
267 : : }
268 : : /*---------------------------------------------------
269 : : * End the snapshot
270 : : * --------------------------------------------------*/
271 : :
272 : : // X + Width == 0 with SoftHyph > Line?!
273 [ # # ][ # # ]: 0 : if( !pPor || !(rInf.X() + pPor->Width()) )
[ # # ]
274 : : {
275 [ # # ]: 0 : delete pFly;
276 : 0 : return 0;
277 : : }
278 : :
279 : : // Preparing for Format()
280 : : // We need to chip off the chain behind pLast, because we Insert after the Format()
281 : 0 : SeekAndChg( rInf );
282 : :
283 : : // line width is adjusted, so that pPor does not fit to current
284 : : // line anymore
285 [ # # ]: 0 : rInf.Width( (sal_uInt16)(rInf.X() + (pPor->Width() ? pPor->Width() - 1 : 0)) );
286 : 0 : rInf.SetLen( pPor->GetLen() );
287 : 0 : rInf.SetFull( sal_False );
288 [ # # ]: 0 : if( pFly )
289 : : {
290 : : // We need to recalculate the FlyPortion due to the following reason:
291 : : // If the base line is lowered by a big font in the middle of the line,
292 : : // causing overlapping with a fly, the FlyPortion has a wrong size/fixed
293 : : // size.
294 : 0 : rInf.SetFly( pFly );
295 : 0 : CalcFlyWidth( rInf );
296 : : }
297 : 0 : rInf.GetLast()->SetPortion(0);
298 : :
299 : : // The SwLineLayout is an exception to this, which splits at the first
300 : : // portion change.
301 : : // Here inly the other way around:
302 [ # # ]: 0 : if( rInf.GetLast() == pCurr )
303 : : {
304 [ # # ][ # # ]: 0 : if( pPor->InTxtGrp() && !pPor->InExpGrp() )
[ # # ]
305 : : {
306 : 0 : MSHORT nOldWhich = pCurr->GetWhichPor();
307 : 0 : *(SwLinePortion*)pCurr = *pPor;
308 : 0 : pCurr->SetPortion( pPor->GetPortion() );
309 : 0 : pCurr->SetWhichPor( nOldWhich );
310 : 0 : pPor->SetPortion( 0 );
311 [ # # ]: 0 : delete pPor;
312 : 0 : pPor = pCurr;
313 : : }
314 : : }
315 : 0 : pPor->Truncate();
316 : 0 : SwLinePortion *const pRest( rInf.GetRest() );
317 [ # # # # ]: 0 : if (pRest && pRest->InFldGrp() &&
[ # # ][ # # ]
318 : 0 : static_cast<SwFldPortion*>(pRest)->IsNoLength())
319 : : {
320 : : // HACK: decrement again, so we pick up the suffix in next line!
321 : 0 : --m_nHintEndIndex;
322 : : }
323 [ # # ]: 0 : delete pRest;
324 : 0 : rInf.SetRest(0);
325 : 0 : return pPor;
326 : : }
327 : :
328 : : /*************************************************************************
329 : : * SwTxtFormatter::InsertPortion()
330 : : *************************************************************************/
331 : :
332 : 55613 : void SwTxtFormatter::InsertPortion( SwTxtFormatInfo &rInf,
333 : : SwLinePortion *pPor ) const
334 : : {
335 : : // The new portion is inserted, but everything's different for
336 : : // LineLayout ...
337 [ + + ]: 55613 : if( pPor == pCurr )
338 : : {
339 [ + + ]: 49260 : if ( pCurr->GetPortion() )
340 : : {
341 : 1380 : pPor = pCurr->GetPortion();
342 : : }
343 : :
344 : : // #i112181#
345 [ + + ][ + - ]: 49260 : rInf.SetOtherThanFtnInside( rInf.IsOtherThanFtnInside() || !pPor->IsFtnPortion() );
346 : : }
347 : : else
348 : : {
349 : 6353 : SwLinePortion *pLast = rInf.GetLast();
350 [ + + ]: 6353 : if( pLast->GetPortion() )
351 : : {
352 [ + + ]: 210 : while( pLast->GetPortion() )
353 : 140 : pLast = pLast->GetPortion();
354 : 70 : rInf.SetLast( pLast );
355 : : }
356 : 6353 : pLast->Insert( pPor );
357 : :
358 [ + + ][ + + ]: 6353 : rInf.SetOtherThanFtnInside( rInf.IsOtherThanFtnInside() || !pPor->IsFtnPortion() );
359 : :
360 : : // Adjust maxima
361 [ + + ]: 6353 : if( pCurr->Height() < pPor->Height() )
362 : 1335 : pCurr->Height( pPor->Height() );
363 [ + + ]: 6353 : if( pCurr->GetAscent() < pPor->GetAscent() )
364 : 614 : pCurr->SetAscent( pPor->GetAscent() );
365 : : }
366 : :
367 : : // Sometimes chains are constructed (e.g. by hyphenate)
368 : 55613 : rInf.SetLast( pPor );
369 [ + + ]: 112760 : while( pPor )
370 : : {
371 : 57147 : pPor->Move( rInf );
372 : 57147 : rInf.SetLast( pPor );
373 : 57147 : pPor = pPor->GetPortion();
374 : : }
375 : 55613 : }
376 : :
377 : : /*************************************************************************
378 : : * SwTxtFormatter::BuildPortion()
379 : : *************************************************************************/
380 : :
381 : 53784 : void SwTxtFormatter::BuildPortions( SwTxtFormatInfo &rInf )
382 : : {
383 : : OSL_ENSURE( rInf.GetTxt().Len() < STRING_LEN,
384 : : "SwTxtFormatter::BuildPortions: bad text length in info" );
385 : :
386 : 53784 : rInf.ChkNoHyph( CntEndHyph(), CntMidHyph() );
387 : :
388 : : // First NewTxtPortion() decides whether pCurr ends up in pPor.
389 : : // We need to make sure that the font is being set in any case.
390 : : // This is done automatically in CalcAscent.
391 : 53784 : rInf.SetLast( pCurr );
392 : 53784 : rInf.ForcedLeftMargin( 0 );
393 : :
394 : : OSL_ENSURE( pCurr->FindLastPortion() == pCurr, "pLast supposed to equal pCurr" );
395 : :
396 [ + - ][ + - ]: 53784 : if( !pCurr->GetAscent() && !pCurr->Height() )
[ + - ]
397 : 53784 : CalcAscent( rInf, pCurr );
398 : :
399 : 53784 : SeekAndChg( rInf );
400 : :
401 : : // Width() is shortened in CalcFlyWidth if we have a FlyPortion
402 : : OSL_ENSURE( !rInf.X() || pMulti, "SwTxtFormatter::BuildPortion X=0?" );
403 : 53784 : CalcFlyWidth( rInf );
404 : 53784 : SwFlyPortion *pFly = rInf.GetFly();
405 [ + + ]: 53784 : if( pFly )
406 : : {
407 [ + + ]: 382 : if ( 0 < pFly->Fix() )
408 : 344 : ClearFly( rInf );
409 : : else
410 : 38 : rInf.SetFull(sal_True);
411 : : }
412 : :
413 : 53784 : SwLinePortion *pPor = NewPortion( rInf );
414 : :
415 : : // Asian grid stuff
416 [ - + ][ # # ]: 53784 : GETGRID( pFrm->FindPageFrm() )
[ - + ][ + - ]
417 : 0 : const sal_Bool bHasGrid = pGrid && rInf.SnapToGrid() &&
418 [ - + # # ]: 53784 : GRID_LINES_CHARS == pGrid->GetGridType();
[ # # ]
419 : :
420 : 53784 : const SwDoc *pDoc = rInf.GetTxtFrm()->GetNode()->GetDoc();
421 : : const sal_uInt16 nGridWidth = bHasGrid ?
422 [ # # ][ - + ]: 53784 : GETGRIDWIDTH(pGrid,pDoc) : 0; //for textgrid refactor
423 : :
424 : : // used for grid mode only:
425 : : // the pointer is stored, because after formatting of non-asian text,
426 : : // the width of the kerning portion has to be adjusted
427 : 53784 : SwKernPortion* pGridKernPortion = 0;
428 : :
429 : : sal_Bool bFull;
430 : 53784 : SwTwips nUnderLineStart = 0;
431 : 53784 : rInf.Y( Y() );
432 : :
433 [ + + ][ + - ]: 109397 : while( pPor && !rInf.IsStop() )
[ + + ]
434 : : {
435 : : OSL_ENSURE( rInf.GetLen() < STRING_LEN &&
436 : : rInf.GetIdx() <= rInf.GetTxt().Len(),
437 : : "SwTxtFormatter::BuildPortions: bad length in info" );
438 : :
439 : : // We have to check the script for fields in order to set the
440 : : // correct nActual value for the font.
441 [ + + ]: 55613 : if( pPor->InFldGrp() )
442 : 1753 : ((SwFldPortion*)pPor)->CheckScript( rInf );
443 : :
444 [ + - ][ + + : 223167 : if( ! bHasGrid && rInf.HasScriptSpace() &&
+ - + + +
+ + + ]
[ + + ]
445 : 111048 : rInf.GetLast() && rInf.GetLast()->InTxtGrp() &&
446 : 56506 : rInf.GetLast()->Width() && !rInf.GetLast()->InNumberGrp() )
447 : : {
448 : 1544 : sal_uInt8 nNxtActual = rInf.GetFont()->GetActual();
449 : 1544 : sal_uInt8 nLstActual = nNxtActual;
450 : 1544 : sal_uInt16 nLstHeight = (sal_uInt16)rInf.GetFont()->GetHeight();
451 : 1544 : sal_Bool bAllowBefore = sal_False;
452 : 1544 : sal_Bool bAllowBehind = sal_False;
453 : 1544 : const CharClass& rCC = GetAppCharClass();
454 : :
455 : : // are there any punctuation characters on both sides
456 : : // of the kerning portion?
457 [ + + ]: 1544 : if ( pPor->InFldGrp() )
458 : : {
459 [ + - ]: 555 : XubString aAltTxt;
460 [ + - ]: 1110 : if ( ((SwFldPortion*)pPor)->GetExpTxt( rInf, aAltTxt ) &&
[ + - + + ]
[ + + ]
461 : 555 : aAltTxt.Len() )
462 : : {
463 [ + - ]: 166 : bAllowBehind = rCC.isLetterNumeric( aAltTxt, 0 );
464 : :
465 : 166 : const SwFont* pTmpFnt = ((SwFldPortion*)pPor)->GetFont();
466 [ + + ]: 166 : if ( pTmpFnt )
467 : 2 : nNxtActual = pTmpFnt->GetActual();
468 [ + - ]: 555 : }
469 : : }
470 : : else
471 : 989 : bAllowBehind = rCC.isLetterNumeric( rInf.GetTxt(), rInf.GetIdx() );
472 : :
473 : 1544 : const SwLinePortion* pLast = rInf.GetLast();
474 [ + - ][ + + ]: 1544 : if ( bAllowBehind && pLast )
475 : : {
476 [ + + ]: 854 : if ( pLast->InFldGrp() )
477 : : {
478 [ + - ]: 152 : XubString aAltTxt;
479 [ + - ]: 304 : if ( ((SwFldPortion*)pLast)->GetExpTxt( rInf, aAltTxt ) &&
[ + - + - ]
[ + - ]
480 : 152 : aAltTxt.Len() )
481 : : {
482 [ + - ]: 152 : bAllowBefore = rCC.isLetterNumeric( aAltTxt, aAltTxt.Len() - 1 );
483 : :
484 : 152 : const SwFont* pTmpFnt = ((SwFldPortion*)pLast)->GetFont();
485 [ - + ]: 152 : if ( pTmpFnt )
486 : : {
487 : 0 : nLstActual = pTmpFnt->GetActual();
488 [ # # ]: 0 : nLstHeight = (sal_uInt16)pTmpFnt->GetHeight();
489 : : }
490 [ + - ]: 152 : }
491 : : }
492 [ + - ]: 702 : else if ( rInf.GetIdx() )
493 : : {
494 : 702 : bAllowBefore = rCC.isLetterNumeric( rInf.GetTxt(), rInf.GetIdx() - 1 );
495 : : // Note: ScriptType returns values in [1,4]
496 [ + + ]: 702 : if ( bAllowBefore )
497 : 576 : nLstActual = pScriptInfo->ScriptType( rInf.GetIdx() - 1 ) - 1;
498 : : }
499 : :
500 : 854 : nLstHeight /= 5;
501 : : // does the kerning portion still fit into the line?
502 [ + + ][ - + ]: 854 : if( bAllowBefore && ( nLstActual != nNxtActual ) &&
[ # # # # ]
[ - + ]
503 : 0 : nLstHeight && rInf.X() + nLstHeight <= rInf.Width() )
504 : : {
505 : : SwKernPortion* pKrn =
506 : : new SwKernPortion( *rInf.GetLast(), nLstHeight,
507 [ # # ][ # # ]: 0 : pLast->InFldGrp() && pPor->InFldGrp() );
[ # # ]
508 : 0 : rInf.GetLast()->SetPortion( NULL );
509 : 0 : InsertPortion( rInf, pKrn );
510 : : }
511 : : }
512 : : }
513 [ - + ][ # # ]: 54069 : else if ( bHasGrid && ! pGridKernPortion && ! pMulti )
[ # # ]
514 : : {
515 : : // insert a grid kerning portion
516 [ # # ]: 0 : if ( ! pGridKernPortion )
517 : 0 : pGridKernPortion = pPor->IsKernPortion() ?
518 : : (SwKernPortion*)pPor :
519 [ # # ][ # # ]: 0 : new SwKernPortion( *pCurr );
520 : :
521 : : // if we have a new GridKernPortion, we initially calculate
522 : : // its size so that its ends on the grid
523 : 0 : const SwPageFrm* pPageFrm = pFrm->FindPageFrm();
524 : 0 : const SwLayoutFrm* pBody = pPageFrm->FindBodyCont();
525 [ # # ][ # # ]: 0 : SWRECTFN( pPageFrm )
[ # # ][ # # ]
526 : :
527 : : const long nGridOrigin = pBody ?
528 [ # # ]: 0 : (pBody->*fnRect->fnGetPrtLeft)() :
529 [ # # ][ # # ]: 0 : (pPageFrm->*fnRect->fnGetPrtLeft)();
530 : :
531 : 0 : SwTwips nStartX = rInf.X() + GetLeftMargin();
532 [ # # ]: 0 : if ( bVert )
533 : : {
534 : 0 : Point aPoint( nStartX, 0 );
535 [ # # ]: 0 : pFrm->SwitchHorizontalToVertical( aPoint );
536 : 0 : nStartX = aPoint.Y();
537 : : }
538 : :
539 : 0 : const SwTwips nOfst = nStartX - nGridOrigin;
540 [ # # ]: 0 : if ( nOfst )
541 : : {
542 : : const sal_uLong i = ( nOfst > 0 ) ?
543 : : ( ( nOfst - 1 ) / nGridWidth + 1 ) :
544 [ # # ]: 0 : 0;
545 : 0 : const SwTwips nKernWidth = i * nGridWidth - nOfst;
546 : 0 : const SwTwips nRestWidth = rInf.Width() - rInf.X();
547 : :
548 [ # # ]: 0 : if ( nKernWidth <= nRestWidth )
549 : 0 : pGridKernPortion->Width( (sal_uInt16)nKernWidth );
550 : : }
551 : :
552 [ # # ]: 0 : if ( pGridKernPortion != pPor )
553 : 0 : InsertPortion( rInf, pGridKernPortion );
554 : : }
555 : :
556 : : // the multi-portion has it's own format function
557 [ + + ][ - + ]: 55613 : if( pPor->IsMultiPortion() && ( !pMulti || pMulti->IsBidi() ) )
[ # # ][ + + ]
558 : 356 : bFull = BuildMultiPortion( rInf, *((SwMultiPortion*)pPor) );
559 : : else
560 : 55257 : bFull = pPor->Format( rInf );
561 : :
562 [ + + ][ + - ]: 55613 : if( rInf.IsRuby() && !rInf.GetRest() )
[ + + ]
563 : 336 : bFull = sal_True;
564 : :
565 : : // if we are underlined, we store the beginning of this underlined
566 : : // segment for repaint optimization
567 [ + + ][ + + ]: 55613 : if ( UNDERLINE_NONE != pFnt->GetUnderline() && ! nUnderLineStart )
[ + + ]
568 : 737 : nUnderLineStart = GetLeftMargin() + rInf.X();
569 : :
570 [ + + ]: 55613 : if ( pPor->IsFlyPortion() )
571 : 119 : pCurr->SetFly( sal_True );
572 : : // some special cases, where we have to take care for the repaint
573 : : // offset:
574 : : // 1. Underlined portions due to special underline feature
575 : : // 2. Right Tab
576 : : // 3. BidiPortions
577 : : // 4. other Multiportions
578 : : // 5. DropCaps
579 : : // 6. Grid Mode
580 [ + + ][ + + ]: 58289 : else if ( ( ! rInf.GetPaintOfst() || nUnderLineStart < rInf.GetPaintOfst() ) &&
[ + + + +
+ - + + +
+ + + ]
[ + + ]
581 : : // 1. Underlined portions
582 : : nUnderLineStart &&
583 : : // reformat is at end of an underlined portion and next portion
584 : : // is not underlined
585 : 619 : ( ( rInf.GetReformatStart() == rInf.GetIdx() &&
586 : 459 : UNDERLINE_NONE == pFnt->GetUnderline()
587 : : ) ||
588 : : // reformat is inside portion and portion is underlined
589 : 619 : ( rInf.GetReformatStart() >= rInf.GetIdx() &&
590 : 599 : rInf.GetReformatStart() <= rInf.GetIdx() + pPor->GetLen() &&
591 : 499 : UNDERLINE_NONE != pFnt->GetUnderline() ) ) )
592 : 495 : rInf.SetPaintOfst( nUnderLineStart );
593 [ + + + + : 273598 : else if ( ! rInf.GetPaintOfst() &&
+ + + + +
- + - + +
+ + + + ]
[ - + # # ]
[ + + ]
594 : : // 2. Right Tab
595 : 54680 : ( ( pPor->InTabGrp() && !pPor->IsTabLeftPortion() ) ||
596 : : // 3. BidiPortions
597 : 54643 : ( pPor->IsMultiPortion() && ((SwMultiPortion*)pPor)->IsBidi() ) ||
598 : : // 4. Multi Portion and 5. Drop Caps
599 : 108954 : ( ( pPor->IsDropPortion() || pPor->IsMultiPortion() ) &&
600 : 166 : rInf.GetReformatStart() >= rInf.GetIdx() &&
601 : 156 : rInf.GetReformatStart() <= rInf.GetIdx() + pPor->GetLen() )
602 : : // 6. Grid Mode
603 : 0 : || ( bHasGrid && SW_CJK != pFnt->GetActual() )
604 : : )
605 : : )
606 : : // we store the beginning of the critical portion as our
607 : : // paint offset
608 : 88 : rInf.SetPaintOfst( GetLeftMargin() + rInf.X() );
609 : :
610 : : // under one of these conditions we are allowed to delete the
611 : : // start of the underline portion
612 [ + + ]: 55613 : if ( IsUnderlineBreak( *pPor, *pFnt ) )
613 : 55304 : nUnderLineStart = 0;
614 : :
615 [ + + ]: 55969 : if( pPor->IsFlyCntPortion() || ( pPor->IsMultiPortion() &&
[ + + - + ]
[ + + ]
616 : 356 : ((SwMultiPortion*)pPor)->HasFlyInCntnt() ) )
617 : 1290 : SetFlyInCntBase();
618 : : // bUnderFlow needs to be reset or we wrap again at the next softhyphen
619 [ + + ]: 55613 : if ( !bFull )
620 : : {
621 : 14023 : rInf.ClrUnderFlow();
622 [ + + ][ + + : 37559 : if( ! bHasGrid && rInf.HasScriptSpace() && pPor->InTxtGrp() &&
+ + + + ]
[ + + ][ + - ]
623 : 23536 : pPor->GetLen() && !pPor->InFldGrp() )
624 : : {
625 : : // The distance between two different scripts is set
626 : : // to 20% of the fontheight.
627 : 10639 : xub_StrLen nTmp = rInf.GetIdx() + pPor->GetLen();
628 [ - + ]: 19555 : if( nTmp == pScriptInfo->NextScriptChg( nTmp - 1 ) &&
[ + + - + ]
629 : 8916 : nTmp != rInf.GetTxt().Len() )
630 : : {
631 : 0 : sal_uInt16 nDist = (sal_uInt16)(rInf.GetFont()->GetHeight()/5);
632 : :
633 [ # # ]: 0 : if( nDist )
634 : : {
635 : : // we do not want a kerning portion if any end
636 : : // would be a punctuation character
637 : 0 : const CharClass& rCC = GetAppCharClass();
638 [ # # ]: 0 : if ( rCC.isLetterNumeric( rInf.GetTxt(), nTmp - 1 ) &&
[ # # # # ]
639 : 0 : rCC.isLetterNumeric( rInf.GetTxt(), nTmp ) )
640 : : {
641 : : // does the kerning portion still fit into the line?
642 [ # # ]: 0 : if ( rInf.X() + pPor->Width() + nDist <= rInf.Width() )
643 [ # # ]: 0 : new SwKernPortion( *pPor, nDist );
644 : : else
645 : 0 : bFull = sal_True;
646 : : }
647 : : }
648 : : }
649 : : }
650 : : }
651 : :
652 [ - + ][ # # ]: 55613 : if ( bHasGrid && pPor != pGridKernPortion && ! pMulti )
[ # # ]
653 : : {
654 : 0 : xub_StrLen nTmp = rInf.GetIdx() + pPor->GetLen();
655 : 0 : const SwTwips nRestWidth = rInf.Width() - rInf.X() - pPor->Width();
656 : :
657 : 0 : const sal_uInt8 nCurrScript = pFnt->GetActual(); // pScriptInfo->ScriptType( rInf.GetIdx() );
658 : 0 : const sal_uInt8 nNextScript = nTmp >= rInf.GetTxt().Len() ?
659 : : SW_CJK :
660 [ # # ]: 0 : SwScriptInfo::WhichFont( nTmp, 0, pScriptInfo );
661 : :
662 : : // snap non-asian text to grid if next portion is ASIAN or
663 : : // there are no more portions in this line
664 : : // be careful when handling an underflow event: the gridkernportion
665 : : // could have been deleted
666 [ # # ]: 0 : if ( nRestWidth > 0 && SW_CJK != nCurrScript &&
[ # # # # ]
[ # # ][ # # ]
[ # # ]
667 : 0 : ! rInf.IsUnderFlow() && ( bFull || SW_CJK == nNextScript ) )
668 : : {
669 : : OSL_ENSURE( pGridKernPortion, "No GridKernPortion available" );
670 : :
671 : : // calculate size
672 : 0 : SwLinePortion* pTmpPor = pGridKernPortion->GetPortion();
673 : 0 : sal_uInt16 nSumWidth = pPor->Width();
674 [ # # ]: 0 : while ( pTmpPor )
675 : : {
676 : 0 : nSumWidth = nSumWidth + pTmpPor->Width();
677 : 0 : pTmpPor = pTmpPor->GetPortion();
678 : : }
679 : :
680 : : const sal_uInt16 i = nSumWidth ?
681 : : ( nSumWidth - 1 ) / nGridWidth + 1 :
682 [ # # ]: 0 : 0;
683 : 0 : const SwTwips nTmpWidth = i * nGridWidth;
684 : : const SwTwips nKernWidth = Min( (SwTwips)(nTmpWidth - nSumWidth),
685 : 0 : nRestWidth );
686 : 0 : const sal_uInt16 nKernWidth_1 = (sal_uInt16)(nKernWidth / 2);
687 : :
688 : : OSL_ENSURE( nKernWidth <= nRestWidth,
689 : : "Not enough space left for adjusting non-asian text in grid mode" );
690 : :
691 : 0 : pGridKernPortion->Width( pGridKernPortion->Width() + nKernWidth_1 );
692 : 0 : rInf.X( rInf.X() + nKernWidth_1 );
693 : :
694 [ # # ]: 0 : if ( ! bFull )
695 : : new SwKernPortion( *pPor, (short)(nKernWidth - nKernWidth_1),
696 [ # # ]: 0 : sal_False, sal_True );
697 : :
698 : 0 : pGridKernPortion = 0;
699 : : }
700 [ # # ][ # # : 0 : else if ( pPor->IsMultiPortion() || pPor->InFixMargGrp() ||
# # # # #
# ][ # # ]
[ # # ]
701 : 0 : pPor->IsFlyCntPortion() || pPor->InNumberGrp() ||
702 : 0 : pPor->InFldGrp() || nCurrScript != nNextScript )
703 : : // next portion should snap to grid
704 : 0 : pGridKernPortion = 0;
705 : : }
706 : :
707 : 55613 : rInf.SetFull( bFull );
708 : :
709 : : // Restportions from fields with multiple lines don't yet have the right ascent
710 [ + + + - : 59013 : if ( !pPor->GetLen() && !pPor->IsFlyPortion()
+ + + - ]
[ + + ][ + + ]
711 : 2624 : && !pPor->IsGrfNumPortion() && ! pPor->InNumberGrp()
712 : 776 : && !pPor->IsMultiPortion() )
713 : 776 : CalcAscent( rInf, pPor );
714 : :
715 : 55613 : InsertPortion( rInf, pPor );
716 : 55613 : pPor = NewPortion( rInf );
717 : : }
718 : :
719 [ + - ]: 53784 : if( !rInf.IsStop() )
720 : : {
721 : : // The last right centered, decimal tab
722 : 53784 : SwTabPortion *pLastTab = rInf.GetLastTab();
723 [ + + ]: 53784 : if( pLastTab )
724 : 2 : pLastTab->FormatEOL( rInf );
725 [ + - ][ + + ]: 53782 : else if( rInf.GetLast() && rInf.LastKernPortion() )
[ + + ]
726 : 256 : rInf.GetLast()->FormatEOL( rInf );
727 : : }
728 [ + + ]: 54146 : if( pCurr->GetPortion() && pCurr->GetPortion()->InNumberGrp()
[ + + - + ]
[ - + ]
729 : 362 : && ((SwNumberPortion*)pCurr->GetPortion())->IsHide() )
730 : 0 : rInf.SetNumDone( sal_False );
731 : :
732 : : // Delete fly in any case
733 : 53784 : ClearFly( rInf );
734 : :
735 : : // Reinit the tab overflow flag after the line
736 : 53784 : rInf.SetTabOverflow( sal_False );
737 : 53784 : }
738 : :
739 : : /*************************************************************************
740 : : * SwTxtFormatter::CalcAdjustLine()
741 : : *************************************************************************/
742 : :
743 : 52762 : void SwTxtFormatter::CalcAdjustLine( SwLineLayout *pCurrent )
744 : : {
745 [ + + ][ + - ]: 52762 : if( SVX_ADJUST_LEFT != GetAdjust() && !pMulti)
[ + + ]
746 : : {
747 : 953 : pCurrent->SetFormatAdj(sal_True);
748 [ + + ]: 953 : if( IsFlyInCntBase() )
749 : : {
750 : 3 : CalcAdjLine( pCurrent );
751 : : // For e.g. centered fly we need to switch the RefPoint
752 : : // That's why bAllWays = sal_True
753 : 3 : UpdatePos( pCurrent, GetTopLeft(), GetStart(), sal_True );
754 : : }
755 : : }
756 : 52762 : }
757 : :
758 : : /*************************************************************************
759 : : * SwTxtFormatter::CalcAscent()
760 : : *************************************************************************/
761 : :
762 : 108095 : void SwTxtFormatter::CalcAscent( SwTxtFormatInfo &rInf, SwLinePortion *pPor )
763 : : {
764 [ + + ][ + + ]: 108095 : if ( pPor->InFldGrp() && ((SwFldPortion*)pPor)->GetFont() )
[ + + ]
765 : : {
766 : : // Numbering + InterNetFlds can keep an own font, then their size is
767 : : // independent from hard attribute values
768 : 1215 : SwFont* pFldFnt = ((SwFldPortion*)pPor)->pFnt;
769 [ + - ]: 1215 : SwFontSave aSave( rInf, pFldFnt );
770 [ + - ]: 1215 : ((SwFldPortion*)pPor)->Height( pFldFnt->GetHeight( rInf.GetVsh(), *rInf.GetOut() ) );
771 [ + - ][ + - ]: 1215 : ((SwFldPortion*)pPor)->SetAscent( pFldFnt->GetAscent( rInf.GetVsh(), *rInf.GetOut() ) );
772 : : }
773 : : // #i89179#
774 : : // tab portion representing the list tab of a list label gets the
775 : : // same height and ascent as the corresponding number portion
776 [ + + ][ + + : 107924 : else if ( pPor->InTabGrp() && pPor->GetLen() == 0 &&
+ - + - +
- ][ + + ]
777 : 696 : rInf.GetLast() && rInf.GetLast()->InNumberGrp() &&
778 : 348 : static_cast<const SwNumberPortion*>(rInf.GetLast())->HasFont() )
779 : : {
780 : 348 : const SwLinePortion* pLast = rInf.GetLast();
781 : 348 : pPor->Height( pLast->Height() );
782 : 348 : pPor->SetAscent( pLast->GetAscent() );
783 : : }
784 : : else
785 : : {
786 : 106532 : const SwLinePortion *pLast = rInf.GetLast();
787 : : sal_Bool bChg;
788 : :
789 : : // In empty lines the attributes are switched on via SeekStart
790 : 106532 : const sal_Bool bFirstPor = rInf.GetLineStart() == rInf.GetIdx();
791 [ - + ]: 106532 : if ( pPor->IsQuoVadisPortion() )
792 : 0 : bChg = SeekStartAndChg( rInf, sal_True );
793 : : else
794 : : {
795 [ + + ]: 106532 : if( bFirstPor )
796 : : {
797 [ + + ]: 104297 : if( rInf.GetTxt().Len() )
798 : : {
799 [ + + ][ + + ]: 145184 : if ( pPor->GetLen() || !rInf.GetIdx()
[ - + # #
+ - ][ + - ]
800 : 0 : || ( pCurr != pLast && !pLast->IsFlyPortion() )
801 : 42709 : || !pCurr->IsRest() ) // instead of !rInf.GetRest()
802 : 102475 : bChg = SeekAndChg( rInf );
803 : : else
804 : 0 : bChg = SeekAndChgBefore( rInf );
805 : : }
806 [ - + ]: 1822 : else if ( pMulti )
807 : : // do not open attributes starting at 0 in empty multi
808 : : // portions (rotated numbering followed by a footnote
809 : : // can cause trouble, because the footnote attribute
810 : : // starts at 0, but if we open it, the attribute handler
811 : : // cannot handle it.
812 : 0 : bChg = sal_False;
813 : : else
814 : 1822 : bChg = SeekStartAndChg( rInf );
815 : : }
816 : : else
817 : 2235 : bChg = SeekAndChg( rInf );
818 : : }
819 [ + + ][ - + ]: 106532 : if( bChg || bFirstPor || !pPor->GetAscent()
[ # # # # ]
[ + - ]
820 : 0 : || !rInf.GetLast()->InTxtGrp() )
821 : : {
822 : 106532 : pPor->SetAscent( rInf.GetAscent() );
823 : 106532 : pPor->Height( rInf.GetTxtHeight() );
824 : : }
825 : : else
826 : : {
827 : 0 : pPor->Height( pLast->Height() );
828 : 0 : pPor->SetAscent( pLast->GetAscent() );
829 : : }
830 : : }
831 : 108095 : }
832 : :
833 : : /*************************************************************************
834 : : * class SwMetaPortion
835 : : *************************************************************************/
836 : :
837 [ - + ]: 1152 : class SwMetaPortion : public SwTxtPortion
838 : : {
839 : : public:
840 : 576 : inline SwMetaPortion() { SetWhichPor( POR_META ); }
841 : : virtual void Paint( const SwTxtPaintInfo &rInf ) const;
842 : : // OUTPUT_OPERATOR
843 : : };
844 : :
845 : : //CLASSIO( SwMetaPortion )
846 : :
847 : : /*************************************************************************
848 : : * virtual SwMetaPortion::Paint()
849 : : *************************************************************************/
850 : :
851 : 602 : void SwMetaPortion::Paint( const SwTxtPaintInfo &rInf ) const
852 : : {
853 [ + - ]: 602 : if ( Width() )
854 : : {
855 : 602 : rInf.DrawViewOpt( *this, POR_META );
856 : 602 : SwTxtPortion::Paint( rInf );
857 : : }
858 : 602 : }
859 : :
860 : :
861 : : /*************************************************************************
862 : : * SwTxtFormatter::WhichTxtPor()
863 : : *************************************************************************/
864 : :
865 : 51271 : SwTxtPortion *SwTxtFormatter::WhichTxtPor( SwTxtFormatInfo &rInf ) const
866 : : {
867 : 51271 : SwTxtPortion *pPor = 0;
868 [ + + ]: 51271 : if( GetFnt()->IsTox() )
869 [ + - ]: 42 : pPor = new SwToxPortion;
870 : : else
871 : : {
872 [ + + ]: 51229 : if( GetFnt()->IsRef() )
873 [ + - ]: 36 : pPor = new SwRefPortion;
874 [ + + ]: 51193 : else if (GetFnt()->IsMeta())
875 : : {
876 [ + - ]: 576 : pPor = new SwMetaPortion;
877 : : }
878 : : else
879 : : {
880 : : // Only at the End!
881 : : // If pCurr does not have a width, it can however aready have content.
882 : : // E.g. for non-displayable characters
883 [ + + ]: 50617 : if( rInf.GetLen() > 0 )
884 : : {
885 [ + + ]: 50052 : if( rInf.GetTxt().GetChar(rInf.GetIdx())==CH_TXT_ATR_FIELDSTART )
886 [ + - ]: 18 : pPor = new SwFieldMarkPortion();
887 [ + + ]: 50034 : else if( rInf.GetTxt().GetChar(rInf.GetIdx())==CH_TXT_ATR_FIELDEND )
888 [ + - ]: 18 : pPor = new SwFieldMarkPortion();
889 [ + + ]: 50016 : else if( rInf.GetTxt().GetChar(rInf.GetIdx())==CH_TXT_ATR_FORMELEMENT )
890 [ + - ]: 3 : pPor = new SwFieldFormPortion();
891 : : }
892 [ + + ]: 50617 : if( !pPor )
893 : : {
894 [ + + ][ + + ]: 50578 : if( !rInf.X() && !pCurr->GetPortion() && !pCurr->GetLen() && !GetFnt()->IsURL() )
[ + - ][ + - ]
[ + + ]
895 : 49260 : pPor = pCurr;
896 : : else
897 : : {
898 [ + - ]: 1318 : pPor = new SwTxtPortion;
899 [ - + ]: 1318 : if( GetFnt()->IsURL() )
900 : 0 : pPor->SetWhichPor( POR_URL );
901 : : }
902 : : }
903 : : }
904 : : }
905 : 51271 : return pPor;
906 : : }
907 : :
908 : : /*************************************************************************
909 : : * SwTxtFormatter::NewTxtPortion()
910 : : *************************************************************************/
911 : : // We calculate the length, the following portion limits are defined:
912 : : // 1) Tabs
913 : : // 2) Linebreaks
914 : : // 3) CH_TXTATR_BREAKWORD / CH_TXTATR_INWORD
915 : : // 4) next attribute change
916 : :
917 : 51271 : SwTxtPortion *SwTxtFormatter::NewTxtPortion( SwTxtFormatInfo &rInf )
918 : : {
919 : : // If we're at the line's beginning, we take pCurr
920 : : // If pCurr is not derived from SwTxtPortion, we need to duplicate
921 : 51271 : Seek( rInf.GetIdx() );
922 : 51271 : SwTxtPortion *pPor = WhichTxtPor( rInf );
923 : :
924 : : // until next attribute change:
925 : 51271 : const xub_StrLen nNextAttr = GetNextAttr();
926 : 51271 : xub_StrLen nNextChg = Min( nNextAttr, rInf.GetTxt().Len() );
927 : :
928 : : // end of script type:
929 : 51271 : const xub_StrLen nNextScript = pScriptInfo->NextScriptChg( rInf.GetIdx() );
930 : 51271 : nNextChg = Min( nNextChg, nNextScript );
931 : :
932 : : // end of direction:
933 : 51271 : const xub_StrLen nNextDir = pScriptInfo->NextDirChg( rInf.GetIdx() );
934 : 51271 : nNextChg = Min( nNextChg, nNextDir );
935 : :
936 : : // Turbo boost:
937 : : // We assume that a font's characters are not larger than twice
938 : : // as wide as heigh.
939 : : // Very crazy: We need to take the ascent into account.
940 : : //
941 : : // Mind the trap! GetSize() contains the wished-for height, the real height
942 : : // is only known in CalcAscent!
943 : : //
944 : : // The ratio is even crazier: a blank in Times New Roman has an ascent of
945 : : // 182, a height of 200 and a width of 53!
946 : : // It follows that a line with a lot of blanks is processed incorrectly.
947 : : // Therefore we increase from factor 2 to 8 (due to negative kerning).
948 : :
949 : 51271 : pPor->SetLen(1);
950 : 51271 : CalcAscent( rInf, pPor );
951 : :
952 : 51271 : const SwFont* pTmpFnt = rInf.GetFont();
953 : 51271 : KSHORT nExpect = Min( KSHORT( ((Font *)pTmpFnt)->GetSize().Height() ),
954 : 102542 : KSHORT( pPor->GetAscent() ) ) / 8;
955 [ - + ]: 51271 : if ( !nExpect )
956 : 0 : nExpect = 1;
957 : 51271 : nExpect = (sal_uInt16)(rInf.GetIdx() + ((rInf.Width() - rInf.X()) / nExpect));
958 [ + + ][ + + ]: 51271 : if( nExpect > rInf.GetIdx() && nNextChg > nExpect )
[ + - ]
959 : 28743 : nNextChg = Min( nExpect, rInf.GetTxt().Len() );
960 : :
961 : : // we keep an invariant during method calls:
962 : : // there are no portion ending characters like hard spaces
963 : : // or tabs in [ nLeftScanIdx, nRightScanIdx ]
964 [ + + ][ + + ]: 51271 : if ( nLeftScanIdx <= rInf.GetIdx() && rInf.GetIdx() <= nRightScanIdx )
[ + + ]
965 : : {
966 [ + + ]: 39259 : if ( nNextChg > nRightScanIdx )
967 : : nNextChg = nRightScanIdx =
968 : 27656 : rInf.ScanPortionEnd( nRightScanIdx, nNextChg );
969 : : }
970 : : else
971 : : {
972 : 12012 : nLeftScanIdx = rInf.GetIdx();
973 : : nNextChg = nRightScanIdx =
974 : 12012 : rInf.ScanPortionEnd( rInf.GetIdx(), nNextChg );
975 : : }
976 : :
977 : 51271 : pPor->SetLen( nNextChg - rInf.GetIdx() );
978 : 51271 : rInf.SetLen( pPor->GetLen() );
979 : 51271 : return pPor;
980 : : }
981 : :
982 : :
983 : : /*************************************************************************
984 : : * SwTxtFormatter::WhichFirstPortion()
985 : : *************************************************************************/
986 : :
987 : 109031 : SwLinePortion *SwTxtFormatter::WhichFirstPortion(SwTxtFormatInfo &rInf)
988 : : {
989 : 109031 : SwLinePortion *pPor = 0;
990 : :
991 [ + + ]: 109031 : if( rInf.GetRest() )
992 : : {
993 : : // Tabs and fields
994 [ + + ]: 684 : if( '\0' != rInf.GetHookChar() )
995 : 174 : return 0;
996 : :
997 : 510 : pPor = rInf.GetRest();
998 [ - + ]: 510 : if( pPor->IsErgoSumPortion() )
999 : 0 : rInf.SetErgoDone(sal_True);
1000 : : else
1001 [ - + ]: 510 : if( pPor->IsFtnNumPortion() )
1002 : 0 : rInf.SetFtnDone(sal_True);
1003 : : else
1004 [ + + ]: 510 : if( pPor->InNumberGrp() )
1005 : 174 : rInf.SetNumDone(sal_True);
1006 : :
1007 : 510 : rInf.SetRest(0);
1008 : 510 : pCurr->SetRest( sal_True );
1009 : 510 : return pPor;
1010 : : }
1011 : :
1012 : : // We can stand in the follow, it's crucial that
1013 : : // pFrm->GetOfst() == 0!
1014 [ + + ]: 108347 : if( rInf.GetIdx() )
1015 : : {
1016 : : // We now too can elongate FtnPortions and ErgoSumPortions
1017 : :
1018 : : // 1. The ErgoSumTexts
1019 [ + + ]: 96761 : if( !rInf.IsErgoDone() )
1020 : : {
1021 [ - + ][ # # ]: 3917 : if( pFrm->IsInFtn() && !pFrm->GetIndPrev() )
[ - + ]
1022 : 0 : pPor = (SwLinePortion*)NewErgoSumPortion( rInf );
1023 : 3917 : rInf.SetErgoDone( sal_True );
1024 : : }
1025 : :
1026 : : // 2. Arrow portions
1027 [ + - ][ + + ]: 96761 : if( !pPor && !rInf.IsArrowDone() )
[ + + ]
1028 : : {
1029 [ + + ]: 12793 : if( pFrm->GetOfst() && !pFrm->IsFollow() &&
[ + + + - ]
[ + + ]
1030 : 42 : rInf.GetIdx() == pFrm->GetOfst() )
1031 [ + - ]: 42 : pPor = new SwArrowPortion( *pCurr );
1032 : 12751 : rInf.SetArrowDone( sal_True );
1033 : : }
1034 : :
1035 : : // 3. Kerning portions at beginning of line in grid mode
1036 [ + + ][ + + ]: 96761 : if ( ! pPor && ! pCurr->GetPortion() )
[ + + ]
1037 : : {
1038 [ + - ][ - + ]: 90119 : GETGRID( GetTxtFrm()->FindPageFrm() )
[ # # ][ - + ]
1039 [ - + ]: 90119 : if ( pGrid )
1040 [ # # ]: 0 : pPor = new SwKernPortion( *pCurr );
1041 : : }
1042 : :
1043 : : // 4. The line rests (multiline fields)
1044 [ + + ]: 96761 : if( !pPor )
1045 : : {
1046 : 96719 : pPor = rInf.GetRest();
1047 : : // Only for pPor of course
1048 [ - + ]: 96719 : if( pPor )
1049 : : {
1050 : 0 : pCurr->SetRest( sal_True );
1051 : 0 : rInf.SetRest(0);
1052 : : }
1053 : : }
1054 : : }
1055 : : else
1056 : : {
1057 : : // 5. The foot note count
1058 [ + + ]: 11586 : if( !rInf.IsFtnDone() )
1059 : : {
1060 : : OSL_ENSURE( ( ! rInf.IsMulti() && ! pMulti ) || pMulti->HasRotation(),
1061 : : "Rotated number portion trouble" );
1062 : :
1063 : 10651 : sal_Bool bFtnNum = pFrm->IsFtnNumFrm();
1064 : 10651 : rInf.GetParaPortion()->SetFtnNum( bFtnNum );
1065 [ + + ]: 10651 : if( bFtnNum )
1066 : 128 : pPor = (SwLinePortion*)NewFtnNumPortion( rInf );
1067 : 10651 : rInf.SetFtnDone( sal_True );
1068 : : }
1069 : :
1070 : : // 6. The ErgoSumTexts of course also exist in the TextMaster,
1071 : : // it's crucial whether the SwFtnFrm is aFollow
1072 [ + + ][ + + ]: 11586 : if( !rInf.IsErgoDone() && !pPor && ! rInf.IsMulti() )
[ + + ][ + + ]
1073 : : {
1074 [ + + ][ + + ]: 10642 : if( pFrm->IsInFtn() && !pFrm->GetIndPrev() )
[ + + ]
1075 : 128 : pPor = (SwLinePortion*)NewErgoSumPortion( rInf );
1076 : 10642 : rInf.SetErgoDone( sal_True );
1077 : : }
1078 : :
1079 : : // 7. The numbering
1080 [ + + ][ + + ]: 11586 : if( !rInf.IsNumDone() && !pPor )
[ + + ]
1081 : : {
1082 : : OSL_ENSURE( ( ! rInf.IsMulti() && ! pMulti ) || pMulti->HasRotation(),
1083 : : "Rotated number portion trouble" );
1084 : :
1085 : : // If we're in the follow, then of course not
1086 [ + + ]: 10514 : if( GetTxtFrm()->GetTxtNode()->GetNumRule() )
1087 : 240 : pPor = (SwLinePortion*)NewNumberPortion( rInf );
1088 : 10514 : rInf.SetNumDone( sal_True );
1089 : : }
1090 : : // 8. The DropCaps
1091 [ + + ][ - + ]: 11586 : if( !pPor && GetDropFmt() && ! rInf.IsMulti() )
[ # # ][ - + ]
1092 : 0 : pPor = (SwLinePortion*)NewDropPortion( rInf );
1093 : :
1094 : : // 9. Kerning portions at beginning of line in grid mode
1095 [ + + ][ + + ]: 11586 : if ( !pPor && !pCurr->GetPortion() )
[ + + ]
1096 : : {
1097 [ + - ][ - + ]: 10681 : GETGRID( GetTxtFrm()->FindPageFrm() )
[ # # ][ - + ]
1098 [ - + ]: 10681 : if ( pGrid )
1099 [ # # ]: 0 : pPor = new SwKernPortion( *pCurr );
1100 : : }
1101 : : }
1102 : :
1103 : : // 10. Decimal tab portion at the beginning of each line in table cells
1104 [ + + ][ + + : 211967 : if ( !pPor && !pCurr->GetPortion() &&
+ + + - ]
[ + + ]
1105 : 100800 : GetTxtFrm()->IsInTab() &&
1106 : 2820 : GetTxtFrm()->GetTxtNode()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::TAB_COMPAT) )
1107 : : {
1108 : 2820 : pPor = NewTabPortion( rInf, true );
1109 : : }
1110 : :
1111 : : // 11. suffix of meta-field
1112 [ + + ]: 108347 : if (!pPor)
1113 : : {
1114 : 107943 : pPor = TryNewNoLengthPortion(rInf);
1115 : : }
1116 : :
1117 : 109031 : return pPor;
1118 : : }
1119 : :
1120 : 41262 : sal_Bool lcl_OldFieldRest( const SwLineLayout* pCurr )
1121 : : {
1122 [ + + ]: 41262 : if( !pCurr->GetNext() )
1123 : 7446 : return sal_False;
1124 : 33816 : const SwLinePortion *pPor = pCurr->GetNext()->GetPortion();
1125 : 33816 : sal_Bool bRet = sal_False;
1126 [ + + ][ + - ]: 35756 : while( pPor && !bRet )
[ + + ]
1127 : : {
1128 : 1946 : bRet = (pPor->InFldGrp() && ((SwFldPortion*)pPor)->IsFollow()) ||
1129 [ - + ][ # # ]: 1946 : (pPor->IsMultiPortion() && ((SwMultiPortion*)pPor)->IsFollowFld());
[ - + # # ]
1130 [ + + ]: 1946 : if( !pPor->GetLen() )
1131 : 6 : break;
1132 : 1940 : pPor = pPor->GetPortion();
1133 : : }
1134 : 41262 : return bRet;
1135 : : }
1136 : :
1137 : : /*************************************************************************
1138 : : * SwTxtFormatter::NewPortion()
1139 : : *************************************************************************/
1140 : :
1141 : : /* NewPortion sets rInf.nLen
1142 : : * A SwTxtPortion is limited by a tab, break, txtatr or attr change
1143 : : * We can have three cases:
1144 : : * 1) The line is full and the wrap was not emulated
1145 : : * -> return 0;
1146 : : * 2) The line is full and a wrap was emulated
1147 : : * -> Reset width and return new FlyPortion
1148 : : * 3) We need to construct a new portion
1149 : : * -> CalcFlyWidth emulates the width and return portion, if needed
1150 : : */
1151 : :
1152 : 109397 : SwLinePortion *SwTxtFormatter::NewPortion( SwTxtFormatInfo &rInf )
1153 : : {
1154 : : // Underflow takes precedence
1155 : 109397 : rInf.SetStopUnderFlow( sal_False );
1156 [ - + ]: 109397 : if( rInf.GetUnderFlow() )
1157 : : {
1158 : : OSL_ENSURE( rInf.IsFull(), "SwTxtFormatter::NewPortion: underflow but not full" );
1159 : 0 : return UnderFlow( rInf );
1160 : : }
1161 : :
1162 : : // If the line is full, flys and UnderFlow portions could be waiting ...
1163 [ + + ]: 109397 : if( rInf.IsFull() )
1164 : : {
1165 : : // LineBreaks and Flys (bug05.sdw)
1166 : : // IsDummy()
1167 [ + + ][ + + ]: 41628 : if( rInf.IsNewLine() && (!rInf.GetFly() || !pCurr->IsDummy()) )
[ - + ][ + + ]
1168 : 233 : return 0;
1169 : :
1170 : : // Wenn der Text an den Fly gestossen ist, oder wenn
1171 : : // der Fly als erstes drankommt, weil er ueber dem linken
1172 : : // Rand haengt, wird GetFly() returnt.
1173 : : // Wenn IsFull() und kein GetFly() vorhanden ist, gibt's
1174 : : // naturgemaesz eine 0.
1175 [ + + ]: 41395 : if( rInf.GetFly() )
1176 : : {
1177 [ + + ]: 133 : if( rInf.GetLast()->IsBreakPortion() )
1178 : : {
1179 [ + - ]: 14 : delete rInf.GetFly();
1180 : 14 : rInf.SetFly( 0 );
1181 : : }
1182 : :
1183 : 133 : return rInf.GetFly();
1184 : : }
1185 : : // Ein fieser Sonderfall: ein Rahmen ohne Umlauf kreuzt den
1186 : : // Ftn-Bereich. Wir muessen die Ftn-Portion als Zeilenrest
1187 : : // bekanntgeben, damit SwTxtFrm::Format nicht abbricht
1188 : : // (die Textmasse wurde ja durchformatiert).
1189 [ - + ]: 41262 : if( rInf.GetRest() )
1190 : 0 : rInf.SetNewLine( sal_True );
1191 : : else
1192 : : {
1193 : : // Wenn die naechste Zeile mit einem Rest eines Feldes beginnt,
1194 : : // jetzt aber kein Rest mehr anliegt,
1195 : : // muss sie auf jeden Fall neu formatiert werden!
1196 [ - + ]: 41262 : if( lcl_OldFieldRest( GetCurr() ) )
1197 : 0 : rInf.SetNewLine( sal_True );
1198 : : else
1199 : : {
1200 : 41262 : SwLinePortion *pFirst = WhichFirstPortion( rInf );
1201 [ - + ]: 41262 : if( pFirst )
1202 : : {
1203 : 0 : rInf.SetNewLine( sal_True );
1204 [ # # ]: 0 : if( pFirst->InNumberGrp() )
1205 : 0 : rInf.SetNumDone( sal_False) ;
1206 [ # # ]: 0 : delete pFirst;
1207 : : }
1208 : : }
1209 : : }
1210 : :
1211 : 41262 : return 0;
1212 : : }
1213 : :
1214 : 67769 : SwLinePortion *pPor = WhichFirstPortion( rInf );
1215 : :
1216 : : // Check for Hidden Portion:
1217 [ + + ]: 67769 : if ( !pPor )
1218 : : {
1219 : 66815 : xub_StrLen nEnd = rInf.GetIdx();
1220 [ - + ][ + - ]: 66815 : if ( ::lcl_BuildHiddenPortion( rInf, nEnd ) )
1221 [ # # ][ # # ]: 66815 : pPor = new SwHiddenTextPortion( nEnd - rInf.GetIdx() );
1222 : : }
1223 : :
1224 [ + + ]: 67769 : if( !pPor )
1225 : : {
1226 [ + + ][ - + : 132604 : if( ( !pMulti || pMulti->IsBidi() ) &&
+ + - + ]
[ + + ]
1227 : : // #i42734#
1228 : : // No multi portion if there is a hook character waiting:
1229 : 65789 : ( !rInf.GetRest() || '\0' == rInf.GetHookChar() ) )
1230 : : {
1231 : : // We open a multiportion part, if we enter a multi-line part
1232 : : // of the paragraph.
1233 : 65441 : xub_StrLen nEnd = rInf.GetIdx();
1234 [ + - ]: 65441 : SwMultiCreator* pCreate = rInf.GetMultiCreator( nEnd, pMulti );
1235 [ + + ]: 65441 : if( pCreate )
1236 : : {
1237 : 356 : SwMultiPortion* pTmp = NULL;
1238 : :
1239 [ - + ]: 356 : if ( SW_MC_BIDI == pCreate->nId )
1240 [ # # ][ # # ]: 0 : pTmp = new SwBidiPortion( nEnd, pCreate->nLevel );
1241 [ + + ]: 356 : else if ( SW_MC_RUBY == pCreate->nId )
1242 : : {
1243 [ + - ]: 336 : Seek( rInf.GetIdx() );
1244 : : sal_Bool bRubyTop;
1245 : 336 : sal_Bool* pRubyPos = 0;
1246 : :
1247 [ + - ]: 336 : if ( rInf.SnapToGrid() )
1248 : : {
1249 [ + - ][ + - ]: 336 : GETGRID( GetTxtFrm()->FindPageFrm() )
[ + - ][ - + ]
[ # # ][ # # ]
[ # # ][ - + ]
1250 [ - + ]: 336 : if ( pGrid )
1251 : : {
1252 : 0 : bRubyTop = ! pGrid->GetRubyTextBelow();
1253 : 0 : pRubyPos = &bRubyTop;
1254 : : }
1255 : : }
1256 : :
1257 : 336 : pTmp = new SwRubyPortion( *pCreate, *rInf.GetFont(),
1258 : 336 : *GetTxtFrm()->GetTxtNode()->getIDocumentSettingAccess(),
1259 [ + - ][ + - ]: 672 : nEnd, 0, pRubyPos );
[ + - ]
1260 : : }
1261 [ - + ]: 20 : else if( SW_MC_ROTATE == pCreate->nId )
1262 : : pTmp = new SwRotatedPortion( *pCreate, nEnd,
1263 [ # # ][ # # ]: 0 : GetTxtFrm()->IsRightToLeft() );
[ # # ]
1264 : : else
1265 [ + - ][ + - ]: 20 : pTmp = new SwDoubleLinePortion( *pCreate, nEnd );
1266 : :
1267 : 356 : delete pCreate;
1268 [ + - ]: 356 : CalcFlyWidth( rInf );
1269 : :
1270 : 65441 : return pTmp;
1271 : : }
1272 : : }
1273 : : // 5010: Tabs und Felder
1274 : 66459 : xub_Unicode cChar = rInf.GetHookChar();
1275 : :
1276 [ + + ]: 66459 : if( cChar )
1277 : : {
1278 : : /* Wir holen uns nocheinmal cChar, um sicherzustellen, dass das
1279 : : * Tab jetzt wirklich ansteht und nicht auf die naechste Zeile
1280 : : * gewandert ist ( so geschehen hinter Rahmen ).
1281 : : * Wenn allerdings eine FldPortion im Rest wartet, muessen wir
1282 : : * das cChar natuerlich aus dem Feldinhalt holen, z.B. bei
1283 : : * DezimalTabs und Feldern (22615)
1284 : : */
1285 [ + + ][ - + ]: 302 : if( !rInf.GetRest() || !rInf.GetRest()->InFldGrp() )
[ + + ]
1286 : 128 : cChar = rInf.GetChar( rInf.GetIdx() );
1287 : 302 : rInf.ClearHookChar();
1288 : : }
1289 : : else
1290 : : {
1291 [ + + ]: 66157 : if( rInf.GetIdx() >= rInf.GetTxt().Len() )
1292 : : {
1293 : 12275 : rInf.SetFull(sal_True);
1294 : 12275 : CalcFlyWidth( rInf );
1295 : 12275 : return pPor;
1296 : : }
1297 : 53882 : cChar = rInf.GetChar( rInf.GetIdx() );
1298 : : }
1299 : :
1300 [ + + + + : 54184 : switch( cChar )
+ - + + ]
1301 : : {
1302 : : case CH_TAB:
1303 : 207 : pPor = NewTabPortion( rInf, false ); break;
1304 : :
1305 : : case CH_BREAK:
1306 [ + - ]: 271 : pPor = new SwBreakPortion( *rInf.GetLast() ); break;
1307 : :
1308 : : case CHAR_SOFTHYPHEN: // soft hyphen
1309 [ + - ]: 6 : pPor = new SwSoftHyphPortion; break;
1310 : :
1311 : : case CHAR_HARDBLANK: // no-break space
1312 [ + - ]: 6 : pPor = new SwBlankPortion( ' ' ); break;
1313 : :
1314 : : case CHAR_HARDHYPHEN: // non-breaking hyphen
1315 [ + - ]: 12 : pPor = new SwBlankPortion( '-' ); break;
1316 : :
1317 : : case CHAR_ZWSP: // zero width space
1318 : : case CHAR_ZWNBSP : // word joiner
1319 : : // case CHAR_RLM : // right to left mark
1320 : : // case CHAR_LRM : // left to right mark
1321 [ # # ]: 0 : pPor = new SwControlCharPortion( cChar ); break;
1322 : :
1323 : : case CH_TXTATR_BREAKWORD:
1324 : : case CH_TXTATR_INWORD:
1325 [ + - ]: 2411 : if( rInf.HasHint( rInf.GetIdx() ) )
1326 : : {
1327 : 2411 : pPor = NewExtraPortion( rInf );
1328 : 2411 : break;
1329 : : }
1330 : : // No break
1331 : : default :
1332 : : {
1333 : 51271 : SwTabPortion* pLastTabPortion = rInf.GetLastTab();
1334 [ - + ][ - + ]: 51271 : if ( pLastTabPortion && cChar == rInf.GetTabDecimal() )
[ + + ]
1335 : : {
1336 : : // #127428# Abandon dec. tab position if line is full
1337 : : // We have a decimal tab portion in the line and the next character has to be
1338 : : // aligned at the tab stop position. We store the width from the beginning of
1339 : : // the tab stop portion up to the portion containint the decimal separator:
1340 [ # # # # ]: 0 : if ( GetTxtFrm()->GetTxtNode()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::TAB_COMPAT) /*rInf.GetVsh()->IsTabCompat();*/ &&
[ # # ]
1341 : 0 : POR_TABDECIMAL == pLastTabPortion->GetWhichPor() )
1342 : : {
1343 : : OSL_ENSURE( rInf.X() >= pLastTabPortion->Fix(), "Decimal tab stop position cannot be calculated" );
1344 : 0 : const sal_uInt16 nWidthOfPortionsUpToDecimalPosition = (sal_uInt16)(rInf.X() - pLastTabPortion->Fix() );
1345 : 0 : static_cast<SwTabDecimalPortion*>(pLastTabPortion)->SetWidthOfPortionsUpToDecimalPosition( nWidthOfPortionsUpToDecimalPosition );
1346 : 0 : rInf.SetTabDecimal( 0 );
1347 : : }
1348 : : else
1349 : 0 : rInf.SetFull( rInf.GetLastTab()->Format( rInf ) );
1350 : : }
1351 : :
1352 [ - + ]: 51271 : if( rInf.GetRest() )
1353 : : {
1354 [ # # ]: 0 : if( rInf.IsFull() )
1355 : : {
1356 : 0 : rInf.SetNewLine(sal_True);
1357 : 0 : return 0;
1358 : : }
1359 : 0 : pPor = rInf.GetRest();
1360 : 0 : rInf.SetRest(0);
1361 : : }
1362 : : else
1363 : : {
1364 [ - + ]: 51271 : if( rInf.IsFull() )
1365 : 0 : return 0;
1366 : 51271 : pPor = NewTxtPortion( rInf );
1367 : : }
1368 : 51271 : break;
1369 : : }
1370 : : }
1371 : :
1372 : : // if a portion is created despite there being a pending RestPortion,
1373 : : // then it is a field which has been split (e.g. because it contains a Tab)
1374 [ + - ][ + + ]: 54184 : if( pPor && rInf.GetRest() )
[ + + ]
1375 : 174 : pPor->SetLen( 0 );
1376 : :
1377 : : // robust:
1378 [ + - ][ - + ]: 54184 : if( !pPor || rInf.IsStop() )
[ - + ]
1379 : : {
1380 [ # # ]: 0 : delete pPor;
1381 : 0 : return 0;
1382 : : }
1383 : : }
1384 : :
1385 : : // Special portions containing numbers (footnote anchor, footnote number,
1386 : : // numbering) can be contained in a rotated portion, if the user
1387 : : // choose a rotated character attribute.
1388 [ + - ][ + + ]: 55138 : if ( pPor && ! pMulti )
1389 : : {
1390 [ + + ]: 54032 : if ( pPor->IsFtnPortion() )
1391 : : {
1392 : 132 : const SwTxtFtn* pTxtFtn = ((SwFtnPortion*)pPor)->GetTxtFtn();
1393 : :
1394 [ + - ]: 132 : if ( pTxtFtn )
1395 : : {
1396 : 132 : SwFmtFtn& rFtn = (SwFmtFtn&)pTxtFtn->GetFtn();
1397 : 132 : const SwDoc *pDoc = rInf.GetTxtFrm()->GetNode()->GetDoc();
1398 : : const SwEndNoteInfo* pInfo;
1399 [ + + ]: 132 : if( rFtn.IsEndNote() )
1400 : 33 : pInfo = &pDoc->GetEndNoteInfo();
1401 : : else
1402 : 99 : pInfo = &pDoc->GetFtnInfo();
1403 [ + - ]: 132 : const SwAttrSet& rSet = pInfo->GetAnchorCharFmt((SwDoc&)*pDoc)->GetAttrSet();
1404 : :
1405 : : const SfxPoolItem* pItem;
1406 : 132 : sal_uInt16 nDir = 0;
1407 [ - + ]: 132 : if( SFX_ITEM_SET == rSet.GetItemState( RES_CHRATR_ROTATE,
1408 [ + - ]: 132 : sal_True, &pItem ))
1409 : 0 : nDir = ((SvxCharRotateItem*)pItem)->GetValue();
1410 : :
1411 [ - + ]: 132 : if ( 0 != nDir )
1412 : : {
1413 [ # # ][ # # ]: 0 : delete pPor;
1414 : 0 : pPor = new SwRotatedPortion( rInf.GetIdx() + 1, 900 == nDir ?
1415 : : DIR_BOTTOM2TOP :
1416 [ # # ][ # # ]: 132 : DIR_TOP2BOTTOM );
[ # # ]
1417 : : }
1418 : : }
1419 : : }
1420 [ + + ]: 53900 : else if ( pPor->InNumberGrp() )
1421 : : {
1422 : 536 : const SwFont* pNumFnt = ((SwFldPortion*)pPor)->GetFont();
1423 : :
1424 [ + - ]: 536 : if ( pNumFnt )
1425 : : {
1426 : 536 : sal_uInt16 nDir = pNumFnt->GetOrientation( rInf.GetTxtFrm()->IsVertical() );
1427 [ - + ]: 536 : if ( 0 != nDir )
1428 : : {
1429 [ # # ]: 0 : delete pPor;
1430 : : pPor = new SwRotatedPortion( 0, 900 == nDir ?
1431 : : DIR_BOTTOM2TOP :
1432 [ # # ][ # # ]: 0 : DIR_TOP2BOTTOM );
1433 : :
1434 : 0 : rInf.SetNumDone( sal_False );
1435 : 0 : rInf.SetFtnDone( sal_False );
1436 : : }
1437 : : }
1438 : : }
1439 : : }
1440 : :
1441 : : // Der Font wird im Outputdevice eingestellt,
1442 : : // der Ascent und die Hoehe werden berechnet.
1443 [ + + ][ + + ]: 55138 : if( !pPor->GetAscent() && !pPor->Height() )
[ + + ]
1444 : 2264 : CalcAscent( rInf, pPor );
1445 : 55138 : rInf.SetLen( pPor->GetLen() );
1446 : :
1447 : : // In CalcFlyWidth wird Width() verkuerzt, wenn eine FlyPortion vorliegt.
1448 : 55138 : CalcFlyWidth( rInf );
1449 : :
1450 : : // Man darf nicht vergessen, dass pCurr als GetLast() vernuenftige
1451 : : // Werte bereithalten muss:
1452 [ - + ]: 55138 : if( !pCurr->Height() )
1453 : : {
1454 : : OSL_ENSURE( pCurr->Height(), "SwTxtFormatter::NewPortion: limbo dance" );
1455 : 0 : pCurr->Height( pPor->Height() );
1456 : 0 : pCurr->SetAscent( pPor->GetAscent() );
1457 : : }
1458 : :
1459 : : OSL_ENSURE( !pPor || pPor->Height(),
1460 : : "SwTxtFormatter::NewPortion: something went wrong");
1461 [ + + ][ - + ]: 55138 : if( pPor->IsPostItsPortion() && rInf.X() >= rInf.Width() && rInf.GetFly() )
[ # # ][ - + ]
1462 : : {
1463 [ # # ]: 0 : delete pPor;
1464 : 0 : pPor = rInf.GetFly();
1465 : : }
1466 : 109397 : return pPor;
1467 : : }
1468 : :
1469 : : /*************************************************************************
1470 : : * SwTxtFormatter::FormatLine()
1471 : : *************************************************************************/
1472 : :
1473 : 52762 : xub_StrLen SwTxtFormatter::FormatLine( const xub_StrLen nStartPos )
1474 : : {
1475 : : OSL_ENSURE( ! pFrm->IsVertical() || pFrm->IsSwapped(),
1476 : : "SwTxtFormatter::FormatLine( nStartPos ) with unswapped frame" );
1477 : :
1478 : : // For the formatting routines, we set pOut to the reference device.
1479 [ + - ]: 52762 : SwHookOut aHook( GetInfo() );
1480 [ + + ]: 52762 : if( GetInfo().GetLen() < GetInfo().GetTxt().Len() )
1481 : 37778 : GetInfo().SetLen( GetInfo().GetTxt().Len() );
1482 : :
1483 : 52762 : sal_Bool bBuild = sal_True;
1484 : 52762 : SetFlyInCntBase( sal_False );
1485 : 52762 : GetInfo().SetLineHeight( 0 );
1486 : 52762 : GetInfo().SetLineNettoHeight( 0 );
1487 : :
1488 : : // Recycling muss bei geaenderter Zeilenhoehe unterdrueckt werden
1489 : : // und auch bei geaendertem Ascent (Absenken der Grundlinie).
1490 : 52762 : const KSHORT nOldHeight = pCurr->Height();
1491 : 52762 : const KSHORT nOldAscent = pCurr->GetAscent();
1492 : :
1493 : 52762 : pCurr->SetEndHyph( sal_False );
1494 : 52762 : pCurr->SetMidHyph( sal_False );
1495 : :
1496 : : // fly positioning can make it necessary format a line several times
1497 : : // for this, we have to keep a copy of our rest portion
1498 : 52762 : SwLinePortion* pFld = GetInfo().GetRest();
1499 : 52762 : SwFldPortion* pSaveFld = 0;
1500 : :
1501 [ # # ][ # # ]: 52762 : if ( pFld && pFld->InFldGrp() && !pFld->IsFtnPortion() )
[ - + ][ - + ]
1502 [ # # ][ # # ]: 0 : pSaveFld = new SwFldPortion( *((SwFldPortion*)pFld) );
1503 : :
1504 : : // for an optimal repaint rectangle, we want to compare fly portions
1505 : : // before and after the BuildPortions call
1506 [ + - ]: 52762 : const sal_Bool bOptimizeRepaint = AllowRepaintOpt();
1507 : 52762 : const xub_StrLen nOldLineEnd = nStartPos + pCurr->GetLen();
1508 [ + - ]: 52762 : std::vector<long> flyStarts;
1509 : :
1510 : : // these are the conditions for a fly position comparison
1511 [ + + ][ - + ]: 52762 : if ( bOptimizeRepaint && pCurr->IsFly() )
[ - + ]
1512 : : {
1513 : 0 : SwLinePortion* pPor = pCurr->GetFirstPortion();
1514 : 0 : long nPOfst = 0;
1515 [ # # ]: 0 : while ( pPor )
1516 : : {
1517 [ # # ]: 0 : if ( pPor->IsFlyPortion() )
1518 : : // insert start value of fly portion
1519 [ # # ]: 0 : flyStarts.push_back( nPOfst );
1520 : :
1521 : 0 : nPOfst += pPor->Width();
1522 : 0 : pPor = pPor->GetPortion();
1523 : : }
1524 : : }
1525 : :
1526 : : // Hier folgt bald die Unterlaufpruefung.
1527 [ + + ]: 105524 : while( bBuild )
1528 : : {
1529 : 52762 : GetInfo().SetFtnInside( sal_False );
1530 : 52762 : GetInfo().SetOtherThanFtnInside( sal_False );
1531 : :
1532 : : // These values must not be reset by FormatReset();
1533 : 52762 : sal_Bool bOldNumDone = GetInfo().IsNumDone();
1534 : 52762 : sal_Bool bOldArrowDone = GetInfo().IsArrowDone();
1535 : 52762 : sal_Bool bOldErgoDone = GetInfo().IsErgoDone();
1536 : :
1537 : : // besides other things, this sets the repaint offset to 0
1538 [ + - ]: 52762 : FormatReset( GetInfo() );
1539 : :
1540 : 52762 : GetInfo().SetNumDone( bOldNumDone );
1541 : 52762 : GetInfo().SetArrowDone( bOldArrowDone );
1542 : 52762 : GetInfo().SetErgoDone( bOldErgoDone );
1543 : :
1544 : : // build new portions for this line
1545 [ + - ]: 52762 : BuildPortions( GetInfo() );
1546 : :
1547 [ - + ]: 52762 : if( GetInfo().IsStop() )
1548 : : {
1549 : 0 : pCurr->SetLen( 0 );
1550 [ # # ]: 0 : pCurr->Height( GetFrmRstHeight() + 1 );
1551 [ # # ]: 0 : pCurr->SetRealHeight( GetFrmRstHeight() + 1 );
1552 : 0 : pCurr->Width(0);
1553 [ # # ]: 0 : pCurr->Truncate();
1554 : 0 : return nStartPos;
1555 : : }
1556 [ - + ]: 52762 : else if( GetInfo().IsDropInit() )
1557 : : {
1558 [ # # ]: 0 : DropInit();
1559 : 0 : GetInfo().SetDropInit( sal_False );
1560 : : }
1561 : :
1562 [ + - ]: 52762 : pCurr->CalcLine( *this, GetInfo() );
1563 [ + - ]: 52762 : CalcRealHeight( GetInfo().IsNewLine() );
1564 : :
1565 [ + + ][ + - ]: 52762 : if ( IsFlyInCntBase() && !IsQuick() )
[ + - ][ + + ]
1566 : : {
1567 : : KSHORT nTmpAscent, nTmpHeight;
1568 [ + - ]: 939 : CalcAscentAndHeight( nTmpAscent, nTmpHeight );
1569 [ + - ]: 939 : AlignFlyInCntBase( Y() + long( nTmpAscent ) );
1570 [ + - ]: 939 : pCurr->CalcLine( *this, GetInfo() );
1571 [ + - ]: 939 : CalcRealHeight();
1572 : : }
1573 : :
1574 : : // bBuild entscheidet, ob noch eine Ehrenrunde gedreht wird
1575 [ - + ]: 52762 : if ( pCurr->GetRealHeight() <= GetInfo().GetLineHeight() )
1576 : : {
1577 : 0 : pCurr->SetRealHeight( GetInfo().GetLineHeight() );
1578 : 0 : bBuild = sal_False;
1579 : : }
1580 : : else
1581 : : {
1582 [ + - ]: 53378 : bBuild = ( GetInfo().GetTxtFly()->IsOn() && ChkFlyUnderflow(GetInfo()) )
1583 [ + - ][ + - ]: 53378 : || GetInfo().CheckFtnPortion(pCurr);
[ - + ][ + + ]
1584 [ - + ]: 52762 : if( bBuild )
1585 : : {
1586 : 0 : GetInfo().SetNumDone( bOldNumDone );
1587 : 0 : GetInfo().ResetMaxWidthDiff();
1588 : :
1589 : : // delete old rest
1590 [ # # ]: 0 : if ( GetInfo().GetRest() )
1591 : : {
1592 [ # # ][ # # ]: 0 : delete GetInfo().GetRest();
1593 : 0 : GetInfo().SetRest( 0 );
1594 : : }
1595 : :
1596 : : // set original rest portion
1597 [ # # ]: 0 : if ( pSaveFld )
1598 [ # # ][ # # ]: 0 : GetInfo().SetRest( new SwFldPortion( *pSaveFld ) );
1599 : :
1600 : 0 : pCurr->SetLen( 0 );
1601 : 0 : pCurr->Width(0);
1602 [ # # ]: 0 : pCurr->Truncate();
1603 : : }
1604 : : }
1605 : : }
1606 : :
1607 : : // calculate optimal repaint rectangle
1608 [ + + ]: 52762 : if ( bOptimizeRepaint )
1609 : : {
1610 [ + - ]: 3304 : GetInfo().SetPaintOfst( ::lcl_CalcOptRepaint( *this, *pCurr, nOldLineEnd, flyStarts ) );
1611 : 3304 : flyStarts.clear();
1612 : : }
1613 : : else
1614 : : // Special case: We do not allow an optimitation of the repaint
1615 : : // area, but during formatting the repaint offset is set to indicate
1616 : : // a maximum value for the offset. This value has to be reset:
1617 : 49458 : GetInfo().SetPaintOfst( 0 );
1618 : :
1619 : : // This corrects the start of the reformat range if something has
1620 : : // moved to the next line. Otherwise IsFirstReformat in AllowRepaintOpt
1621 : : // will give us a wrong result if we have to reformat another line
1622 : 52762 : GetInfo().GetParaPortion()->GetReformat()->LeftMove( GetInfo().GetIdx() );
1623 : :
1624 : : // delete master copy of rest portion
1625 [ # # ][ - + ]: 52762 : delete pSaveFld;
1626 : :
1627 : 52762 : xub_StrLen nNewStart = nStartPos + pCurr->GetLen();
1628 : :
1629 : : // adjust text if kana compression is enabled
1630 [ - + ]: 52762 : if ( GetInfo().CompressLine() )
1631 : : {
1632 [ # # ]: 0 : SwTwips nRepaintOfst = CalcKanaAdj( pCurr );
1633 : :
1634 : : // adjust repaint offset
1635 [ # # ]: 0 : if ( nRepaintOfst < GetInfo().GetPaintOfst() )
1636 : 0 : GetInfo().SetPaintOfst( nRepaintOfst );
1637 : : }
1638 : :
1639 [ + - ]: 52762 : CalcAdjustLine( pCurr );
1640 : :
1641 [ + + ][ + + ]: 52762 : if( nOldHeight != pCurr->Height() || nOldAscent != pCurr->GetAscent() )
[ + + ]
1642 : : {
1643 : 12049 : SetFlyInCntBase();
1644 : 12049 : GetInfo().SetPaintOfst( 0 ); //geaenderte Zeilenhoehe => kein Recycling
1645 : : // alle weiteren Zeilen muessen gepaintet und, wenn Flys im Spiel sind
1646 : : // auch formatiert werden.
1647 : 12049 : GetInfo().SetShift( sal_True );
1648 : : }
1649 : :
1650 [ + + ][ + - ]: 52762 : if ( IsFlyInCntBase() && !IsQuick() )
[ + + ][ + + ]
1651 [ + - ][ + - ]: 12078 : UpdatePos( pCurr, GetTopLeft(), GetStart() );
1652 : :
1653 [ + - ]: 52762 : return nNewStart;
1654 : : }
1655 : :
1656 : : /*************************************************************************
1657 : : * SwTxtFormatter::RecalcRealHeight()
1658 : : *************************************************************************/
1659 : :
1660 : 0 : void SwTxtFormatter::RecalcRealHeight()
1661 : : {
1662 : 0 : sal_Bool bMore = sal_True;
1663 [ # # ]: 0 : while(bMore)
1664 : : {
1665 : 0 : CalcRealHeight();
1666 : 0 : bMore = Next() != 0;
1667 : : }
1668 : 0 : }
1669 : :
1670 : : /*************************************************************************
1671 : : * SwTxtFormatter::CalcRealHeight()
1672 : : *************************************************************************/
1673 : :
1674 : 54963 : void SwTxtFormatter::CalcRealHeight( sal_Bool bNewLine )
1675 : : {
1676 : 54963 : KSHORT nLineHeight = pCurr->Height();
1677 : 54963 : pCurr->SetClipping( sal_False );
1678 : :
1679 [ - + ][ # # ]: 54963 : GETGRID( pFrm->FindPageFrm() )
[ - + ][ + - ]
1680 [ - + ][ # # ]: 54963 : if ( pGrid && GetInfo().SnapToGrid() )
[ - + ]
1681 : : {
1682 : 0 : const sal_uInt16 nGridWidth = pGrid->GetBaseHeight();
1683 : 0 : const sal_uInt16 nRubyHeight = pGrid->GetRubyHeight();
1684 : 0 : const sal_Bool bRubyTop = ! pGrid->GetRubyTextBelow();
1685 : :
1686 : 0 : nLineHeight = nGridWidth + nRubyHeight;
1687 : 0 : sal_uInt16 nLineDist = nLineHeight;
1688 : :
1689 [ # # ]: 0 : while ( pCurr->Height() > nLineHeight )
1690 : 0 : nLineHeight = nLineHeight + nLineDist;
1691 : :
1692 : 0 : KSHORT nAsc = pCurr->GetAscent() +
1693 : : ( bRubyTop ?
1694 : 0 : ( nLineHeight - pCurr->Height() + nRubyHeight ) / 2 :
1695 [ # # ]: 0 : ( nLineHeight - pCurr->Height() - nRubyHeight ) / 2 );
1696 : :
1697 : 0 : pCurr->Height( nLineHeight );
1698 : 0 : pCurr->SetAscent( nAsc );
1699 : 0 : pInf->GetParaPortion()->SetFixLineHeight();
1700 : :
1701 : : // we ignore any line spacing options except from ...
1702 : 0 : const SvxLineSpacingItem* pSpace = aLineInf.GetLineSpacing();
1703 [ # # # # ]: 0 : if ( ! IsParaLine() && pSpace &&
[ # # ][ # # ]
1704 : 0 : SVX_INTER_LINE_SPACE_PROP == pSpace->GetInterLineSpaceRule() )
1705 : : {
1706 : 0 : sal_uLong nTmp = pSpace->GetPropLineSpace();
1707 : :
1708 [ # # ]: 0 : if( nTmp < 100 )
1709 : 0 : nTmp = 100;
1710 : :
1711 : 0 : nTmp *= nLineHeight;
1712 : 0 : nLineHeight = (sal_uInt16)(nTmp / 100);
1713 : : }
1714 : :
1715 : 0 : pCurr->SetRealHeight( nLineHeight );
1716 : 54963 : return;
1717 : : }
1718 : :
1719 : : // Das Dummyflag besitzen Zeilen, die nur Flyportions enthalten, diese
1720 : : // sollten kein Register etc. beachten. Dummerweise hat kann es eine leere
1721 : : // Zeile am Absatzende geben (bei leeren Abs?tzen oder nach einem
1722 : : // Shift-Return), die das Register durchaus beachten soll.
1723 [ + + ]: 56822 : if( !pCurr->IsDummy() || ( !pCurr->GetNext() &&
[ + + + + ]
[ + + ][ + + ]
1724 : 1859 : GetStart() >= GetTxtFrm()->GetTxt().Len() && !bNewLine ) )
1725 : : {
1726 : 54918 : const SvxLineSpacingItem *pSpace = aLineInf.GetLineSpacing();
1727 [ + - ]: 54918 : if( pSpace )
1728 : : {
1729 [ + + - - ]: 54918 : switch( pSpace->GetLineSpaceRule() )
1730 : : {
1731 : : case SVX_LINE_SPACE_AUTO:
1732 [ + + ]: 54906 : if (pSpace->GetInterLineSpaceRule()==SVX_INTER_LINE_SPACE_PROP) {
1733 : 543 : long nTmp = pSpace->GetPropLineSpace();
1734 [ - + ]: 543 : if (nTmp<100) { // code adaped from fixed line height
1735 : 0 : nTmp *= nLineHeight;
1736 : 0 : nTmp /= 100;
1737 [ # # ]: 0 : if( !nTmp )
1738 : 0 : ++nTmp;
1739 : 0 : nLineHeight = (KSHORT)nTmp;
1740 : : /*
1741 : : //@TODO figure out how WW maps ascent and descent
1742 : : //in case of prop line spacing <100%
1743 : : KSHORT nAsc = ( 4 * nLineHeight ) / 5; // 80%
1744 : : if( nAsc < pCurr->GetAscent() ||
1745 : : nLineHeight - nAsc < pCurr->Height() -
1746 : : pCurr->GetAscent() )
1747 : : pCurr->SetClipping( sal_True );
1748 : : pCurr->SetAscent( nAsc );
1749 : : */
1750 : 0 : pCurr->Height( nLineHeight );
1751 : 0 : pInf->GetParaPortion()->SetFixLineHeight();
1752 : : }
1753 : : }
1754 : 54906 : break;
1755 : : case SVX_LINE_SPACE_MIN:
1756 : : {
1757 [ - + ]: 12 : if( nLineHeight < KSHORT( pSpace->GetLineHeight() ) )
1758 : 0 : nLineHeight = pSpace->GetLineHeight();
1759 : 12 : break;
1760 : : }
1761 : : case SVX_LINE_SPACE_FIX:
1762 : : {
1763 : 0 : nLineHeight = pSpace->GetLineHeight();
1764 : 0 : KSHORT nAsc = ( 4 * nLineHeight ) / 5; // 80%
1765 [ # # ]: 0 : if( nAsc < pCurr->GetAscent() ||
[ # # # # ]
1766 : 0 : nLineHeight - nAsc < pCurr->Height() - pCurr->GetAscent() )
1767 : 0 : pCurr->SetClipping( sal_True );
1768 : 0 : pCurr->Height( nLineHeight );
1769 : 0 : pCurr->SetAscent( nAsc );
1770 : 0 : pInf->GetParaPortion()->SetFixLineHeight();
1771 : : }
1772 : 0 : break;
1773 : : default: OSL_FAIL( ": unknown LineSpaceRule" );
1774 : : }
1775 [ + + ]: 54918 : if( !IsParaLine() )
1776 [ + + - - ]: 41676 : switch( pSpace->GetInterLineSpaceRule() )
1777 : : {
1778 : : case SVX_INTER_LINE_SPACE_OFF:
1779 : 41562 : break;
1780 : : case SVX_INTER_LINE_SPACE_PROP:
1781 : : {
1782 : 114 : long nTmp = pSpace->GetPropLineSpace();
1783 : : // 50% ist das Minimum, bei 0% schalten wir auf
1784 : : // den Defaultwert 100% um ...
1785 [ - + ]: 114 : if( nTmp < 50 )
1786 [ # # ]: 0 : nTmp = nTmp ? 50 : 100;
1787 : :
1788 : 114 : nTmp *= nLineHeight;
1789 : 114 : nTmp /= 100;
1790 [ - + ]: 114 : if( !nTmp )
1791 : 0 : ++nTmp;
1792 : 114 : nLineHeight = (KSHORT)nTmp;
1793 : 114 : break;
1794 : : }
1795 : : case SVX_INTER_LINE_SPACE_FIX:
1796 : : {
1797 : 0 : nLineHeight = nLineHeight + pSpace->GetInterLineSpace();
1798 : 41676 : break;
1799 : : }
1800 : : default: OSL_FAIL( ": unknown InterLineSpaceRule" );
1801 : : }
1802 : : }
1803 : : #if OSL_DEBUG_LEVEL > 1
1804 : : KSHORT nDummy = nLineHeight + 1;
1805 : : (void)nDummy;
1806 : : #endif
1807 : :
1808 [ - + ]: 54918 : if( IsRegisterOn() )
1809 : : {
1810 : 0 : SwTwips nTmpY = Y() + pCurr->GetAscent() + nLineHeight - pCurr->Height();
1811 [ # # ][ # # ]: 0 : SWRECTFN( pFrm )
[ # # ][ # # ]
1812 [ # # ]: 0 : if ( bVert )
1813 : 0 : nTmpY = pFrm->SwitchHorizontalToVertical( nTmpY );
1814 : 0 : nTmpY = (*fnRect->fnYDiff)( nTmpY, RegStart() );
1815 : 0 : KSHORT nDiff = KSHORT( nTmpY % RegDiff() );
1816 [ # # ]: 0 : if( nDiff )
1817 : 0 : nLineHeight += RegDiff() - nDiff;
1818 : : }
1819 : : }
1820 : 54963 : pCurr->SetRealHeight( nLineHeight );
1821 : : }
1822 : :
1823 : : /*************************************************************************
1824 : : * SwTxtFormatter::FeedInf()
1825 : : *************************************************************************/
1826 : :
1827 : 53368 : void SwTxtFormatter::FeedInf( SwTxtFormatInfo &rInf ) const
1828 : : {
1829 : : // 3260, 3860: Fly auf jeden Fall loeschen!
1830 : 53368 : ClearFly( rInf );
1831 : 53368 : rInf.Init();
1832 : :
1833 : 53368 : rInf.ChkNoHyph( CntEndHyph(), CntMidHyph() );
1834 : 53368 : rInf.SetRoot( pCurr );
1835 : 53368 : rInf.SetLineStart( nStart );
1836 : 53368 : rInf.SetIdx( nStart );
1837 : :
1838 : : // Handle overflows:
1839 : : // #i34348# Changed type from sal_uInt16 to SwTwips
1840 : 53368 : SwTwips nTmpLeft = Left();
1841 : 53368 : SwTwips nTmpRight = Right();
1842 : 53368 : SwTwips nTmpFirst = FirstLeft();
1843 : :
1844 [ + + ][ - + ]: 53368 : if ( nTmpLeft > USHRT_MAX ||
[ + - ]
1845 : : nTmpRight > USHRT_MAX ||
1846 : : nTmpFirst > USHRT_MAX )
1847 : : {
1848 [ - + ][ # # ]: 1 : SWRECTFN( rInf.GetTxtFrm() )
[ # # ][ - + ]
1849 [ + - ]: 1 : nTmpLeft = (rInf.GetTxtFrm()->Frm().*fnRect->fnGetLeft)();
1850 [ + - ]: 1 : nTmpRight = (rInf.GetTxtFrm()->Frm().*fnRect->fnGetRight)();
1851 : 1 : nTmpFirst = nTmpLeft;
1852 : : }
1853 : :
1854 : 53368 : rInf.Left( nTmpLeft );
1855 : 53368 : rInf.Right( nTmpRight );
1856 : 53368 : rInf.First( nTmpFirst );
1857 : :
1858 : 53368 : rInf.RealWidth( KSHORT(rInf.Right()) - KSHORT(GetLeftMargin()) );
1859 : 53368 : rInf.Width( rInf.RealWidth() );
1860 [ - + ]: 53368 : if( ((SwTxtFormatter*)this)->GetRedln() )
1861 : : {
1862 : 0 : ((SwTxtFormatter*)this)->GetRedln()->Clear( ((SwTxtFormatter*)this)->GetFnt() );
1863 : 0 : ((SwTxtFormatter*)this)->GetRedln()->Reset();
1864 : : }
1865 : 53368 : }
1866 : :
1867 : : /*************************************************************************
1868 : : * SwTxtFormatter::FormatReset()
1869 : : *************************************************************************/
1870 : :
1871 : 53368 : void SwTxtFormatter::FormatReset( SwTxtFormatInfo &rInf )
1872 : : {
1873 : 53368 : pCurr->Truncate();
1874 : 53368 : pCurr->Init();
1875 [ - + ][ - + ]: 53368 : if( pBlink && pCurr->IsBlinking() )
[ + + ]
1876 : 0 : pBlink->Delete( pCurr );
1877 : :
1878 : : // delete pSpaceAdd und pKanaComp
1879 : 53368 : pCurr->FinishSpaceAdd();
1880 : 53368 : pCurr->FinishKanaComp();
1881 : 53368 : pCurr->ResetFlags();
1882 : 53368 : FeedInf( rInf );
1883 : 53368 : }
1884 : :
1885 : : /*************************************************************************
1886 : : * SwTxtFormatter::CalcOnceMore()
1887 : : *************************************************************************/
1888 : :
1889 : 0 : sal_Bool SwTxtFormatter::CalcOnceMore()
1890 : : {
1891 [ # # ]: 0 : if( pDropFmt )
1892 : : {
1893 : 0 : const KSHORT nOldDrop = GetDropHeight();
1894 : 0 : CalcDropHeight( pDropFmt->GetLines() );
1895 : 0 : bOnceMore = nOldDrop != GetDropHeight();
1896 : : }
1897 : : else
1898 : 0 : bOnceMore = sal_False;
1899 : 0 : return bOnceMore;
1900 : : }
1901 : :
1902 : : /*************************************************************************
1903 : : * SwTxtFormatter::CalcBottomLine()
1904 : : *************************************************************************/
1905 : :
1906 : 14711 : SwTwips SwTxtFormatter::CalcBottomLine() const
1907 : : {
1908 : 14711 : SwTwips nRet = Y() + GetLineHeight();
1909 : 14711 : SwTwips nMin = GetInfo().GetTxtFly()->GetMinBottom();
1910 [ # # ][ - + ]: 14711 : if( nMin && ++nMin > nRet )
[ - + ]
1911 : : {
1912 : 0 : SwTwips nDist = pFrm->Frm().Height() - pFrm->Prt().Height()
1913 : 0 : - pFrm->Prt().Top();
1914 [ # # ]: 0 : if( nRet + nDist < nMin )
1915 : : {
1916 : 0 : sal_Bool bRepaint = HasTruncLines() &&
1917 [ # # ][ # # ]: 0 : GetInfo().GetParaPortion()->GetRepaint()->Bottom() == nRet-1;
1918 : 0 : nRet = nMin - nDist;
1919 [ # # ]: 0 : if( bRepaint )
1920 : : {
1921 : 0 : ((SwRepaint*)GetInfo().GetParaPortion()
1922 : 0 : ->GetRepaint())->Bottom( nRet-1 );
1923 : 0 : ((SwTxtFormatInfo&)GetInfo()).SetPaintOfst( 0 );
1924 : : }
1925 : : }
1926 : : }
1927 : 14711 : return nRet;
1928 : : }
1929 : :
1930 : : /*************************************************************************
1931 : : * SwTxtFormatter::_CalcFitToContent()
1932 : : *
1933 : : * FME/OD: This routine does a limited text formatting.
1934 : : *************************************************************************/
1935 : :
1936 : 90 : SwTwips SwTxtFormatter::_CalcFitToContent()
1937 : : {
1938 : 90 : FormatReset( GetInfo() );
1939 : 90 : BuildPortions( GetInfo() );
1940 : 90 : pCurr->CalcLine( *this, GetInfo() );
1941 : 90 : return pCurr->Width();
1942 : : }
1943 : :
1944 : : /*************************************************************************
1945 : : * SwTxtFormatter::AllowRepaintOpt()
1946 : : *
1947 : : * determines if the calculation of a repaint offset is allowed
1948 : : * otherwise each line is painted from 0 (this is a copy of the beginning
1949 : : * of the former SwTxtFormatter::Recycle() function
1950 : : *************************************************************************/
1951 : 52762 : sal_Bool SwTxtFormatter::AllowRepaintOpt() const
1952 : : {
1953 : : // reformat position in front of current line? Only in this case
1954 : : // we want to set the repaint offset
1955 : 52762 : sal_Bool bOptimizeRepaint = nStart < GetInfo().GetReformatStart() &&
1956 [ + - ][ + + ]: 52762 : pCurr->GetLen();
1957 : :
1958 : : // a special case is the last line of a block adjusted paragraph:
1959 [ + + ]: 52762 : if ( bOptimizeRepaint )
1960 : : {
1961 [ - + + ]: 3748 : switch( GetAdjust() )
1962 : : {
1963 : : case SVX_ADJUST_BLOCK:
1964 : : {
1965 [ # # ][ # # ]: 0 : if( IsLastBlock() || IsLastCenter() )
[ # # ]
1966 : 0 : bOptimizeRepaint = sal_False;
1967 : : else
1968 : : {
1969 : : // ????: Blank in der letzten Masterzeile (blocksat.sdw)
1970 [ # # ][ # # ]: 0 : bOptimizeRepaint = 0 == pCurr->GetNext() && !pFrm->GetFollow();
1971 [ # # ]: 0 : if ( bOptimizeRepaint )
1972 : : {
1973 : 0 : SwLinePortion *pPos = pCurr->GetFirstPortion();
1974 [ # # ][ # # ]: 0 : while ( pPos && !pPos->IsFlyPortion() )
[ # # ]
1975 : 0 : pPos = pPos->GetPortion();
1976 : 0 : bOptimizeRepaint = !pPos;
1977 : : }
1978 : : }
1979 : 0 : break;
1980 : : }
1981 : : case SVX_ADJUST_CENTER:
1982 : : case SVX_ADJUST_RIGHT:
1983 : 4 : bOptimizeRepaint = sal_False;
1984 : 3748 : break;
1985 : : default: ;
1986 : : }
1987 : : }
1988 : :
1989 : : // Schon wieder ein Sonderfall: unsichtbare SoftHyphs
1990 : 52762 : const xub_StrLen nReformat = GetInfo().GetReformatStart();
1991 [ + - ][ + + ]: 52762 : if( bOptimizeRepaint && STRING_LEN != nReformat )
1992 : : {
1993 : 3744 : const xub_Unicode cCh = GetInfo().GetTxt().GetChar( nReformat );
1994 : : bOptimizeRepaint = ( CH_TXTATR_BREAKWORD != cCh && CH_TXTATR_INWORD != cCh )
1995 [ + + ][ - + ]: 3744 : || ! GetInfo().HasHint( nReformat );
[ + + ]
1996 : : }
1997 : :
1998 : 52762 : return bOptimizeRepaint;
1999 : : }
2000 : :
2001 : 0 : void SwTxtFormatter::CalcUnclipped( SwTwips& rTop, SwTwips& rBottom )
2002 : : {
2003 : : OSL_ENSURE( ! pFrm->IsVertical() || pFrm->IsSwapped(),
2004 : : "SwTxtFormatter::CalcUnclipped with unswapped frame" );
2005 : :
2006 : : long nFlyAsc, nFlyDesc;
2007 [ # # ]: 0 : pCurr->MaxAscentDescent( rTop, rBottom, nFlyAsc, nFlyDesc );
2008 : 0 : rTop = Y() + GetCurr()->GetAscent();
2009 : 0 : rBottom = rTop + nFlyDesc;
2010 : 0 : rTop -= nFlyAsc;
2011 : 0 : }
2012 : :
2013 : :
2014 : 12081 : void SwTxtFormatter::UpdatePos( SwLineLayout *pCurrent, Point aStart,
2015 : : xub_StrLen nStartIdx, sal_Bool bAllWays ) const
2016 : : {
2017 : : OSL_ENSURE( ! pFrm->IsVertical() || pFrm->IsSwapped(),
2018 : : "SwTxtFormatter::UpdatePos with unswapped frame" );
2019 : :
2020 [ + - ]: 12081 : if( GetInfo().IsTest() )
2021 : 12081 : return;
2022 : 12081 : SwLinePortion *pFirst = pCurrent->GetFirstPortion();
2023 : 12081 : SwLinePortion *pPos = pFirst;
2024 [ + - ]: 12081 : SwTxtPaintInfo aTmpInf( GetInfo() );
2025 : 12081 : aTmpInf.SetpSpaceAdd( pCurrent->GetpLLSpaceAdd() );
2026 : 12081 : aTmpInf.ResetSpaceIdx();
2027 : 12081 : aTmpInf.SetKanaComp( pCurrent->GetpKanaComp() );
2028 : 12081 : aTmpInf.ResetKanaIdx();
2029 : :
2030 : : // The frame's size
2031 : 12081 : aTmpInf.SetIdx( nStartIdx );
2032 : 12081 : aTmpInf.SetPos( aStart );
2033 : :
2034 : : long nTmpAscent, nTmpDescent, nFlyAsc, nFlyDesc;
2035 [ + - ]: 12081 : pCurrent->MaxAscentDescent( nTmpAscent, nTmpDescent, nFlyAsc, nFlyDesc );
2036 : :
2037 : 12081 : KSHORT nTmpHeight = pCurrent->GetRealHeight();
2038 : 12081 : KSHORT nAscent = pCurrent->GetAscent() + nTmpHeight - pCurrent->Height();
2039 : 12081 : objectpositioning::AsCharFlags nFlags = AS_CHAR_ULSPACE;
2040 [ - + ]: 12081 : if( GetMulti() )
2041 : : {
2042 : 0 : aTmpInf.SetDirection( GetMulti()->GetDirection() );
2043 [ # # ]: 0 : if( GetMulti()->HasRotation() )
2044 : : {
2045 : 0 : nFlags |= AS_CHAR_ROTATE;
2046 [ # # ]: 0 : if( GetMulti()->IsRevers() )
2047 : : {
2048 : 0 : nFlags |= AS_CHAR_REVERSE;
2049 : 0 : aTmpInf.X( aTmpInf.X() - nAscent );
2050 : : }
2051 : : else
2052 : 0 : aTmpInf.X( aTmpInf.X() + nAscent );
2053 : : }
2054 : : else
2055 : : {
2056 [ # # ]: 0 : if ( GetMulti()->IsBidi() )
2057 : 0 : nFlags |= AS_CHAR_BIDI;
2058 : 0 : aTmpInf.Y( aTmpInf.Y() + nAscent );
2059 : : }
2060 : : }
2061 : : else
2062 : 12081 : aTmpInf.Y( aTmpInf.Y() + nAscent );
2063 : :
2064 [ + + ]: 25610 : while( pPos )
2065 : : {
2066 : : // We only know one case where changing the position (caused by the
2067 : : // adjustment) could be relevant for a portion: We need to SetRefPoint
2068 : : // for FlyCntPortions.
2069 [ + + ][ - + ]: 14795 : if( ( pPos->IsFlyCntPortion() || pPos->IsGrfNumPortion() )
[ + + ][ + - ]
[ + + ]
2070 [ + - ]: 1266 : && ( bAllWays || !IsQuick() ) )
2071 : : {
2072 [ + - ]: 1269 : pCurrent->MaxAscentDescent( nTmpAscent, nTmpDescent, nFlyAsc, nFlyDesc, pPos );
2073 : :
2074 [ - + ]: 1269 : if( pPos->IsGrfNumPortion() )
2075 : : {
2076 [ # # ][ # # ]: 0 : if( !nFlyAsc && !nFlyDesc )
2077 : : {
2078 : 0 : nTmpAscent = nAscent;
2079 : 0 : nFlyAsc = nAscent;
2080 : 0 : nTmpDescent = nTmpHeight - nAscent;
2081 : 0 : nFlyDesc = nTmpDescent;
2082 : : }
2083 : : ((SwGrfNumPortion*)pPos)->SetBase( nTmpAscent, nTmpDescent,
2084 [ # # ]: 0 : nFlyAsc, nFlyDesc );
2085 : : }
2086 : : else
2087 : : {
2088 : 1269 : Point aBase( aTmpInf.GetPos() );
2089 [ - + ][ + - ]: 1269 : if ( GetInfo().GetTxtFrm()->IsVertical() )
2090 [ # # ]: 0 : GetInfo().GetTxtFrm()->SwitchHorizontalToVertical( aBase );
2091 : :
2092 : 1269 : ((SwFlyCntPortion*)pPos)->SetBase( *aTmpInf.GetTxtFrm(),
2093 : : aBase, nTmpAscent, nTmpDescent, nFlyAsc,
2094 [ + - ]: 1269 : nFlyDesc, nFlags );
2095 : : }
2096 : : }
2097 [ + + ][ - + ]: 13529 : if( pPos->IsMultiPortion() && ((SwMultiPortion*)pPos)->HasFlyInCntnt() )
[ - + ]
2098 : : {
2099 : : OSL_ENSURE( !GetMulti(), "Too much multi" );
2100 : 0 : ((SwTxtFormatter*)this)->pMulti = (SwMultiPortion*)pPos;
2101 : 0 : SwLineLayout *pLay = &GetMulti()->GetRoot();
2102 : 0 : Point aSt( aTmpInf.X(), aStart.Y() );
2103 : :
2104 [ # # ][ # # ]: 0 : if ( GetMulti()->HasBrackets() )
2105 : : {
2106 : : OSL_ENSURE( GetMulti()->IsDouble(), "Brackets only for doubles");
2107 : 0 : aSt.X() += ((SwDoubleLinePortion*)GetMulti())->PreWidth();
2108 : : }
2109 [ # # ]: 0 : else if( GetMulti()->HasRotation() )
2110 : : {
2111 : 0 : aSt.Y() += pCurrent->GetAscent() - GetMulti()->GetAscent();
2112 [ # # ]: 0 : if( GetMulti()->IsRevers() )
2113 : 0 : aSt.X() += GetMulti()->Width();
2114 : : else
2115 : 0 : aSt.Y() += GetMulti()->Height();
2116 : : }
2117 [ # # ]: 0 : else if ( GetMulti()->IsBidi() )
2118 : : // jump to end of the bidi portion
2119 : 0 : aSt.X() += pLay->Width();
2120 : :
2121 : 0 : xub_StrLen nStIdx = aTmpInf.GetIdx();
2122 [ # # ]: 0 : do
2123 : : {
2124 [ # # ]: 0 : UpdatePos( pLay, aSt, nStIdx, bAllWays );
2125 : 0 : nStIdx = nStIdx + pLay->GetLen();
2126 : 0 : aSt.Y() += pLay->Height();
2127 : 0 : pLay = pLay->GetNext();
2128 : : } while ( pLay );
2129 : 0 : ((SwTxtFormatter*)this)->pMulti = NULL;
2130 : : }
2131 [ + - ]: 13529 : pPos->Move( aTmpInf );
2132 : 13529 : pPos = pPos->GetPortion();
2133 [ + - ]: 12081 : }
2134 : : }
2135 : :
2136 : :
2137 : 939 : void SwTxtFormatter::AlignFlyInCntBase( long nBaseLine ) const
2138 : : {
2139 : : OSL_ENSURE( ! pFrm->IsVertical() || pFrm->IsSwapped(),
2140 : : "SwTxtFormatter::AlignFlyInCntBase with unswapped frame" );
2141 : :
2142 [ + - ]: 939 : if( GetInfo().IsTest() )
2143 : 939 : return;
2144 : 939 : SwLinePortion *pFirst = pCurr->GetFirstPortion();
2145 : 939 : SwLinePortion *pPos = pFirst;
2146 : 939 : objectpositioning::AsCharFlags nFlags = AS_CHAR_NOFLAG;
2147 [ # # ][ - + ]: 939 : if( GetMulti() && GetMulti()->HasRotation() )
[ - + ]
2148 : : {
2149 : 0 : nFlags |= AS_CHAR_ROTATE;
2150 [ # # ]: 0 : if( GetMulti()->IsRevers() )
2151 : 0 : nFlags |= AS_CHAR_REVERSE;
2152 : : }
2153 : :
2154 : : long nTmpAscent, nTmpDescent, nFlyAsc, nFlyDesc;
2155 : :
2156 [ + + ]: 2233 : while( pPos )
2157 : : {
2158 [ + + ][ - + ]: 1294 : if( pPos->IsFlyCntPortion() || pPos->IsGrfNumPortion() )
[ + + ]
2159 : : {
2160 [ + - ]: 1266 : pCurr->MaxAscentDescent( nTmpAscent, nTmpDescent, nFlyAsc, nFlyDesc, pPos );
2161 : :
2162 [ - + ]: 1266 : if( pPos->IsGrfNumPortion() )
2163 : : ((SwGrfNumPortion*)pPos)->SetBase( nTmpAscent, nTmpDescent,
2164 [ # # ]: 0 : nFlyAsc, nFlyDesc );
2165 : : else
2166 : : {
2167 : 1266 : Point aBase;
2168 [ - + ][ + - ]: 1266 : if ( GetInfo().GetTxtFrm()->IsVertical() )
2169 : : {
2170 [ # # ]: 0 : nBaseLine = GetInfo().GetTxtFrm()->SwitchHorizontalToVertical( nBaseLine );
2171 : 0 : aBase = Point( nBaseLine, ((SwFlyCntPortion*)pPos)->GetRefPoint().Y() );
2172 : : }
2173 : : else
2174 : 1266 : aBase = Point( ((SwFlyCntPortion*)pPos)->GetRefPoint().X(), nBaseLine );
2175 : :
2176 : 1266 : ((SwFlyCntPortion*)pPos)->SetBase( *GetInfo().GetTxtFrm(), aBase, nTmpAscent, nTmpDescent,
2177 [ + - ]: 1266 : nFlyAsc, nFlyDesc, nFlags );
2178 : : }
2179 : : }
2180 : 1294 : pPos = pPos->GetPortion();
2181 : : }
2182 : : }
2183 : :
2184 : :
2185 : 616 : sal_Bool SwTxtFormatter::ChkFlyUnderflow( SwTxtFormatInfo &rInf ) const
2186 : : {
2187 : : OSL_ENSURE( rInf.GetTxtFly()->IsOn(), "SwTxtFormatter::ChkFlyUnderflow: why?" );
2188 [ + - ]: 616 : if( GetCurr() )
2189 : : {
2190 : : // First we check, whether a fly overlaps with the line.
2191 : : // = GetLineHeight()
2192 : 616 : const long nHeight = GetCurr()->GetRealHeight();
2193 [ + - ]: 616 : SwRect aLine( GetLeftMargin(), Y(), rInf.RealWidth(), nHeight );
2194 : :
2195 : 616 : SwRect aLineVert( aLine );
2196 [ - + ][ + - ]: 616 : if ( pFrm->IsVertical() )
2197 [ # # ]: 0 : pFrm->SwitchHorizontalToVertical( aLineVert );
2198 [ + - ]: 616 : SwRect aInter( rInf.GetTxtFly()->GetFrm( aLineVert ) );
2199 [ + - ][ - + ]: 616 : if ( pFrm->IsVertical() )
2200 [ # # ]: 0 : pFrm->SwitchVerticalToHorizontal( aInter );
2201 : :
2202 [ + - ][ + + ]: 616 : if( !aInter.HasArea() )
2203 : 234 : return sal_False;
2204 : :
2205 : : // We now check every portion that could have lowered for overlapping
2206 : : // with the fly.
2207 : 382 : const SwLinePortion *pPos = GetCurr()->GetFirstPortion();
2208 : 382 : aLine.Pos().Y() = Y() + GetCurr()->GetRealHeight() - GetCurr()->Height();
2209 : 382 : aLine.Height( GetCurr()->Height() );
2210 : :
2211 [ + + ]: 1264 : while( pPos )
2212 : : {
2213 : 648 : aLine.Width( pPos->Width() );
2214 : :
2215 : 648 : aLineVert = aLine;
2216 [ - + ][ + - ]: 648 : if ( pFrm->IsVertical() )
2217 [ # # ]: 0 : pFrm->SwitchHorizontalToVertical( aLineVert );
2218 [ + - ]: 648 : aInter = rInf.GetTxtFly()->GetFrm( aLineVert );
2219 [ - + ][ + - ]: 648 : if ( pFrm->IsVertical() )
2220 [ # # ]: 0 : pFrm->SwitchVerticalToHorizontal( aInter );
2221 : :
2222 : : // New flys from below?
2223 [ + + ]: 648 : if( !pPos->IsFlyPortion() )
2224 : : {
2225 [ + - ][ - + ]: 529 : if( aInter.IsOver( aLine ) )
2226 : : {
2227 [ # # ]: 0 : aInter._Intersection( aLine );
2228 [ # # ][ # # ]: 0 : if( aInter.HasArea() )
2229 : : {
2230 : : // To be evaluated during reformat of this line:
2231 : : // RealHeight including spacing
2232 : 0 : rInf.SetLineHeight( KSHORT(nHeight) );
2233 : : // Height without extra spacing
2234 : 0 : rInf.SetLineNettoHeight( KSHORT( pCurr->Height() ) );
2235 : 0 : return sal_True;
2236 : : }
2237 : : }
2238 : : }
2239 : : else
2240 : : {
2241 : : // The fly portion is not intersected by a fly anymore
2242 [ + - ][ - + ]: 119 : if ( ! aInter.IsOver( aLine ) )
2243 : : {
2244 : 0 : rInf.SetLineHeight( KSHORT(nHeight) );
2245 : 0 : rInf.SetLineNettoHeight( KSHORT( pCurr->Height() ) );
2246 : 0 : return sal_True;
2247 : : }
2248 : : else
2249 : : {
2250 [ + - ]: 119 : aInter._Intersection( aLine );
2251 : :
2252 : : // No area means a fly has become invalid because of
2253 : : // lowering the line => reformat the line
2254 : : // we also have to reformat the line, if the fly size
2255 : : // differs from the intersection interval's size.
2256 [ + - ]: 238 : if( ! aInter.HasArea() ||
[ + - - + ]
[ - + ]
2257 : 119 : ((SwFlyPortion*)pPos)->GetFixWidth() != aInter.Width() )
2258 : : {
2259 : 0 : rInf.SetLineHeight( KSHORT(nHeight) );
2260 : 0 : rInf.SetLineNettoHeight( KSHORT( pCurr->Height() ) );
2261 : 0 : return sal_True;
2262 : : }
2263 : : }
2264 : : }
2265 : :
2266 : 648 : aLine.Left( aLine.Left() + pPos->Width() );
2267 : 648 : pPos = pPos->GetPortion();
2268 : : }
2269 : : }
2270 : 616 : return sal_False;
2271 : : }
2272 : :
2273 : 121553 : void SwTxtFormatter::CalcFlyWidth( SwTxtFormatInfo &rInf )
2274 : : {
2275 [ + + ][ + + ]: 121553 : if( GetMulti() || rInf.GetFly() )
[ + + ]
2276 : : return;
2277 : :
2278 : 118848 : SwTxtFly *pTxtFly = rInf.GetTxtFly();
2279 [ + + ][ + + ]: 118848 : if( !pTxtFly->IsOn() || rInf.IsIgnoreFly() )
[ + + ]
2280 : : return;
2281 : :
2282 : 1856 : const SwLinePortion *pLast = rInf.GetLast();
2283 : :
2284 : : long nAscent;
2285 : 1856 : long nTop = Y();
2286 : : long nHeight;
2287 : :
2288 [ - + ]: 1856 : if( rInf.GetLineHeight() )
2289 : : {
2290 : : // Real line height has already been calculated, we only have to
2291 : : // search for intersections in the lower part of the strip
2292 : 0 : nAscent = pCurr->GetAscent();
2293 : 0 : nHeight = rInf.GetLineNettoHeight();
2294 : 0 : nTop += rInf.GetLineHeight() - nHeight;
2295 : : }
2296 : : else
2297 : : {
2298 : 1856 : nAscent = pLast->GetAscent();
2299 : 1856 : nHeight = pLast->Height();
2300 : :
2301 : : // We make a first guess for the lines real height
2302 [ + + ]: 1856 : if ( ! pCurr->GetRealHeight() )
2303 [ + - ]: 1120 : CalcRealHeight();
2304 : :
2305 [ + + ]: 1856 : if ( pCurr->GetRealHeight() > nHeight )
2306 : 5 : nTop += pCurr->GetRealHeight() - nHeight;
2307 : : else
2308 : : // Important for fixed space between lines
2309 : 1851 : nHeight = pCurr->GetRealHeight();
2310 : : }
2311 : :
2312 [ + - ]: 1856 : const long nLeftMar = GetLeftMargin();
2313 [ + + ][ + - ]: 1856 : const long nLeftMin = (rInf.X() || GetDropLeft()) ? nLeftMar : GetLeftMin();
2314 : :
2315 : 1856 : SwRect aLine( rInf.X() + nLeftMin, nTop, rInf.RealWidth() - rInf.X()
2316 : 1856 : + nLeftMar - nLeftMin , nHeight );
2317 : :
2318 : 1856 : SwRect aLineVert( aLine );
2319 [ - + ][ + - ]: 1856 : if ( pFrm->IsRightToLeft() )
2320 [ # # ]: 0 : pFrm->SwitchLTRtoRTL( aLineVert );
2321 : :
2322 [ + - ][ - + ]: 1856 : if ( pFrm->IsVertical() )
2323 [ # # ]: 0 : pFrm->SwitchHorizontalToVertical( aLineVert );
2324 [ + - ]: 1856 : SwRect aInter( pTxtFly->GetFrm( aLineVert ) );
2325 : :
2326 [ + - ][ - + ]: 1856 : if ( pFrm->IsRightToLeft() )
2327 [ # # ]: 0 : pFrm->SwitchRTLtoLTR( aInter );
2328 : :
2329 [ + - ][ - + ]: 1856 : if ( pFrm->IsVertical() )
2330 [ # # ]: 0 : pFrm->SwitchVerticalToHorizontal( aInter );
2331 : :
2332 [ + - ][ + + ]: 1856 : if( aInter.IsOver( aLine ) )
2333 : : {
2334 : 729 : aLine.Left( rInf.X() + nLeftMar );
2335 : 729 : sal_Bool bForced = sal_False;
2336 [ + + ]: 729 : if( aInter.Left() <= nLeftMin )
2337 : : {
2338 : 38 : SwTwips nFrmLeft = GetTxtFrm()->Frm().Left();
2339 [ - + ]: 38 : if( GetTxtFrm()->Prt().Left() < 0 )
2340 : 0 : nFrmLeft += GetTxtFrm()->Prt().Left();
2341 [ + + ]: 38 : if( aInter.Left() < nFrmLeft )
2342 : 25 : aInter.Left( nFrmLeft );
2343 : :
2344 : 38 : long nAddMar = 0;
2345 [ + - ][ - + ]: 38 : if ( pFrm->IsRightToLeft() )
2346 : : {
2347 : 0 : nAddMar = pFrm->Frm().Right() - Right();
2348 [ # # ]: 0 : if ( nAddMar < 0 )
2349 : 0 : nAddMar = 0;
2350 : : }
2351 : : else
2352 : 38 : nAddMar = nLeftMar - nFrmLeft;
2353 : :
2354 : 38 : aInter.Width( aInter.Width() + nAddMar );
2355 : : // For a negative first line indent, we set this flag to show
2356 : : // that the indentation/margin has been moved.
2357 : : // This needs to be respected by the DefaultTab at the zero position.
2358 [ + - ][ - + ]: 38 : if( IsFirstTxtLine() && HasNegFirst() )
[ - + ][ + - ]
2359 : 0 : bForced = sal_True;
2360 : : }
2361 [ + - ]: 729 : aInter.Intersection( aLine );
2362 [ + - ][ + - ]: 729 : if( !aInter.HasArea() )
2363 : : return;
2364 : :
2365 : 729 : const sal_Bool bFullLine = aLine.Left() == aInter.Left() &&
2366 [ + + ][ + + ]: 729 : aLine.Right() == aInter.Right();
2367 : :
2368 : : // Although no text is left, we need to format another line,
2369 : : // because also empty lines need to avoid a Fly with no wrapping.
2370 [ + + ][ + - ]: 729 : if( bFullLine && rInf.GetIdx() == rInf.GetTxt().Len() )
[ + + ]
2371 : : {
2372 : 14 : rInf.SetNewLine( sal_True );
2373 : : // 8221: We know that for dummies, it holds ascent == height
2374 : 14 : pCurr->SetDummy(sal_True);
2375 : : }
2376 : :
2377 : : // aInter becomes frame-local
2378 : 729 : aInter.Pos().X() -= nLeftMar;
2379 [ + - ][ + - ]: 729 : SwFlyPortion *pFly = new SwFlyPortion( aInter );
2380 [ - + ]: 729 : if( bForced )
2381 : : {
2382 : 0 : pCurr->SetForcedLeftMargin( sal_True );
2383 : 0 : rInf.ForcedLeftMargin( (sal_uInt16)aInter.Width() );
2384 : : }
2385 : :
2386 [ + + ]: 729 : if( bFullLine )
2387 : : {
2388 : : // 8110: In order to properly flow around Flys with different
2389 : : // wrapping attributes, we need to increase by units of line height.
2390 : : // The last avoiding line should be adjusted in height, so that
2391 : : // we don't get a frame spacing effect.
2392 : : // 8221: It is important that ascent == height, because the FlyPortion
2393 : : // values are transferred to pCurr in CalcLine and IsDummy() relies
2394 : : // on this behaviour.
2395 : : // To my knowledge we only have two places where DummyLines can be
2396 : : // created: here and in MakeFlyDummies.
2397 : : // IsDummy() is evaluated in IsFirstTxtLine(), when moving lines
2398 : : // and in relation with DropCaps.
2399 : 14 : pFly->Height( KSHORT(aInter.Height()) );
2400 : :
2401 : : // nNextTop now contains the margin's bottom edge, which we avoid
2402 : : // or the next margin's top edge, which we need to respect.
2403 : : // That means we can comfortably grow up to this value; that's how
2404 : : // we save a few empty lines.
2405 : 14 : long nNextTop = pTxtFly->GetNextTop();
2406 [ - + ][ + - ]: 14 : if ( pFrm->IsVertical() )
2407 [ # # ]: 0 : nNextTop = pFrm->SwitchVerticalToHorizontal( nNextTop );
2408 [ + - ]: 14 : if( nNextTop > aInter.Bottom() )
2409 : : {
2410 : 14 : SwTwips nH = nNextTop - aInter.Top();
2411 [ + - ]: 14 : if( nH < KSHRT_MAX )
2412 : 14 : pFly->Height( KSHORT( nH ) );
2413 : : }
2414 [ + - ]: 14 : if( nAscent < pFly->Height() )
2415 : 14 : pFly->SetAscent( KSHORT(nAscent) );
2416 : : else
2417 : 0 : pFly->SetAscent( pFly->Height() );
2418 : : }
2419 : : else
2420 : : {
2421 [ + + ]: 715 : if( rInf.GetIdx() == rInf.GetTxt().Len() )
2422 : : {
2423 : : // Don't use nHeight, or we have a huge descent
2424 : 263 : pFly->Height( pLast->Height() );
2425 : 263 : pFly->SetAscent( pLast->GetAscent() );
2426 : : }
2427 : : else
2428 : : {
2429 : 452 : pFly->Height( KSHORT(aInter.Height()) );
2430 [ + + ]: 452 : if( nAscent < pFly->Height() )
2431 : 414 : pFly->SetAscent( KSHORT(nAscent) );
2432 : : else
2433 : 38 : pFly->SetAscent( pFly->Height() );
2434 : : }
2435 : : }
2436 : :
2437 : 729 : rInf.SetFly( pFly );
2438 : :
2439 [ + + ]: 729 : if( pFly->Fix() < rInf.Width() )
2440 : 385 : rInf.Width( pFly->Fix() );
2441 : :
2442 [ + - ][ + - ]: 729 : GETGRID( pFrm->FindPageFrm() )
[ + - ][ - + ]
[ # # ][ # # ]
[ # # ][ - + ]
2443 [ - + ]: 729 : if ( pGrid )
2444 : : {
2445 [ # # ]: 0 : const SwPageFrm* pPageFrm = pFrm->FindPageFrm();
2446 [ # # ]: 0 : const SwLayoutFrm* pBody = pPageFrm->FindBodyCont();
2447 : :
2448 [ # # ][ # # ]: 0 : SWRECTFN( pPageFrm )
[ # # ][ # # ]
[ # # ]
2449 : :
2450 : : const long nGridOrigin = pBody ?
2451 [ # # ]: 0 : (pBody->*fnRect->fnGetPrtLeft)() :
2452 [ # # ][ # # ]: 0 : (pPageFrm->*fnRect->fnGetPrtLeft)();
[ # # ][ # # ]
2453 : :
2454 : 0 : const SwDoc *pDoc = rInf.GetTxtFrm()->GetNode()->GetDoc();
2455 [ # # ][ # # ]: 0 : const sal_uInt16 nGridWidth = GETGRIDWIDTH( pGrid, pDoc); //For textgrid refactor
2456 : :
2457 [ # # ]: 0 : SwTwips nStartX = GetLeftMargin();
2458 [ # # ]: 0 : if ( bVert )
2459 : : {
2460 : 0 : Point aPoint( nStartX, 0 );
2461 [ # # ]: 0 : pFrm->SwitchHorizontalToVertical( aPoint );
2462 : 0 : nStartX = aPoint.Y();
2463 : : }
2464 : :
2465 : 0 : const SwTwips nOfst = nStartX - nGridOrigin;
2466 : 0 : const SwTwips nTmpWidth = rInf.Width() + nOfst;
2467 : :
2468 : 0 : const sal_uLong i = nTmpWidth / nGridWidth + 1;
2469 : :
2470 : 0 : const long nNewWidth = ( i - 1 ) * nGridWidth - nOfst;
2471 [ # # ]: 0 : if ( nNewWidth > 0 )
2472 : 0 : rInf.Width( (sal_uInt16)nNewWidth );
2473 : : else
2474 : 121553 : rInf.Width( 0 );
2475 : : }
2476 : : }
2477 : : }
2478 : :
2479 : :
2480 : 1290 : SwFlyCntPortion *SwTxtFormatter::NewFlyCntPortion( SwTxtFormatInfo &rInf,
2481 : : SwTxtAttr *pHint ) const
2482 : : {
2483 : 1290 : SwFlyCntPortion *pRet = 0;
2484 : 1290 : const SwFrm *pFrame = (SwFrm*)pFrm;
2485 : :
2486 : : SwFlyInCntFrm *pFly;
2487 : 1290 : SwFrmFmt* pFrmFmt = ((SwTxtFlyCnt*)pHint)->GetFlyCnt().GetFrmFmt();
2488 [ + + ]: 1290 : if( RES_FLYFRMFMT == pFrmFmt->Which() )
2489 [ + - ]: 562 : pFly = ((SwTxtFlyCnt*)pHint)->GetFlyFrm(pFrame);
2490 : : else
2491 : 728 : pFly = NULL;
2492 : : // aBase is the document-global position, from which the new extra portion is placed
2493 : : // aBase.X() = Offset in in the line after the current position
2494 : : // aBase.Y() = LineIter.Y() + Ascent of the current position
2495 : :
2496 : : long nTmpAscent, nTmpDescent, nFlyAsc, nFlyDesc;
2497 : : // OD 08.01.2004 #i11859# - use new method <SwLineLayout::MaxAscentDescent(..)>
2498 : : //SwLinePortion *pPos = pCurr->GetFirstPortion();
2499 : : //lcl_MaxAscDescent( pPos, nTmpAscent, nTmpDescent, nFlyAsc, nFlyDesc );
2500 [ + - ]: 1290 : pCurr->MaxAscentDescent( nTmpAscent, nTmpDescent, nFlyAsc, nFlyDesc );
2501 : :
2502 : : // If the ascent of the frame is larger than the ascent of the current position,
2503 : : // we use this one when calculating the base, or the frame would be positioned
2504 : : // too much to the top, sliding down after all causing a repaint in an area
2505 : : // he actually never was in.
2506 : 1290 : KSHORT nAscent = 0;
2507 : :
2508 [ + - ]: 1290 : const bool bTxtFrmVertical = GetInfo().GetTxtFrm()->IsVertical();
2509 : :
2510 : 562 : const bool bUseFlyAscent = pFly && pFly->GetValidPosFlag() &&
2511 : : 0 != ( bTxtFrmVertical ?
2512 : 0 : pFly->GetRefPoint().X() :
2513 [ + + + + ]: 1852 : pFly->GetRefPoint().Y() );
[ - + # # ]
[ + + ]
2514 : :
2515 [ + + ]: 1290 : if ( bUseFlyAscent )
2516 : : nAscent = static_cast<sal_uInt16>( Abs( int( bTxtFrmVertical ?
2517 [ # # ][ - + ]: 92 : pFly->GetRelPos().X() :
[ # # ]
2518 [ - + ][ + - ]: 92 : pFly->GetRelPos().Y() ) ) );
[ + - ][ # # ]
2519 : :
2520 : : // Check if be prefer to use the ascent of the last portion:
2521 [ + - ][ + - ]: 1382 : if ( IsQuick() ||
[ + + + + ]
[ + + ]
2522 : 1290 : !bUseFlyAscent ||
2523 : 92 : nAscent < rInf.GetLast()->GetAscent() )
2524 : : {
2525 : 1206 : nAscent = rInf.GetLast()->GetAscent();
2526 : : }
2527 [ + - ]: 84 : else if( nAscent > nFlyAsc )
2528 : 84 : nFlyAsc = nAscent;
2529 : :
2530 [ + - ]: 1290 : Point aBase( GetLeftMargin() + rInf.X(), Y() + nAscent );
2531 [ - + ][ + - ]: 1290 : objectpositioning::AsCharFlags nMode = IsQuick() ? AS_CHAR_QUICK : 0;
2532 [ - + ][ # # ]: 1290 : if( GetMulti() && GetMulti()->HasRotation() )
[ - + ]
2533 : : {
2534 : 0 : nMode |= AS_CHAR_ROTATE;
2535 [ # # ]: 0 : if( GetMulti()->IsRevers() )
2536 : 0 : nMode |= AS_CHAR_REVERSE;
2537 : : }
2538 : :
2539 : 1290 : Point aTmpBase( aBase );
2540 [ + - ][ - + ]: 1290 : if ( GetInfo().GetTxtFrm()->IsVertical() )
2541 [ # # ]: 0 : GetInfo().GetTxtFrm()->SwitchHorizontalToVertical( aTmpBase );
2542 : :
2543 [ + + ]: 1290 : if( pFly )
2544 : : {
2545 : 562 : pRet = new SwFlyCntPortion( *GetInfo().GetTxtFrm(), pFly, aTmpBase,
2546 [ + - ][ + - ]: 562 : nTmpAscent, nTmpDescent, nFlyAsc, nFlyDesc, nMode );
2547 : : // We need to make sure that our font is set again in the OutputDevice
2548 : : // It could be that the FlyInCnt was added anew and GetFlyFrm() would
2549 : : // in turn cause, that it'd be created anew again.
2550 : : // This one's frames get formatted right away, which change the font and
2551 : : // we have a bug (3322).
2552 [ + - ]: 562 : rInf.SelectFont();
2553 [ + + ]: 562 : if( pRet->GetAscent() > nAscent )
2554 : : {
2555 : 362 : aBase.Y() = Y() + pRet->GetAscent();
2556 : 362 : nMode |= AS_CHAR_ULSPACE;
2557 [ + - ]: 362 : if( !rInf.IsTest() )
2558 : 362 : aTmpBase = aBase;
2559 [ + - ][ - + ]: 362 : if ( GetInfo().GetTxtFrm()->IsVertical() )
2560 [ # # ]: 0 : GetInfo().GetTxtFrm()->SwitchHorizontalToVertical( aTmpBase );
2561 : :
2562 : 362 : pRet->SetBase( *rInf.GetTxtFrm(), aTmpBase, nTmpAscent,
2563 [ + - ]: 362 : nTmpDescent, nFlyAsc, nFlyDesc, nMode );
2564 : : }
2565 : : }
2566 : : else
2567 : : {
2568 : 728 : pRet = new SwFlyCntPortion( *rInf.GetTxtFrm(), (SwDrawContact*)pFrmFmt->FindContactObj(),
2569 [ + - ][ + - ]: 728 : aTmpBase, nTmpAscent, nTmpDescent, nFlyAsc, nFlyDesc, nMode );
[ + - ]
2570 : : }
2571 : 1290 : return pRet;
2572 : : }
2573 : :
2574 : : namespace {
2575 : : /*************************************************************************
2576 : : * ::CalcOptRepaint()
2577 : : *
2578 : : * calculates and sets optimal repaint offset for the current line
2579 : : *************************************************************************/
2580 : 3304 : long lcl_CalcOptRepaint( SwTxtFormatter &rThis,
2581 : : SwLineLayout &rCurr,
2582 : : const xub_StrLen nOldLineEnd,
2583 : : const std::vector<long> &rFlyStarts )
2584 : : {
2585 [ + - ]: 3304 : SwTxtFormatInfo txtFmtInfo = rThis.GetInfo();
2586 [ + + ]: 3304 : if ( txtFmtInfo.GetIdx() < txtFmtInfo.GetReformatStart() )
2587 : : // the reformat position is behind our new line, that means
2588 : : // something of our text has moved to the next line
2589 : 186 : return 0;
2590 : :
2591 : 3118 : xub_StrLen nReformat = Min( txtFmtInfo.GetReformatStart(), nOldLineEnd );
2592 : :
2593 : : // in case we do not have any fly in our line, our repaint position
2594 : : // is the changed position - 1
2595 [ + - ][ + - ]: 3118 : if ( rFlyStarts.empty() && ! rCurr.IsFly() )
[ + - ]
2596 : : {
2597 : : // this is the maximum repaint offset determined during formatting
2598 : : // for example: the beginning of the first right tab stop
2599 : : // if this value is 0, this means that we do not have an upper
2600 : : // limit for the repaint offset
2601 : 3118 : const long nFormatRepaint = txtFmtInfo.GetPaintOfst();
2602 : :
2603 [ + + ]: 3118 : if ( nReformat < txtFmtInfo.GetLineStart() + 3 )
2604 : 50 : return 0;
2605 : :
2606 : : // step back two positions for smoother repaint
2607 : 3068 : nReformat -= 2;
2608 : :
2609 : : #ifndef QUARTZ
2610 : : #ifndef ENABLE_GRAPHITE
2611 : : // #i28795#, #i34607#, #i38388#
2612 : : // step back six(!) more characters for complex scripts
2613 : : // this is required e.g., for Khmer (thank you, Javier!)
2614 : : const SwScriptInfo& rSI = txtFmtInfo.GetParaPortion()->GetScriptInfo();
2615 : : xub_StrLen nMaxContext = 0;
2616 : : if( ::i18n::ScriptType::COMPLEX == rSI.ScriptType( nReformat ) )
2617 : : nMaxContext = 6;
2618 : : #else
2619 : : // Some Graphite fonts need context for scripts not marked as complex
2620 : : static const xub_StrLen nMaxContext = 10;
2621 : : #endif
2622 : : #else
2623 : : // some fonts like Quartz's Zapfino need more context
2624 : : // TODO: query FontInfo for maximum unicode context
2625 : : static const xub_StrLen nMaxContext = 8;
2626 : : #endif
2627 : : if( nMaxContext > 0 )
2628 : : {
2629 [ + + ]: 3068 : if ( nReformat > txtFmtInfo.GetLineStart() + nMaxContext )
2630 : 2786 : nReformat = nReformat - nMaxContext;
2631 : : else
2632 : 282 : nReformat = txtFmtInfo.GetLineStart();
2633 : : }
2634 : :
2635 : : // Weird situation: Our line used to end with a hole portion
2636 : : // and we delete some characters at the end of our line. We have
2637 : : // to take care for repainting the blanks which are not anymore
2638 : : // covered by the hole portion
2639 [ + + + + ]: 5942 : while ( nReformat > txtFmtInfo.GetLineStart() &&
[ + + ]
2640 : 2830 : CH_BLANK == txtFmtInfo.GetChar( nReformat ) )
2641 : 44 : --nReformat;
2642 : :
2643 : : OSL_ENSURE( nReformat < txtFmtInfo.GetIdx(), "Reformat too small for me!" );
2644 : 3068 : SwRect aRect;
2645 : :
2646 : : // Note: GetChareRect is not const. It definitely changes the
2647 : : // bMulti flag. We have to save and resore the old value.
2648 : 3068 : sal_Bool bOldMulti = txtFmtInfo.IsMulti();
2649 [ + - ]: 3068 : rThis.GetCharRect( &aRect, nReformat );
2650 : 3068 : txtFmtInfo.SetMulti( bOldMulti );
2651 : :
2652 : 52 : return nFormatRepaint ? Min( aRect.Left(), nFormatRepaint ) :
2653 [ + + ]: 3170 : aRect.Left();
2654 : : }
2655 : : else
2656 : : {
2657 : : // nReformat may be wrong, if something around flys has changed:
2658 : : // we compare the former and the new fly positions in this line
2659 : : // if anything has changed, we carefully have to adjust the right
2660 : : // repaint position
2661 : 0 : long nPOfst = 0;
2662 : 0 : sal_uInt16 nCnt = 0;
2663 : 0 : sal_uInt16 nX = 0;
2664 : 0 : sal_uInt16 nIdx = rThis.GetInfo().GetLineStart();
2665 : 0 : SwLinePortion* pPor = rCurr.GetFirstPortion();
2666 : :
2667 [ # # ]: 0 : while ( pPor )
2668 : : {
2669 [ # # ]: 0 : if ( pPor->IsFlyPortion() )
2670 : : {
2671 : : // compare start of fly with former start of fly
2672 [ # # ][ # # ]: 0 : if (nCnt < rFlyStarts.size() &&
[ # # ][ # # ]
2673 [ # # ]: 0 : nX == rFlyStarts[ nCnt ] &&
2674 : : nIdx < nReformat
2675 : : )
2676 : : // found fix position, nothing has changed left from nX
2677 : 0 : nPOfst = nX + pPor->Width();
2678 : : else
2679 : 0 : break;
2680 : :
2681 : 0 : nCnt++;
2682 : : }
2683 : 0 : nX = nX + pPor->Width();
2684 : 0 : nIdx = nIdx + pPor->GetLen();
2685 : 0 : pPor = pPor->GetPortion();
2686 : : }
2687 : :
2688 [ # # ]: 0 : return nPOfst + rThis.GetLeftMargin();
2689 [ + - ]: 3304 : }
2690 : : }
2691 : :
2692 : : // Determine if we need to build hidden portions
2693 : 66815 : bool lcl_BuildHiddenPortion( const SwTxtSizeInfo& rInf, xub_StrLen &rPos )
2694 : : {
2695 : : // Only if hidden text should not be shown:
2696 : : // if ( rInf.GetVsh() && rInf.GetVsh()->GetWin() && rInf.GetOpt().IsShowHiddenChar() )
2697 [ + - ][ + + ]: 66815 : const bool bShowInDocView = rInf.GetVsh() && rInf.GetVsh()->GetWin() && rInf.GetOpt().IsShowHiddenChar();
[ - + ]
2698 [ - + ][ # # ]: 66815 : const bool bShowForPrinting = rInf.GetOpt().IsShowHiddenChar( sal_True ) && rInf.GetOpt().IsPrinting();
2699 [ + - ][ - + ]: 66815 : if (bShowInDocView || bShowForPrinting)
2700 : 0 : return false;
2701 : :
2702 : 66815 : const SwScriptInfo& rSI = rInf.GetParaPortion()->GetScriptInfo();
2703 : : xub_StrLen nHiddenStart;
2704 : : xub_StrLen nHiddenEnd;
2705 [ + - ]: 66815 : rSI.GetBoundsOfHiddenRange( rPos, nHiddenStart, nHiddenEnd );
2706 [ - + ]: 66815 : if ( nHiddenEnd )
2707 : : {
2708 : 0 : rPos = nHiddenEnd;
2709 : 0 : return true;
2710 : : }
2711 : :
2712 : 66815 : return false;
2713 : : }
2714 : :
2715 : : } //end unnamed namespace
2716 : :
2717 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|