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