LCOV - code coverage report
Current view: top level - sw/source/core/text - itrform2.cxx (source / functions) Hit Total Coverage
Test: commit 0e63ca4fde4e446f346e35849c756a30ca294aab Lines: 1005 1346 74.7 %
Date: 2014-04-11 Functions: 38 41 92.7 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10