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

Generated by: LCOV version 1.10