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

Generated by: LCOV version 1.11