LCOV - code coverage report
Current view: top level - sw/source/core/text - itrform2.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 1064 1351 78.8 %
Date: 2014-11-03 Functions: 41 43 95.3 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10