LCOV - code coverage report
Current view: top level - libreoffice/sw/source/core/text - itrform2.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 709 1208 58.7 %
Date: 2012-12-27 Functions: 27 37 73.0 %
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        1542 : inline void ClearFly( SwTxtFormatInfo &rInf )
      80             : {
      81        1542 :     delete rInf.GetFly();
      82        1542 :     rInf.SetFly(0);
      83        1542 : }
      84             : 
      85             : /*************************************************************************
      86             :  *                  SwTxtFormatter::CtorInitTxtFormatter()
      87             :  *************************************************************************/
      88             : 
      89         692 : void SwTxtFormatter::CtorInitTxtFormatter( SwTxtFrm *pNewFrm, SwTxtFormatInfo *pNewInf )
      90             : {
      91         692 :     CtorInitTxtPainter( pNewFrm, pNewInf );
      92         692 :     pInf = pNewInf;
      93         692 :     pDropFmt = GetInfo().GetDropFmt();
      94         692 :     pMulti = NULL;
      95             : 
      96         692 :     bOnceMore = sal_False;
      97         692 :     bFlyInCntBase = sal_False;
      98         692 :     bChanges = sal_False;
      99         692 :     bTruncLines = sal_False;
     100         692 :     nCntEndHyph = 0;
     101         692 :     nCntMidHyph = 0;
     102         692 :     nLeftScanIdx = STRING_LEN;
     103         692 :     nRightScanIdx = 0;
     104         692 :     m_nHintEndIndex = 0;
     105             : 
     106         692 :     if( nStart > GetInfo().GetTxt().Len() )
     107             :     {
     108             :         OSL_ENSURE( !this, "+SwTxtFormatter::CTOR: bad offset" );
     109           0 :         nStart = GetInfo().GetTxt().Len();
     110             :     }
     111             : 
     112         692 : }
     113             : 
     114             : /*************************************************************************
     115             :  *                      SwTxtFormatter::DTOR
     116             :  *************************************************************************/
     117             : 
     118        1384 : SwTxtFormatter::~SwTxtFormatter()
     119             : {
     120             :     // Extremly unlikely, but still possible
     121             :     // e.g.: field splits up, widows start to matter
     122         692 :     if( GetInfo().GetRest() )
     123             :     {
     124           0 :         delete GetInfo().GetRest();
     125           0 :         GetInfo().SetRest(0);
     126             :     }
     127         692 : }
     128             : 
     129             : /*************************************************************************
     130             :  *                      SwTxtFormatter::Insert()
     131             :  *************************************************************************/
     132             : 
     133          81 : void SwTxtFormatter::Insert( SwLineLayout *pLay )
     134             : {
     135             :     // Insert BEHIND the current element
     136          81 :     if ( pCurr )
     137             :     {
     138          81 :         pLay->SetNext( pCurr->GetNext() );
     139          81 :         pCurr->SetNext( pLay );
     140             :     }
     141             :     else
     142           0 :         pCurr = pLay;
     143          81 : }
     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           0 : SwLinePortion *SwTxtFormatter::UnderFlow( SwTxtFormatInfo &rInf )
     171             : {
     172             :     // Save values and initialize rInf
     173           0 :     SwLinePortion *pUnderFlow = rInf.GetUnderFlow();
     174           0 :     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           0 :     const xub_StrLen nSoftHyphPos = rInf.GetSoftHyphPos();
     182           0 :     const xub_StrLen nUnderScorePos = rInf.GetUnderScorePos();
     183             : 
     184             :     // Save flys and set to 0, or else segmentation fault
     185             :     // Not ClearFly(rInf) !
     186           0 :     SwFlyPortion *pFly = rInf.GetFly();
     187           0 :     rInf.SetFly( 0 );
     188             : 
     189           0 :     FeedInf( rInf );
     190           0 :     rInf.SetLast( pCurr );
     191             :     // pUnderFlow does not need to be deleted, because it will drown in the following
     192             :     // Truncate()
     193           0 :     rInf.SetUnderFlow(0);
     194           0 :     rInf.SetSoftHyphPos( nSoftHyphPos );
     195           0 :     rInf.SetUnderScorePos( nUnderScorePos );
     196           0 :     rInf.SetPaintOfst( GetLeftMargin() );
     197             : 
     198             :     // We look for the portion with the under-flow position
     199           0 :     SwLinePortion *pPor = pCurr->GetFirstPortion();
     200           0 :     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           0 :         SwLinePortion *pTmpPrev = pPor;
     207           0 :         while( pPor && pPor != pUnderFlow )
     208             :         {
     209           0 :             if( !pPor->IsKernPortion() &&
     210           0 :                 ( pPor->Width() || pPor->IsSoftHyphPortion() ) )
     211             :             {
     212           0 :                 while( pTmpPrev != pPor )
     213             :                 {
     214           0 :                     pTmpPrev->Move( rInf );
     215           0 :                     rInf.SetLast( pTmpPrev );
     216           0 :                     pTmpPrev = pTmpPrev->GetPortion();
     217             :                     OSL_ENSURE( pTmpPrev, "UnderFlow: Loosing control!" );
     218             :                 };
     219             :             }
     220           0 :             pPor = pPor->GetPortion();
     221             :         }
     222           0 :         pPor = pTmpPrev;
     223           0 :         if( pPor && // Flies + Initialen werden nicht beim UnderFlow mitgenommen
     224           0 :             ( pPor->IsFlyPortion() || pPor->IsDropPortion() ||
     225           0 :               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           0 :     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           0 :     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           0 :     SeekAndChg( rInf );
     275             : 
     276             :     // line width is adjusted, so that pPor does not fit to current
     277             :     // line anymore
     278           0 :     rInf.Width( (sal_uInt16)(rInf.X() + (pPor->Width() ? pPor->Width() - 1 : 0)) );
     279           0 :     rInf.SetLen( pPor->GetLen() );
     280           0 :     rInf.SetFull( sal_False );
     281           0 :     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           0 :     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           0 :     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           0 :     pPor->Truncate();
     309           0 :     SwLinePortion *const pRest( rInf.GetRest() );
     310           0 :     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           0 :     delete pRest;
     317           0 :     rInf.SetRest(0);
     318           0 :     return pPor;
     319             : }
     320             : 
     321             : /*************************************************************************
     322             :  *                      SwTxtFormatter::InsertPortion()
     323             :  *************************************************************************/
     324             : 
     325        1004 : void SwTxtFormatter::InsertPortion( SwTxtFormatInfo &rInf,
     326             :                                     SwLinePortion *pPor ) const
     327             : {
     328             :     // The new portion is inserted, but everything's different for
     329             :     // LineLayout ...
     330        1004 :     if( pPor == pCurr )
     331             :     {
     332         481 :         if ( pCurr->GetPortion() )
     333             :         {
     334           9 :             pPor = pCurr->GetPortion();
     335             :         }
     336             : 
     337             :         // #i112181#
     338         481 :         rInf.SetOtherThanFtnInside( rInf.IsOtherThanFtnInside() || !pPor->IsFtnPortion() );
     339             :     }
     340             :     else
     341             :     {
     342         523 :         SwLinePortion *pLast = rInf.GetLast();
     343         523 :         if( pLast->GetPortion() )
     344             :         {
     345           0 :             while( pLast->GetPortion() )
     346           0 :                 pLast = pLast->GetPortion();
     347           0 :             rInf.SetLast( pLast );
     348             :         }
     349         523 :         pLast->Insert( pPor );
     350             : 
     351         523 :         rInf.SetOtherThanFtnInside( rInf.IsOtherThanFtnInside() || !pPor->IsFtnPortion() );
     352             : 
     353             :         // Adjust maxima
     354         523 :         if( pCurr->Height() < pPor->Height() )
     355         125 :             pCurr->Height( pPor->Height() );
     356         523 :         if( pCurr->GetAscent() < pPor->GetAscent() )
     357         114 :             pCurr->SetAscent( pPor->GetAscent() );
     358             :     }
     359             : 
     360             :     // Sometimes chains are constructed (e.g. by hyphenate)
     361        1004 :     rInf.SetLast( pPor );
     362        3021 :     while( pPor )
     363             :     {
     364        1013 :         pPor->Move( rInf );
     365        1013 :         rInf.SetLast( pPor );
     366        1013 :         pPor = pPor->GetPortion();
     367             :     }
     368        1004 : }
     369             : 
     370             : /*************************************************************************
     371             :  *                      SwTxtFormatter::BuildPortion()
     372             :  *************************************************************************/
     373             : 
     374         755 : void SwTxtFormatter::BuildPortions( SwTxtFormatInfo &rInf )
     375             : {
     376             :     OSL_ENSURE( rInf.GetTxt().Len() < STRING_LEN,
     377             :             "SwTxtFormatter::BuildPortions: bad text length in info" );
     378             : 
     379         755 :     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         755 :     rInf.SetLast( pCurr );
     385         755 :     rInf.ForcedLeftMargin( 0 );
     386             : 
     387             :     OSL_ENSURE( pCurr->FindLastPortion() == pCurr, "pLast supposed to equal pCurr" );
     388             : 
     389         755 :     if( !pCurr->GetAscent() && !pCurr->Height() )
     390         755 :         CalcAscent( rInf, pCurr );
     391             : 
     392         755 :     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         755 :     CalcFlyWidth( rInf );
     397         755 :     SwFlyPortion *pFly = rInf.GetFly();
     398         755 :     if( pFly )
     399             :     {
     400          40 :         if ( 0 < pFly->Fix() )
     401          32 :             ClearFly( rInf );
     402             :         else
     403           8 :             rInf.SetFull(sal_True);
     404             :     }
     405             : 
     406         755 :     SwLinePortion *pPor = NewPortion( rInf );
     407             : 
     408             :     // Asian grid stuff
     409         755 :     GETGRID( pFrm->FindPageFrm() )
     410           0 :     const sal_Bool bHasGrid = pGrid && rInf.SnapToGrid() &&
     411         755 :                               GRID_LINES_CHARS == pGrid->GetGridType();
     412             : 
     413         755 :     const SwDoc *pDoc = rInf.GetTxtFrm()->GetNode()->GetDoc();
     414             :     const sal_uInt16 nGridWidth = bHasGrid ?
     415         755 :                                 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         755 :     SwKernPortion* pGridKernPortion = 0;
     421             : 
     422             :     sal_Bool bFull;
     423         755 :     SwTwips nUnderLineStart = 0;
     424         755 :     rInf.Y( Y() );
     425             : 
     426        2514 :     while( pPor && !rInf.IsStop() )
     427             :     {
     428             :         OSL_ENSURE( rInf.GetLen() < STRING_LEN &&
     429             :                 rInf.GetIdx() <= rInf.GetTxt().Len(),
     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        1004 :         if( pPor->InFldGrp() )
     435         133 :             ((SwFldPortion*)pPor)->CheckScript( rInf );
     436             : 
     437        4026 :         if( ! bHasGrid && rInf.HasScriptSpace() &&
     438        1996 :             rInf.GetLast() && rInf.GetLast()->InTxtGrp() &&
     439        1026 :             rInf.GetLast()->Width() && !rInf.GetLast()->InNumberGrp() )
     440             :         {
     441          72 :             sal_uInt8 nNxtActual = rInf.GetFont()->GetActual();
     442          72 :             sal_uInt8 nLstActual = nNxtActual;
     443          72 :             sal_uInt16 nLstHeight = (sal_uInt16)rInf.GetFont()->GetHeight();
     444          72 :             sal_Bool bAllowBefore = sal_False;
     445          72 :             sal_Bool bAllowBehind = sal_False;
     446          72 :             const CharClass& rCC = GetAppCharClass();
     447             : 
     448             :             // are there any punctuation characters on both sides
     449             :             // of the kerning portion?
     450          72 :             if ( pPor->InFldGrp() )
     451             :             {
     452          11 :                 XubString aAltTxt;
     453          22 :                 if ( ((SwFldPortion*)pPor)->GetExpTxt( rInf, aAltTxt ) &&
     454          11 :                         aAltTxt.Len() )
     455             :                 {
     456          10 :                     bAllowBehind = rCC.isLetterNumeric( aAltTxt, 0 );
     457             : 
     458          10 :                     const SwFont* pTmpFnt = ((SwFldPortion*)pPor)->GetFont();
     459          10 :                     if ( pTmpFnt )
     460           0 :                         nNxtActual = pTmpFnt->GetActual();
     461          11 :                 }
     462             :             }
     463             :             else
     464          61 :                 bAllowBehind = rCC.isLetterNumeric( rInf.GetTxt(), rInf.GetIdx() );
     465             : 
     466          72 :             const SwLinePortion* pLast = rInf.GetLast();
     467          72 :             if ( bAllowBehind && pLast )
     468             :             {
     469          28 :                 if ( pLast->InFldGrp() )
     470             :                 {
     471           2 :                     XubString aAltTxt;
     472           4 :                     if ( ((SwFldPortion*)pLast)->GetExpTxt( rInf, aAltTxt ) &&
     473           2 :                          aAltTxt.Len() )
     474             :                     {
     475           2 :                         bAllowBefore = rCC.isLetterNumeric( aAltTxt, aAltTxt.Len() - 1 );
     476             : 
     477           2 :                         const SwFont* pTmpFnt = ((SwFldPortion*)pLast)->GetFont();
     478           2 :                         if ( pTmpFnt )
     479             :                         {
     480           0 :                             nLstActual = pTmpFnt->GetActual();
     481           0 :                             nLstHeight = (sal_uInt16)pTmpFnt->GetHeight();
     482             :                         }
     483           2 :                     }
     484             :                 }
     485          26 :                 else if ( rInf.GetIdx() )
     486             :                 {
     487          26 :                     bAllowBefore = rCC.isLetterNumeric( rInf.GetTxt(), rInf.GetIdx() - 1 );
     488             :                     // Note: ScriptType returns values in [1,4]
     489          26 :                     if ( bAllowBefore )
     490           6 :                         nLstActual = pScriptInfo->ScriptType( rInf.GetIdx() - 1 ) - 1;
     491             :                 }
     492             : 
     493          28 :                 nLstHeight /= 5;
     494             :                 // does the kerning portion still fit into the line?
     495          28 :                 if( bAllowBefore && ( nLstActual != nNxtActual ) &&
     496           0 :                     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         932 :         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             :                                 ( ( 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        1004 :         if( pPor->IsMultiPortion() && ( !pMulti || pMulti->IsBidi() ) )
     551           1 :             bFull = BuildMultiPortion( rInf, *((SwMultiPortion*)pPor) );
     552             :         else
     553        1003 :             bFull = pPor->Format( rInf );
     554             : 
     555        1004 :         if( rInf.IsRuby() && !rInf.GetRest() )
     556           0 :             bFull = sal_True;
     557             : 
     558             :         // if we are underlined, we store the beginning of this underlined
     559             :         // segment for repaint optimization
     560        1004 :         if ( UNDERLINE_NONE != pFnt->GetUnderline() && ! nUnderLineStart )
     561           9 :             nUnderLineStart = GetLeftMargin() + rInf.X();
     562             : 
     563        1004 :         if ( pPor->IsFlyPortion() )
     564           8 :             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        1047 :         else if ( ( ! rInf.GetPaintOfst() || nUnderLineStart < rInf.GetPaintOfst() ) &&
     574             :                   // 1. Underlined portions
     575             :                   nUnderLineStart &&
     576             :                      // reformat is at end of an underlined portion and next portion
     577             :                      // is not underlined
     578          13 :                   ( ( rInf.GetReformatStart() == rInf.GetIdx() &&
     579           5 :                       UNDERLINE_NONE == pFnt->GetUnderline()
     580             :                     ) ||
     581             :                      // reformat is inside portion and portion is underlined
     582          13 :                     ( rInf.GetReformatStart() >= rInf.GetIdx() &&
     583          15 :                       rInf.GetReformatStart() <= rInf.GetIdx() + pPor->GetLen() &&
     584           5 :                       UNDERLINE_NONE != pFnt->GetUnderline() ) ) )
     585           5 :             rInf.SetPaintOfst( nUnderLineStart );
     586        4981 :         else if (  ! rInf.GetPaintOfst() &&
     587             :                    // 2. Right Tab
     588        1048 :                    ( ( pPor->InTabGrp() && !pPor->IsTabLeftPortion() ) ||
     589             :                    // 3. BidiPortions
     590         982 :                      ( pPor->IsMultiPortion() && ((SwMultiPortion*)pPor)->IsBidi() ) ||
     591             :                    // 4. Multi Portion and 5. Drop Caps
     592        1960 :                      ( ( pPor->IsDropPortion() || pPor->IsMultiPortion() ) &&
     593           0 :                        rInf.GetReformatStart() >= rInf.GetIdx() &&
     594           0 :                        rInf.GetReformatStart() <= rInf.GetIdx() + pPor->GetLen() )
     595             :                    // 6. Grid Mode
     596           0 :                      || ( bHasGrid && SW_CJK != pFnt->GetActual() )
     597             :                    )
     598             :                 )
     599             :             // we store the beginning of the critical portion as our
     600             :             // paint offset
     601           1 :             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        1004 :         if ( IsUnderlineBreak( *pPor, *pFnt ) )
     606         989 :             nUnderLineStart = 0;
     607             : 
     608        1005 :         if( pPor->IsFlyCntPortion() || ( pPor->IsMultiPortion() &&
     609           1 :             ((SwMultiPortion*)pPor)->HasFlyInCntnt() ) )
     610         165 :             SetFlyInCntBase();
     611             :         // bUnderFlow needs to be reset or we wrap again at the next softhyphen
     612        1004 :         if ( !bFull )
     613             :         {
     614         915 :             rInf.ClrUnderFlow();
     615        2140 :             if( ! bHasGrid && rInf.HasScriptSpace() && pPor->InTxtGrp() &&
     616        1225 :                 pPor->GetLen() && !pPor->InFldGrp() )
     617             :             {
     618             :                 // The distance between two different scripts is set
     619             :                 // to 20% of the fontheight.
     620         540 :                 xub_StrLen nTmp = rInf.GetIdx() + pPor->GetLen();
     621         992 :                 if( nTmp == pScriptInfo->NextScriptChg( nTmp - 1 ) &&
     622         452 :                     nTmp != rInf.GetTxt().Len() )
     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        1004 :         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().Len() ?
     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             :                                  ( nSumWidth - 1 ) / nGridWidth + 1 :
     675           0 :                                  0;
     676           0 :                 const SwTwips nTmpWidth = i * nGridWidth;
     677             :                 const SwTwips nKernWidth = 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        1004 :         rInf.SetFull( bFull );
     701             : 
     702             :         // Restportions from fields with multiple lines don't yet have the right ascent
     703        1423 :         if ( !pPor->GetLen() && !pPor->IsFlyPortion()
     704         360 :             && !pPor->IsGrfNumPortion() && ! pPor->InNumberGrp()
     705          59 :             && !pPor->IsMultiPortion() )
     706          59 :             CalcAscent( rInf, pPor );
     707             : 
     708        1004 :         InsertPortion( rInf, pPor );
     709        1004 :         pPor = NewPortion( rInf );
     710             :     }
     711             : 
     712         755 :     if( !rInf.IsStop() )
     713             :     {
     714             :         // The last right centered, decimal tab
     715         755 :         SwTabPortion *pLastTab = rInf.GetLastTab();
     716         755 :         if( pLastTab )
     717           0 :             pLastTab->FormatEOL( rInf );
     718         755 :         else if( rInf.GetLast() && rInf.LastKernPortion() )
     719           1 :             rInf.GetLast()->FormatEOL( rInf );
     720             :     }
     721         818 :     if( pCurr->GetPortion() && pCurr->GetPortion()->InNumberGrp()
     722          63 :         && ((SwNumberPortion*)pCurr->GetPortion())->IsHide() )
     723           0 :         rInf.SetNumDone( sal_False );
     724             : 
     725             :     // Delete fly in any case
     726         755 :     ClearFly( rInf );
     727             : 
     728             :     // Reinit the tab overflow flag after the line
     729         755 :     rInf.SetTabOverflow( sal_False );
     730         755 : }
     731             : 
     732             : /*************************************************************************
     733             :  *                 SwTxtFormatter::CalcAdjustLine()
     734             :  *************************************************************************/
     735             : 
     736         724 : void SwTxtFormatter::CalcAdjustLine( SwLineLayout *pCurrent )
     737             : {
     738         724 :     if( SVX_ADJUST_LEFT != GetAdjust() && !pMulti)
     739             :     {
     740          44 :         pCurrent->SetFormatAdj(sal_True);
     741          44 :         if( IsFlyInCntBase() )
     742             :         {
     743           1 :             CalcAdjLine( pCurrent );
     744             :             // For e.g. centered fly we need to switch the RefPoint
     745             :             // That's why bAllWays = sal_True
     746           1 :             UpdatePos( pCurrent, GetTopLeft(), GetStart(), sal_True );
     747             :         }
     748             :     }
     749         724 : }
     750             : 
     751             : /*************************************************************************
     752             :  *                      SwTxtFormatter::CalcAscent()
     753             :  *************************************************************************/
     754             : 
     755        1643 : void SwTxtFormatter::CalcAscent( SwTxtFormatInfo &rInf, SwLinePortion *pPor )
     756             : {
     757        1643 :     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         121 :         SwFont* pFldFnt = ((SwFldPortion*)pPor)->pFnt;
     762         121 :         SwFontSave aSave( rInf, pFldFnt );
     763         121 :         ((SwFldPortion*)pPor)->Height( pFldFnt->GetHeight( rInf.GetVsh(), *rInf.GetOut() ) );
     764         121 :         ((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        1870 :     else if ( pPor->InTabGrp() && pPor->GetLen() == 0 &&
     770         232 :               rInf.GetLast() && rInf.GetLast()->InNumberGrp() &&
     771         116 :               static_cast<const SwNumberPortion*>(rInf.GetLast())->HasFont() )
     772             :     {
     773         116 :         const SwLinePortion* pLast = rInf.GetLast();
     774         116 :         pPor->Height( pLast->Height() );
     775         116 :         pPor->SetAscent( pLast->GetAscent() );
     776             :     }
     777             :     else
     778             :     {
     779        1406 :         const SwLinePortion *pLast = rInf.GetLast();
     780             :         sal_Bool bChg;
     781             : 
     782             :         // In empty lines the attributes are switched on via SeekStart
     783        1406 :         const sal_Bool bFirstPor = rInf.GetLineStart() == rInf.GetIdx();
     784        1406 :         if ( pPor->IsQuoVadisPortion() )
     785           0 :             bChg = SeekStartAndChg( rInf, sal_True );
     786             :         else
     787             :         {
     788        1406 :             if( bFirstPor )
     789             :             {
     790        1302 :                 if( rInf.GetTxt().Len() )
     791             :                 {
     792        1303 :                     if ( pPor->GetLen() || !rInf.GetIdx()
     793           0 :                          || ( pCurr != pLast && !pLast->IsFlyPortion() )
     794          79 :                          || !pCurr->IsRest() ) // instead of !rInf.GetRest()
     795        1224 :                         bChg = SeekAndChg( rInf );
     796             :                     else
     797           0 :                         bChg = SeekAndChgBefore( rInf );
     798             :                 }
     799          78 :                 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          78 :                     bChg = SeekStartAndChg( rInf );
     808             :             }
     809             :             else
     810         104 :                 bChg = SeekAndChg( rInf );
     811             :         }
     812        1406 :         if( bChg || bFirstPor || !pPor->GetAscent()
     813           0 :             || !rInf.GetLast()->InTxtGrp() )
     814             :         {
     815        1406 :             pPor->SetAscent( rInf.GetAscent()  );
     816        1406 :             pPor->Height( rInf.GetTxtHeight() );
     817             :         }
     818             :         else
     819             :         {
     820           0 :             pPor->Height( pLast->Height() );
     821           0 :             pPor->SetAscent( pLast->GetAscent() );
     822             :         }
     823             :     }
     824        1643 : }
     825             : 
     826             : /*************************************************************************
     827             :  *                      class SwMetaPortion
     828             :  *************************************************************************/
     829             : 
     830           0 : class SwMetaPortion : public SwTxtPortion
     831             : {
     832             : public:
     833           0 :     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           0 : void SwMetaPortion::Paint( const SwTxtPaintInfo &rInf ) const
     845             : {
     846           0 :     if ( Width() )
     847             :     {
     848           0 :         rInf.DrawViewOpt( *this, POR_META );
     849           0 :         SwTxtPortion::Paint( rInf );
     850             :     }
     851           0 : }
     852             : 
     853             : 
     854             : /*************************************************************************
     855             :  *                      SwTxtFormatter::WhichTxtPor()
     856             :  *************************************************************************/
     857             : 
     858         611 : SwTxtPortion *SwTxtFormatter::WhichTxtPor( SwTxtFormatInfo &rInf ) const
     859             : {
     860         611 :     SwTxtPortion *pPor = 0;
     861         611 :     if( GetFnt()->IsTox() )
     862           0 :         pPor = new SwToxPortion;
     863             :     else
     864             :     {
     865         611 :         if( GetFnt()->IsRef() )
     866           0 :             pPor = new SwRefPortion;
     867         611 :         else if (GetFnt()->IsMeta())
     868             :         {
     869           0 :             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         611 :             if( rInf.GetLen() > 0 )
     877             :             {
     878         548 :                 if( rInf.GetTxt().GetChar(rInf.GetIdx())==CH_TXT_ATR_FIELDSTART )
     879           6 :                     pPor = new SwFieldMarkPortion();
     880         542 :                 else if( rInf.GetTxt().GetChar(rInf.GetIdx())==CH_TXT_ATR_FIELDEND )
     881           6 :                     pPor = new SwFieldMarkPortion();
     882         536 :                 else if( rInf.GetTxt().GetChar(rInf.GetIdx())==CH_TXT_ATR_FORMELEMENT )
     883           1 :                     pPor = new SwFieldFormPortion();
     884             :             }
     885         611 :             if( !pPor )
     886             :             {
     887         598 :                 if( !rInf.X() && !pCurr->GetPortion() && !pCurr->GetLen() && !GetFnt()->IsURL() )
     888         481 :                     pPor = pCurr;
     889             :                 else
     890             :                 {
     891         117 :                     pPor = new SwTxtPortion;
     892         117 :                     if( GetFnt()->IsURL() )
     893           0 :                         pPor->SetWhichPor( POR_URL );
     894             :                 }
     895             :             }
     896             :         }
     897             :     }
     898         611 :     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         611 : 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         611 :     Seek( rInf.GetIdx() );
     915         611 :     SwTxtPortion *pPor = WhichTxtPor( rInf );
     916             : 
     917             :     // until next attribute change:
     918         611 :     const xub_StrLen nNextAttr = GetNextAttr();
     919         611 :     xub_StrLen nNextChg = Min( nNextAttr, rInf.GetTxt().Len() );
     920             : 
     921             :     // end of script type:
     922         611 :     const xub_StrLen nNextScript = pScriptInfo->NextScriptChg( rInf.GetIdx() );
     923         611 :     nNextChg = Min( nNextChg, nNextScript );
     924             : 
     925             :     // end of direction:
     926         611 :     const xub_StrLen nNextDir = pScriptInfo->NextDirChg( rInf.GetIdx() );
     927         611 :     nNextChg = 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         611 :     pPor->SetLen(1);
     943         611 :     CalcAscent( rInf, pPor );
     944             : 
     945         611 :     const SwFont* pTmpFnt = rInf.GetFont();
     946         611 :     KSHORT nExpect = Min( KSHORT( ((Font *)pTmpFnt)->GetSize().Height() ),
     947        1222 :                           KSHORT( pPor->GetAscent() ) ) / 8;
     948         611 :     if ( !nExpect )
     949           0 :         nExpect = 1;
     950         611 :     nExpect = (sal_uInt16)(rInf.GetIdx() + ((rInf.Width() - rInf.X()) / nExpect));
     951         611 :     if( nExpect > rInf.GetIdx() && nNextChg > nExpect )
     952          15 :         nNextChg = Min( nExpect, rInf.GetTxt().Len() );
     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         611 :     if ( nLeftScanIdx <= rInf.GetIdx() && rInf.GetIdx() <= nRightScanIdx )
     958             :     {
     959         123 :         if ( nNextChg > nRightScanIdx )
     960             :             nNextChg = nRightScanIdx =
     961          61 :                 rInf.ScanPortionEnd( nRightScanIdx, nNextChg );
     962             :     }
     963             :     else
     964             :     {
     965         488 :         nLeftScanIdx = rInf.GetIdx();
     966             :         nNextChg = nRightScanIdx =
     967         488 :                 rInf.ScanPortionEnd( rInf.GetIdx(), nNextChg );
     968             :     }
     969             : 
     970         611 :     pPor->SetLen( nNextChg - rInf.GetIdx() );
     971         611 :     rInf.SetLen( pPor->GetLen() );
     972         611 :     return pPor;
     973             : }
     974             : 
     975             : 
     976             : /*************************************************************************
     977             :  *                 SwTxtFormatter::WhichFirstPortion()
     978             :  *************************************************************************/
     979             : 
     980        1748 : SwLinePortion *SwTxtFormatter::WhichFirstPortion(SwTxtFormatInfo &rInf)
     981             : {
     982        1748 :     SwLinePortion *pPor = 0;
     983             : 
     984        1748 :     if( rInf.GetRest() )
     985             :     {
     986             :         // Tabs and fields
     987         116 :         if( '\0' != rInf.GetHookChar() )
     988          58 :             return 0;
     989             : 
     990          58 :         pPor = rInf.GetRest();
     991          58 :         if( pPor->IsErgoSumPortion() )
     992           0 :             rInf.SetErgoDone(sal_True);
     993             :         else
     994          58 :             if( pPor->IsFtnNumPortion() )
     995           0 :                 rInf.SetFtnDone(sal_True);
     996             :             else
     997          58 :                 if( pPor->InNumberGrp() )
     998          58 :                     rInf.SetNumDone(sal_True);
     999             : 
    1000          58 :         rInf.SetRest(0);
    1001          58 :         pCurr->SetRest( sal_True );
    1002          58 :         return pPor;
    1003             :     }
    1004             : 
    1005             :     // We can stand in the follow, it's crucial that
    1006             :     // pFrm->GetOfst() == 0!
    1007        1632 :     if( rInf.GetIdx() )
    1008             :     {
    1009             :         // We now too can elongate FtnPortions and ErgoSumPortions
    1010             : 
    1011             :         // 1. The ErgoSumTexts
    1012         895 :         if( !rInf.IsErgoDone() )
    1013             :         {
    1014           1 :             if( pFrm->IsInFtn() && !pFrm->GetIndPrev() )
    1015           0 :                 pPor = (SwLinePortion*)NewErgoSumPortion( rInf );
    1016           1 :             rInf.SetErgoDone( sal_True );
    1017             :         }
    1018             : 
    1019             :         // 2. Arrow portions
    1020         895 :         if( !pPor && !rInf.IsArrowDone() )
    1021             :         {
    1022         598 :             if( pFrm->GetOfst() && !pFrm->IsFollow() &&
    1023           0 :                 rInf.GetIdx() == pFrm->GetOfst() )
    1024           0 :                 pPor = new SwArrowPortion( *pCurr );
    1025         598 :             rInf.SetArrowDone( sal_True );
    1026             :         }
    1027             : 
    1028             :         // 3. Kerning portions at beginning of line in grid mode
    1029         895 :         if ( ! pPor && ! pCurr->GetPortion() )
    1030             :         {
    1031         551 :             GETGRID( GetTxtFrm()->FindPageFrm() )
    1032         551 :             if ( pGrid )
    1033           0 :                 pPor = new SwKernPortion( *pCurr );
    1034             :         }
    1035             : 
    1036             :         // 4. The line rests (multiline fields)
    1037         895 :         if( !pPor )
    1038             :         {
    1039         895 :             pPor = rInf.GetRest();
    1040             :             // Only for pPor of course
    1041         895 :             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         737 :         if( !rInf.IsFtnDone() )
    1052             :         {
    1053             :             OSL_ENSURE( ( ! rInf.IsMulti() && ! pMulti ) || pMulti->HasRotation(),
    1054             :                      "Rotated number portion trouble" );
    1055             : 
    1056         673 :             sal_Bool bFtnNum = pFrm->IsFtnNumFrm();
    1057         673 :             rInf.GetParaPortion()->SetFtnNum( bFtnNum );
    1058         673 :             if( bFtnNum )
    1059           5 :                 pPor = (SwLinePortion*)NewFtnNumPortion( rInf );
    1060         673 :             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         737 :         if( !rInf.IsErgoDone() && !pPor && ! rInf.IsMulti() )
    1066             :         {
    1067         673 :             if( pFrm->IsInFtn() && !pFrm->GetIndPrev() )
    1068           5 :                 pPor = (SwLinePortion*)NewErgoSumPortion( rInf );
    1069         673 :             rInf.SetErgoDone( sal_True );
    1070             :         }
    1071             : 
    1072             :         // 7. The numbering
    1073         737 :         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         668 :             if( GetTxtFrm()->GetTxtNode()->GetNumRule() )
    1080          60 :                 pPor = (SwLinePortion*)NewNumberPortion( rInf );
    1081         668 :             rInf.SetNumDone( sal_True );
    1082             :         }
    1083             :         // 8. The DropCaps
    1084         737 :         if( !pPor && GetDropFmt() && ! rInf.IsMulti() )
    1085           0 :             pPor = (SwLinePortion*)NewDropPortion( rInf );
    1086             : 
    1087             :         // 9. Kerning portions at beginning of line in grid mode
    1088         737 :         if ( !pPor && !pCurr->GetPortion() )
    1089             :         {
    1090         605 :             GETGRID( GetTxtFrm()->FindPageFrm() )
    1091         605 :             if ( pGrid )
    1092           0 :                 pPor = new SwKernPortion( *pCurr );
    1093             :         }
    1094             :     }
    1095             : 
    1096             :         // 10. Decimal tab portion at the beginning of each line in table cells
    1097        3133 :         if ( !pPor && !pCurr->GetPortion() &&
    1098        1156 :              GetTxtFrm()->IsInTab() &&
    1099         345 :              GetTxtFrm()->GetTxtNode()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::TAB_COMPAT) )
    1100             :         {
    1101         345 :             pPor = NewTabPortion( rInf, true );
    1102             :         }
    1103             : 
    1104             :         // 11. suffix of meta-field
    1105        1632 :         if (!pPor)
    1106             :         {
    1107        1569 :             pPor = TryNewNoLengthPortion(rInf);
    1108             :         }
    1109             : 
    1110        1632 :     return pPor;
    1111             : }
    1112             : 
    1113          86 : static sal_Bool lcl_OldFieldRest( const SwLineLayout* pCurr )
    1114             : {
    1115          86 :     if( !pCurr->GetNext() )
    1116          86 :         return sal_False;
    1117           0 :     const SwLinePortion *pPor = pCurr->GetNext()->GetPortion();
    1118           0 :     sal_Bool bRet = sal_False;
    1119           0 :     while( pPor && !bRet )
    1120             :     {
    1121           0 :         bRet = (pPor->InFldGrp() && ((SwFldPortion*)pPor)->IsFollow()) ||
    1122           0 :             (pPor->IsMultiPortion() && ((SwMultiPortion*)pPor)->IsFollowFld());
    1123           0 :         if( !pPor->GetLen() )
    1124           0 :             break;
    1125           0 :         pPor = pPor->GetPortion();
    1126             :     }
    1127           0 :     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        1759 : SwLinePortion *SwTxtFormatter::NewPortion( SwTxtFormatInfo &rInf )
    1146             : {
    1147             :     // Underflow takes precedence
    1148        1759 :     rInf.SetStopUnderFlow( false );
    1149        1759 :     if( rInf.GetUnderFlow() )
    1150             :     {
    1151             :         OSL_ENSURE( rInf.IsFull(), "SwTxtFormatter::NewPortion: underflow but not full" );
    1152           0 :         return UnderFlow( rInf );
    1153             :     }
    1154             : 
    1155             :     // If the line is full, flys and UnderFlow portions could be waiting ...
    1156        1759 :     if( rInf.IsFull() )
    1157             :     {
    1158             :         // LineBreaks and Flys (bug05.sdw)
    1159             :         // IsDummy()
    1160          97 :         if( rInf.IsNewLine() && (!rInf.GetFly() || !pCurr->IsDummy()) )
    1161           3 :             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          94 :         if( rInf.GetFly() )
    1169             :         {
    1170           8 :             if( rInf.GetLast()->IsBreakPortion() )
    1171             :             {
    1172           0 :                 delete rInf.GetFly();
    1173           0 :                 rInf.SetFly( 0 );
    1174             :             }
    1175             : 
    1176           8 :             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          86 :         if( rInf.GetRest() )
    1183           0 :             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          86 :             if( lcl_OldFieldRest( GetCurr() ) )
    1190           0 :                 rInf.SetNewLine( sal_True );
    1191             :             else
    1192             :             {
    1193          86 :                 SwLinePortion *pFirst = WhichFirstPortion( rInf );
    1194          86 :                 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          86 :         return 0;
    1205             :     }
    1206             : 
    1207        1662 :     SwLinePortion *pPor = WhichFirstPortion( rInf );
    1208             : 
    1209             :     // Check for Hidden Portion:
    1210        1662 :     if ( !pPor )
    1211             :     {
    1212        1541 :         xub_StrLen nEnd = rInf.GetIdx();
    1213        1541 :         if ( ::lcl_BuildHiddenPortion( rInf, nEnd ) )
    1214           0 :             pPor = new SwHiddenTextPortion( nEnd - rInf.GetIdx() );
    1215             :     }
    1216             : 
    1217        1662 :     if( !pPor )
    1218             :     {
    1219        3140 :         if( ( !pMulti || pMulti->IsBidi() ) &&
    1220             :             // #i42734#
    1221             :             // No multi portion if there is a hook character waiting:
    1222        1599 :             ( !rInf.GetRest() || '\0' == rInf.GetHookChar() ) )
    1223             :         {
    1224             :             // We open a multiportion part, if we enter a multi-line part
    1225             :             // of the paragraph.
    1226        1483 :             xub_StrLen nEnd = rInf.GetIdx();
    1227        1483 :             SwMultiCreator* pCreate = rInf.GetMultiCreator( nEnd, pMulti );
    1228        1483 :             if( pCreate )
    1229             :             {
    1230           1 :                 SwMultiPortion* pTmp = NULL;
    1231             : 
    1232           1 :                 if ( SW_MC_BIDI == pCreate->nId )
    1233           1 :                     pTmp = new SwBidiPortion( nEnd, pCreate->nLevel );
    1234           0 :                 else if ( SW_MC_RUBY == pCreate->nId )
    1235             :                 {
    1236           0 :                     Seek( rInf.GetIdx() );
    1237             :                     sal_Bool bRubyTop;
    1238           0 :                     sal_Bool* pRubyPos = 0;
    1239             : 
    1240           0 :                     if ( rInf.SnapToGrid() )
    1241             :                     {
    1242           0 :                         GETGRID( GetTxtFrm()->FindPageFrm() )
    1243           0 :                         if ( pGrid )
    1244             :                         {
    1245           0 :                             bRubyTop = ! pGrid->GetRubyTextBelow();
    1246           0 :                             pRubyPos = &bRubyTop;
    1247             :                         }
    1248             :                     }
    1249             : 
    1250           0 :                     pTmp = new SwRubyPortion( *pCreate, *rInf.GetFont(),
    1251           0 :                                               *GetTxtFrm()->GetTxtNode()->getIDocumentSettingAccess(),
    1252           0 :                                               nEnd, 0, pRubyPos );
    1253             :                 }
    1254           0 :                 else if( SW_MC_ROTATE == pCreate->nId )
    1255             :                     pTmp = new SwRotatedPortion( *pCreate, nEnd,
    1256           0 :                                                  GetTxtFrm()->IsRightToLeft() );
    1257             :                 else
    1258           0 :                     pTmp = new SwDoubleLinePortion( *pCreate, nEnd );
    1259             : 
    1260           1 :                 delete pCreate;
    1261           1 :                 CalcFlyWidth( rInf );
    1262             : 
    1263           1 :                 return pTmp;
    1264             :             }
    1265             :         }
    1266             :         // 5010: Tabs und Felder
    1267        1540 :         sal_Unicode cChar = rInf.GetHookChar();
    1268             : 
    1269        1540 :         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          67 :             if( !rInf.GetRest() || !rInf.GetRest()->InFldGrp() )
    1279           9 :                 cChar = rInf.GetChar( rInf.GetIdx() );
    1280          67 :             rInf.ClearHookChar();
    1281             :         }
    1282             :         else
    1283             :         {
    1284        1473 :             if( rInf.GetIdx() >= rInf.GetTxt().Len() )
    1285             :             {
    1286         666 :                 rInf.SetFull(sal_True);
    1287         666 :                 CalcFlyWidth( rInf );
    1288         666 :                 return pPor;
    1289             :             }
    1290         807 :             cChar = rInf.GetChar( rInf.GetIdx() );
    1291             :         }
    1292             : 
    1293         874 :         switch( cChar )
    1294             :         {
    1295             :             case CH_TAB:
    1296          69 :                 pPor = NewTabPortion( rInf, false ); break;
    1297             : 
    1298             :             case CH_BREAK:
    1299           1 :                 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           6 :                 pPor = new SwBlankPortion( ' ' ); break;
    1306             : 
    1307             :             case CHAR_HARDHYPHEN:               // non-breaking hyphen
    1308           2 :                 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         183 :                             if( rInf.HasHint( rInf.GetIdx() ) )
    1319             :                             {
    1320         183 :                                 pPor = NewExtraPortion( rInf );
    1321         183 :                                 break;
    1322             :                             }
    1323             :                             // No break
    1324             :             default        :
    1325             :             {
    1326         611 :                 SwTabPortion* pLastTabPortion = rInf.GetLastTab();
    1327         611 :                 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         611 :                 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         611 :                     if( rInf.IsFull() )
    1358           0 :                         return 0;
    1359         611 :                     pPor = NewTxtPortion( rInf );
    1360             :                 }
    1361         611 :                 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         874 :         if( pPor && rInf.GetRest() )
    1368          58 :             pPor->SetLen( 0 );
    1369             : 
    1370             :         // robust:
    1371         874 :         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         995 :     if ( pPor && ! pMulti )
    1382             :     {
    1383         994 :         if ( pPor->IsFtnPortion() )
    1384             :         {
    1385           5 :             const SwTxtFtn* pTxtFtn = ((SwFtnPortion*)pPor)->GetTxtFtn();
    1386             : 
    1387           5 :             if ( pTxtFtn )
    1388             :             {
    1389           5 :                 SwFmtFtn& rFtn = (SwFmtFtn&)pTxtFtn->GetFtn();
    1390           5 :                 const SwDoc *pDoc = rInf.GetTxtFrm()->GetNode()->GetDoc();
    1391             :                 const SwEndNoteInfo* pInfo;
    1392           5 :                 if( rFtn.IsEndNote() )
    1393           0 :                     pInfo = &pDoc->GetEndNoteInfo();
    1394             :                 else
    1395           5 :                     pInfo = &pDoc->GetFtnInfo();
    1396           5 :                 const SwAttrSet& rSet = pInfo->GetAnchorCharFmt((SwDoc&)*pDoc)->GetAttrSet();
    1397             : 
    1398             :                 const SfxPoolItem* pItem;
    1399           5 :                 sal_uInt16 nDir = 0;
    1400           5 :                 if( SFX_ITEM_SET == rSet.GetItemState( RES_CHRATR_ROTATE,
    1401           5 :                     sal_True, &pItem ))
    1402           0 :                     nDir = ((SvxCharRotateItem*)pItem)->GetValue();
    1403             : 
    1404           5 :                 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         989 :         else if ( pPor->InNumberGrp() )
    1414             :         {
    1415         121 :             const SwFont* pNumFnt = ((SwFldPortion*)pPor)->GetFont();
    1416             : 
    1417         121 :             if ( pNumFnt )
    1418             :             {
    1419         121 :                 sal_uInt16 nDir = pNumFnt->GetOrientation( rInf.GetTxtFrm()->IsVertical() );
    1420         121 :                 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         995 :     if( !pPor->GetAscent() && !pPor->Height() )
    1437         218 :         CalcAscent( rInf, pPor );
    1438         995 :     rInf.SetLen( pPor->GetLen() );
    1439             : 
    1440             :     // In CalcFlyWidth wird Width() verkuerzt, wenn eine FlyPortion vorliegt.
    1441         995 :     CalcFlyWidth( rInf );
    1442             : 
    1443             :     // Man darf nicht vergessen, dass pCurr als GetLast() vernuenftige
    1444             :     // Werte bereithalten muss:
    1445         995 :     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         995 :     if( pPor->IsPostItsPortion() && rInf.X() >= rInf.Width() && rInf.GetFly() )
    1455             :     {
    1456           0 :         delete pPor;
    1457           0 :         pPor = rInf.GetFly();
    1458             :     }
    1459         995 :     return pPor;
    1460             : }
    1461             : 
    1462             : /*************************************************************************
    1463             :  *                      SwTxtFormatter::FormatLine()
    1464             :  *************************************************************************/
    1465             : 
    1466         724 : 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         724 :     SwHookOut aHook( GetInfo() );
    1473         724 :     if( GetInfo().GetLen() < GetInfo().GetTxt().Len() )
    1474          60 :         GetInfo().SetLen( GetInfo().GetTxt().Len() );
    1475             : 
    1476         724 :     sal_Bool bBuild = sal_True;
    1477         724 :     SetFlyInCntBase( sal_False );
    1478         724 :     GetInfo().SetLineHeight( 0 );
    1479         724 :     GetInfo().SetLineNettoHeight( 0 );
    1480             : 
    1481             :     // Recycling muss bei geaenderter Zeilenhoehe unterdrueckt werden
    1482             :     // und auch bei geaendertem Ascent (Absenken der Grundlinie).
    1483         724 :     const KSHORT nOldHeight = pCurr->Height();
    1484         724 :     const KSHORT nOldAscent = pCurr->GetAscent();
    1485             : 
    1486         724 :     pCurr->SetEndHyph( sal_False );
    1487         724 :     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         724 :     SwLinePortion* pFld = GetInfo().GetRest();
    1492         724 :     SwFldPortion* pSaveFld = 0;
    1493             : 
    1494         724 :     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         724 :     const sal_Bool bOptimizeRepaint = AllowRepaintOpt();
    1500         724 :     const xub_StrLen nOldLineEnd = nStartPos + pCurr->GetLen();
    1501         724 :     std::vector<long> flyStarts;
    1502             : 
    1503             :     // these are the conditions for a fly position comparison
    1504         724 :     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        2172 :     while( bBuild )
    1521             :     {
    1522         724 :         GetInfo().SetFtnInside( false );
    1523         724 :         GetInfo().SetOtherThanFtnInside( false );
    1524             : 
    1525             :         // These values must not be reset by FormatReset();
    1526         724 :         sal_Bool bOldNumDone = GetInfo().IsNumDone();
    1527         724 :         sal_Bool bOldArrowDone = GetInfo().IsArrowDone();
    1528         724 :         sal_Bool bOldErgoDone = GetInfo().IsErgoDone();
    1529             : 
    1530             :         // besides other things, this sets the repaint offset to 0
    1531         724 :         FormatReset( GetInfo() );
    1532             : 
    1533         724 :         GetInfo().SetNumDone( bOldNumDone );
    1534         724 :         GetInfo().SetArrowDone( bOldArrowDone );
    1535         724 :         GetInfo().SetErgoDone( bOldErgoDone );
    1536             : 
    1537             :         // build new portions for this line
    1538         724 :         BuildPortions( GetInfo() );
    1539             : 
    1540         724 :         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         724 :         else if( GetInfo().IsDropInit() )
    1550             :         {
    1551           0 :             DropInit();
    1552           0 :             GetInfo().SetDropInit( sal_False );
    1553             :         }
    1554             : 
    1555         724 :         pCurr->CalcLine( *this, GetInfo() );
    1556         724 :         CalcRealHeight( GetInfo().IsNewLine() );
    1557             : 
    1558         724 :         if ( IsFlyInCntBase() && !IsQuick() )
    1559             :         {
    1560             :             KSHORT nTmpAscent, nTmpHeight;
    1561         130 :             CalcAscentAndHeight( nTmpAscent, nTmpHeight );
    1562         130 :             AlignFlyInCntBase( Y() + long( nTmpAscent ) );
    1563         130 :             pCurr->CalcLine( *this, GetInfo() );
    1564         130 :             CalcRealHeight();
    1565             :         }
    1566             : 
    1567             :         // bBuild entscheidet, ob noch eine Ehrenrunde gedreht wird
    1568         724 :         if ( pCurr->GetRealHeight() <= GetInfo().GetLineHeight() )
    1569             :         {
    1570           0 :             pCurr->SetRealHeight( GetInfo().GetLineHeight() );
    1571           0 :             bBuild = sal_False;
    1572             :         }
    1573             :         else
    1574             :         {
    1575         785 :             bBuild = ( GetInfo().GetTxtFly()->IsOn() && ChkFlyUnderflow(GetInfo()) )
    1576         785 :                      || GetInfo().CheckFtnPortion(pCurr);
    1577         724 :             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             :     // calculate optimal repaint rectangle
    1601         724 :     if ( bOptimizeRepaint )
    1602             :     {
    1603           0 :         GetInfo().SetPaintOfst( ::lcl_CalcOptRepaint( *this, *pCurr, nOldLineEnd, flyStarts ) );
    1604           0 :         flyStarts.clear();
    1605             :     }
    1606             :     else
    1607             :         // Special case: We do not allow an optimitation of the repaint
    1608             :         // area, but during formatting the repaint offset is set to indicate
    1609             :         // a maximum value for the offset. This value has to be reset:
    1610         724 :         GetInfo().SetPaintOfst( 0 );
    1611             : 
    1612             :     // This corrects the start of the reformat range if something has
    1613             :     // moved to the next line. Otherwise IsFirstReformat in AllowRepaintOpt
    1614             :     // will give us a wrong result if we have to reformat another line
    1615         724 :     GetInfo().GetParaPortion()->GetReformat()->LeftMove( GetInfo().GetIdx() );
    1616             : 
    1617             :     // delete master copy of rest portion
    1618         724 :     delete pSaveFld;
    1619             : 
    1620         724 :     xub_StrLen nNewStart = nStartPos + pCurr->GetLen();
    1621             : 
    1622             :     // adjust text if kana compression is enabled
    1623         724 :     if ( GetInfo().CompressLine() )
    1624             :     {
    1625           0 :         SwTwips nRepaintOfst = CalcKanaAdj( pCurr );
    1626             : 
    1627             :         // adjust repaint offset
    1628           0 :         if ( nRepaintOfst < GetInfo().GetPaintOfst() )
    1629           0 :             GetInfo().SetPaintOfst( nRepaintOfst );
    1630             :     }
    1631             : 
    1632         724 :     CalcAdjustLine( pCurr );
    1633             : 
    1634         724 :     if( nOldHeight != pCurr->Height() || nOldAscent != pCurr->GetAscent() )
    1635             :     {
    1636         712 :         SetFlyInCntBase();
    1637         712 :         GetInfo().SetPaintOfst( 0 ); //geaenderte Zeilenhoehe => kein Recycling
    1638             :         // alle weiteren Zeilen muessen gepaintet und, wenn Flys im Spiel sind
    1639             :         // auch formatiert werden.
    1640         712 :         GetInfo().SetShift( sal_True );
    1641             :     }
    1642             : 
    1643         724 :     if ( IsFlyInCntBase() && !IsQuick() )
    1644         712 :         UpdatePos( pCurr, GetTopLeft(), GetStart() );
    1645             : 
    1646         724 :     return nNewStart;
    1647             : }
    1648             : 
    1649             : /*************************************************************************
    1650             :  *                      SwTxtFormatter::RecalcRealHeight()
    1651             :  *************************************************************************/
    1652             : 
    1653           0 : void SwTxtFormatter::RecalcRealHeight()
    1654             : {
    1655           0 :     sal_Bool bMore = sal_True;
    1656           0 :     while(bMore)
    1657             :     {
    1658           0 :         CalcRealHeight();
    1659           0 :         bMore = Next() != 0;
    1660             :     }
    1661           0 : }
    1662             : 
    1663             : /*************************************************************************
    1664             :  *                    SwTxtFormatter::CalcRealHeight()
    1665             :  *************************************************************************/
    1666             : 
    1667         985 : void SwTxtFormatter::CalcRealHeight( sal_Bool bNewLine )
    1668             : {
    1669         985 :     KSHORT nLineHeight = pCurr->Height();
    1670         985 :     pCurr->SetClipping( sal_False );
    1671             : 
    1672         985 :     GETGRID( pFrm->FindPageFrm() )
    1673         985 :     if ( pGrid && GetInfo().SnapToGrid() )
    1674             :     {
    1675           0 :         const sal_uInt16 nGridWidth = pGrid->GetBaseHeight();
    1676           0 :         const sal_uInt16 nRubyHeight = pGrid->GetRubyHeight();
    1677           0 :         const sal_Bool bRubyTop = ! pGrid->GetRubyTextBelow();
    1678             : 
    1679           0 :         nLineHeight = nGridWidth + nRubyHeight;
    1680           0 :         sal_uInt16 nLineDist = nLineHeight;
    1681             : 
    1682           0 :         while ( pCurr->Height() > nLineHeight )
    1683           0 :             nLineHeight = nLineHeight + nLineDist;
    1684             : 
    1685           0 :         KSHORT nAsc = pCurr->GetAscent() +
    1686             :                       ( bRubyTop ?
    1687           0 :                        ( nLineHeight - pCurr->Height() + nRubyHeight ) / 2 :
    1688           0 :                        ( nLineHeight - pCurr->Height() - nRubyHeight ) / 2 );
    1689             : 
    1690           0 :         pCurr->Height( nLineHeight );
    1691           0 :         pCurr->SetAscent( nAsc );
    1692           0 :         pInf->GetParaPortion()->SetFixLineHeight();
    1693             : 
    1694             :         // we ignore any line spacing options except from ...
    1695           0 :         const SvxLineSpacingItem* pSpace = aLineInf.GetLineSpacing();
    1696           0 :         if ( ! IsParaLine() && pSpace &&
    1697           0 :              SVX_INTER_LINE_SPACE_PROP == pSpace->GetInterLineSpaceRule() )
    1698             :         {
    1699           0 :             sal_uLong nTmp = pSpace->GetPropLineSpace();
    1700             : 
    1701           0 :             if( nTmp < 100 )
    1702           0 :                 nTmp = 100;
    1703             : 
    1704           0 :             nTmp *= nLineHeight;
    1705           0 :             nLineHeight = (sal_uInt16)(nTmp / 100);
    1706             :         }
    1707             : 
    1708           0 :         pCurr->SetRealHeight( nLineHeight );
    1709         985 :         return;
    1710             :     }
    1711             : 
    1712             :     // Das Dummyflag besitzen Zeilen, die nur Flyportions enthalten, diese
    1713             :     // sollten kein Register etc. beachten. Dummerweise hat kann es eine leere
    1714             :     // Zeile am Absatzende geben (bei leeren Abs?tzen oder nach einem
    1715             :     // Shift-Return), die das Register durchaus beachten soll.
    1716        1061 :     if( !pCurr->IsDummy() || ( !pCurr->GetNext() &&
    1717          76 :         GetStart() >= GetTxtFrm()->GetTxt().Len() && !bNewLine ) )
    1718             :     {
    1719         983 :         const SvxLineSpacingItem *pSpace = aLineInf.GetLineSpacing();
    1720         983 :         if( pSpace )
    1721             :         {
    1722         983 :             switch( pSpace->GetLineSpaceRule() )
    1723             :             {
    1724             :                 case SVX_LINE_SPACE_AUTO:
    1725         971 :             if (pSpace->GetInterLineSpaceRule()==SVX_INTER_LINE_SPACE_PROP) {
    1726         189 :                         long nTmp = pSpace->GetPropLineSpace();
    1727         189 :                         if (nTmp<100) { // code adaped from fixed line height
    1728           0 :                             nTmp *= nLineHeight;
    1729           0 :                             nTmp /= 100;
    1730           0 :                             if( !nTmp )
    1731           0 :                                 ++nTmp;
    1732           0 :                             nLineHeight = (KSHORT)nTmp;
    1733             : /*
    1734             :                             //@TODO figure out how WW maps ascent and descent
    1735             :                             //in case of prop  line spacing <100%
    1736             :                             KSHORT nAsc = ( 4 * nLineHeight ) / 5;  // 80%
    1737             :                             if( nAsc < pCurr->GetAscent() ||
    1738             :                                 nLineHeight - nAsc < pCurr->Height() -
    1739             : pCurr->GetAscent() )
    1740             :                                 pCurr->SetClipping( sal_True );
    1741             :                             pCurr->SetAscent( nAsc );
    1742             : */
    1743           0 :                             pCurr->Height( nLineHeight );
    1744           0 :                             pInf->GetParaPortion()->SetFixLineHeight();
    1745             :                         }
    1746             :                     }
    1747         971 :                 break;
    1748             :                 case SVX_LINE_SPACE_MIN:
    1749             :                 {
    1750           4 :                     if( nLineHeight < KSHORT( pSpace->GetLineHeight() ) )
    1751           0 :                         nLineHeight = pSpace->GetLineHeight();
    1752           4 :                     break;
    1753             :                 }
    1754             :                 case SVX_LINE_SPACE_FIX:
    1755             :                 {
    1756           8 :                     nLineHeight = pSpace->GetLineHeight();
    1757           8 :                     KSHORT nAsc = ( 4 * nLineHeight ) / 5;  // 80%
    1758           8 :                     if( nAsc < pCurr->GetAscent() ||
    1759           0 :                         nLineHeight - nAsc < pCurr->Height() - pCurr->GetAscent() )
    1760           8 :                         pCurr->SetClipping( sal_True );
    1761           8 :                     pCurr->Height( nLineHeight );
    1762           8 :                     pCurr->SetAscent( nAsc );
    1763           8 :                     pInf->GetParaPortion()->SetFixLineHeight();
    1764             :                 }
    1765           8 :                 break;
    1766             :                 default: OSL_FAIL( ": unknown LineSpaceRule" );
    1767             :             }
    1768         983 :             if( !IsParaLine() )
    1769          86 :                 switch( pSpace->GetInterLineSpaceRule() )
    1770             :                 {
    1771             :                     case SVX_INTER_LINE_SPACE_OFF:
    1772          45 :                     break;
    1773             :                     case SVX_INTER_LINE_SPACE_PROP:
    1774             :                     {
    1775          41 :                         long nTmp = pSpace->GetPropLineSpace();
    1776             :                         // 50% ist das Minimum, bei 0% schalten wir auf
    1777             :                         // den Defaultwert 100% um ...
    1778          41 :                         if( nTmp < 50 )
    1779           0 :                             nTmp = nTmp ? 50 : 100;
    1780             : 
    1781          41 :                         nTmp *= nLineHeight;
    1782          41 :                         nTmp /= 100;
    1783          41 :                         if( !nTmp )
    1784           0 :                             ++nTmp;
    1785          41 :                         nLineHeight = (KSHORT)nTmp;
    1786          41 :                         break;
    1787             :                     }
    1788             :                     case SVX_INTER_LINE_SPACE_FIX:
    1789             :                     {
    1790           0 :                         nLineHeight = nLineHeight + pSpace->GetInterLineSpace();
    1791           0 :                         break;
    1792             :                     }
    1793             :                     default: OSL_FAIL( ": unknown InterLineSpaceRule" );
    1794             :                 }
    1795             :         }
    1796             : #if OSL_DEBUG_LEVEL > 1
    1797             :         KSHORT nDummy = nLineHeight + 1;
    1798             :         (void)nDummy;
    1799             : #endif
    1800             : 
    1801         983 :         if( IsRegisterOn() )
    1802             :         {
    1803           0 :             SwTwips nTmpY = Y() + pCurr->GetAscent() + nLineHeight - pCurr->Height();
    1804           0 :             SWRECTFN( pFrm )
    1805           0 :             if ( bVert )
    1806           0 :                 nTmpY = pFrm->SwitchHorizontalToVertical( nTmpY );
    1807           0 :             nTmpY = (*fnRect->fnYDiff)( nTmpY, RegStart() );
    1808           0 :             KSHORT nDiff = KSHORT( nTmpY % RegDiff() );
    1809           0 :             if( nDiff )
    1810           0 :                 nLineHeight += RegDiff() - nDiff;
    1811             :         }
    1812             :     }
    1813         985 :     pCurr->SetRealHeight( nLineHeight );
    1814             : }
    1815             : 
    1816             : /*************************************************************************
    1817             :  *                      SwTxtFormatter::FeedInf()
    1818             :  *************************************************************************/
    1819             : 
    1820         755 : void SwTxtFormatter::FeedInf( SwTxtFormatInfo &rInf ) const
    1821             : {
    1822             :     // 3260, 3860: Fly auf jeden Fall loeschen!
    1823         755 :     ClearFly( rInf );
    1824         755 :     rInf.Init();
    1825             : 
    1826         755 :     rInf.ChkNoHyph( CntEndHyph(), CntMidHyph() );
    1827         755 :     rInf.SetRoot( pCurr );
    1828         755 :     rInf.SetLineStart( nStart );
    1829         755 :     rInf.SetIdx( nStart );
    1830             : 
    1831             :     // Handle overflows:
    1832             :     // #i34348# Changed type from sal_uInt16 to SwTwips
    1833         755 :     SwTwips nTmpLeft = Left();
    1834         755 :     SwTwips nTmpRight = Right();
    1835         755 :     SwTwips nTmpFirst = FirstLeft();
    1836             : 
    1837         755 :     if ( nTmpLeft > USHRT_MAX ||
    1838             :          nTmpRight > USHRT_MAX ||
    1839             :          nTmpFirst > USHRT_MAX )
    1840             :     {
    1841           0 :         SWRECTFN( rInf.GetTxtFrm() )
    1842           0 :         nTmpLeft = (rInf.GetTxtFrm()->Frm().*fnRect->fnGetLeft)();
    1843           0 :         nTmpRight = (rInf.GetTxtFrm()->Frm().*fnRect->fnGetRight)();
    1844           0 :         nTmpFirst = nTmpLeft;
    1845             :     }
    1846             : 
    1847         755 :     rInf.Left(  nTmpLeft  );
    1848         755 :     rInf.Right( nTmpRight );
    1849         755 :     rInf.First( nTmpFirst );
    1850             : 
    1851         755 :     rInf.RealWidth( KSHORT(rInf.Right()) - KSHORT(GetLeftMargin()) );
    1852         755 :     rInf.Width( rInf.RealWidth() );
    1853         755 :     if( ((SwTxtFormatter*)this)->GetRedln() )
    1854             :     {
    1855           2 :         ((SwTxtFormatter*)this)->GetRedln()->Clear( ((SwTxtFormatter*)this)->GetFnt() );
    1856           2 :         ((SwTxtFormatter*)this)->GetRedln()->Reset();
    1857             :     }
    1858         755 : }
    1859             : 
    1860             : /*************************************************************************
    1861             :  *                      SwTxtFormatter::FormatReset()
    1862             :  *************************************************************************/
    1863             : 
    1864         755 : void SwTxtFormatter::FormatReset( SwTxtFormatInfo &rInf )
    1865             : {
    1866         755 :     pCurr->Truncate();
    1867         755 :     pCurr->Init();
    1868         755 :     if( pBlink && pCurr->IsBlinking() )
    1869           0 :         pBlink->Delete( pCurr );
    1870             : 
    1871             :     // delete pSpaceAdd und pKanaComp
    1872         755 :     pCurr->FinishSpaceAdd();
    1873         755 :     pCurr->FinishKanaComp();
    1874         755 :     pCurr->ResetFlags();
    1875         755 :     FeedInf( rInf );
    1876         755 : }
    1877             : 
    1878             : /*************************************************************************
    1879             :  *                SwTxtFormatter::CalcOnceMore()
    1880             :  *************************************************************************/
    1881             : 
    1882           0 : sal_Bool SwTxtFormatter::CalcOnceMore()
    1883             : {
    1884           0 :     if( pDropFmt )
    1885             :     {
    1886           0 :         const KSHORT nOldDrop = GetDropHeight();
    1887           0 :         CalcDropHeight( pDropFmt->GetLines() );
    1888           0 :         bOnceMore = nOldDrop != GetDropHeight();
    1889             :     }
    1890             :     else
    1891           0 :         bOnceMore = sal_False;
    1892           0 :     return bOnceMore;
    1893             : }
    1894             : 
    1895             : /*************************************************************************
    1896             :  *                SwTxtFormatter::CalcBottomLine()
    1897             :  *************************************************************************/
    1898             : 
    1899         662 : SwTwips SwTxtFormatter::CalcBottomLine() const
    1900             : {
    1901         662 :     SwTwips nRet = Y() + GetLineHeight();
    1902         662 :     SwTwips nMin = GetInfo().GetTxtFly()->GetMinBottom();
    1903         662 :     if( nMin && ++nMin > nRet )
    1904             :     {
    1905           0 :         SwTwips nDist = pFrm->Frm().Height() - pFrm->Prt().Height()
    1906           0 :                         - pFrm->Prt().Top();
    1907           0 :         if( nRet + nDist < nMin )
    1908             :         {
    1909           0 :             sal_Bool bRepaint = HasTruncLines() &&
    1910           0 :                 GetInfo().GetParaPortion()->GetRepaint()->Bottom() == nRet-1;
    1911           0 :             nRet = nMin - nDist;
    1912           0 :             if( bRepaint )
    1913             :             {
    1914           0 :                 ((SwRepaint*)GetInfo().GetParaPortion()
    1915           0 :                     ->GetRepaint())->Bottom( nRet-1 );
    1916           0 :                 ((SwTxtFormatInfo&)GetInfo()).SetPaintOfst( 0 );
    1917             :             }
    1918             :         }
    1919             :     }
    1920         662 :     return nRet;
    1921             : }
    1922             : 
    1923             : /*************************************************************************
    1924             :  *                SwTxtFormatter::_CalcFitToContent()
    1925             :  *
    1926             :  * FME/OD: This routine does a limited text formatting.
    1927             :  *************************************************************************/
    1928             : 
    1929          30 : SwTwips SwTxtFormatter::_CalcFitToContent()
    1930             : {
    1931          30 :     FormatReset( GetInfo() );
    1932          30 :     BuildPortions( GetInfo() );
    1933          30 :     pCurr->CalcLine( *this, GetInfo() );
    1934          30 :     return pCurr->Width();
    1935             : }
    1936             : 
    1937             : /*************************************************************************
    1938             :  *                      SwTxtFormatter::AllowRepaintOpt()
    1939             :  *
    1940             :  * determines if the calculation of a repaint offset is allowed
    1941             :  * otherwise each line is painted from 0 (this is a copy of the beginning
    1942             :  * of the former SwTxtFormatter::Recycle() function
    1943             :  *************************************************************************/
    1944         724 : sal_Bool SwTxtFormatter::AllowRepaintOpt() const
    1945             : {
    1946             :     // reformat position in front of current line? Only in this case
    1947             :     // we want to set the repaint offset
    1948         724 :     sal_Bool bOptimizeRepaint = nStart < GetInfo().GetReformatStart() &&
    1949        1448 :                                 pCurr->GetLen();
    1950             : 
    1951             :     // a special case is the last line of a block adjusted paragraph:
    1952         724 :     if ( bOptimizeRepaint )
    1953             :     {
    1954           0 :         switch( GetAdjust() )
    1955             :         {
    1956             :         case SVX_ADJUST_BLOCK:
    1957             :         {
    1958           0 :             if( IsLastBlock() || IsLastCenter() )
    1959           0 :                 bOptimizeRepaint = sal_False;
    1960             :             else
    1961             :             {
    1962             :                 // ????: Blank in der letzten Masterzeile (blocksat.sdw)
    1963           0 :                 bOptimizeRepaint = 0 == pCurr->GetNext() && !pFrm->GetFollow();
    1964           0 :                 if ( bOptimizeRepaint )
    1965             :                 {
    1966           0 :                     SwLinePortion *pPos = pCurr->GetFirstPortion();
    1967           0 :                     while ( pPos && !pPos->IsFlyPortion() )
    1968           0 :                         pPos = pPos->GetPortion();
    1969           0 :                     bOptimizeRepaint = !pPos;
    1970             :                 }
    1971             :             }
    1972           0 :             break;
    1973             :         }
    1974             :         case SVX_ADJUST_CENTER:
    1975             :         case SVX_ADJUST_RIGHT:
    1976           0 :             bOptimizeRepaint = sal_False;
    1977           0 :             break;
    1978             :         default: ;
    1979             :         }
    1980             :     }
    1981             : 
    1982             :     // Schon wieder ein Sonderfall: unsichtbare SoftHyphs
    1983         724 :     const xub_StrLen nReformat = GetInfo().GetReformatStart();
    1984         724 :     if( bOptimizeRepaint && STRING_LEN != nReformat )
    1985             :     {
    1986           0 :         const sal_Unicode cCh = GetInfo().GetTxt().GetChar( nReformat );
    1987             :         bOptimizeRepaint = ( CH_TXTATR_BREAKWORD != cCh && CH_TXTATR_INWORD != cCh )
    1988           0 :                             || ! GetInfo().HasHint( nReformat );
    1989             :     }
    1990             : 
    1991         724 :     return bOptimizeRepaint;
    1992             : }
    1993             : 
    1994           3 : void SwTxtFormatter::CalcUnclipped( SwTwips& rTop, SwTwips& rBottom )
    1995             : {
    1996             :     OSL_ENSURE( ! pFrm->IsVertical() || pFrm->IsSwapped(),
    1997             :             "SwTxtFormatter::CalcUnclipped with unswapped frame" );
    1998             : 
    1999             :     long nFlyAsc, nFlyDesc;
    2000           3 :     pCurr->MaxAscentDescent( rTop, rBottom, nFlyAsc, nFlyDesc );
    2001           3 :     rTop = Y() + GetCurr()->GetAscent();
    2002           3 :     rBottom = rTop + nFlyDesc;
    2003           3 :     rTop -= nFlyAsc;
    2004           3 : }
    2005             : 
    2006             : 
    2007         713 : void SwTxtFormatter::UpdatePos( SwLineLayout *pCurrent, Point aStart,
    2008             :     xub_StrLen nStartIdx, sal_Bool bAllWays ) const
    2009             : {
    2010             :     OSL_ENSURE( ! pFrm->IsVertical() || pFrm->IsSwapped(),
    2011             :             "SwTxtFormatter::UpdatePos with unswapped frame" );
    2012             : 
    2013         713 :     if( GetInfo().IsTest() )
    2014         713 :         return;
    2015         713 :     SwLinePortion *pFirst = pCurrent->GetFirstPortion();
    2016         713 :     SwLinePortion *pPos = pFirst;
    2017         713 :     SwTxtPaintInfo aTmpInf( GetInfo() );
    2018         713 :     aTmpInf.SetpSpaceAdd( pCurrent->GetpLLSpaceAdd() );
    2019         713 :     aTmpInf.ResetSpaceIdx();
    2020         713 :     aTmpInf.SetKanaComp( pCurrent->GetpKanaComp() );
    2021         713 :     aTmpInf.ResetKanaIdx();
    2022             : 
    2023             :     // The frame's size
    2024         713 :     aTmpInf.SetIdx( nStartIdx );
    2025         713 :     aTmpInf.SetPos( aStart );
    2026             : 
    2027             :     long nTmpAscent, nTmpDescent, nFlyAsc, nFlyDesc;
    2028         713 :     pCurrent->MaxAscentDescent( nTmpAscent, nTmpDescent, nFlyAsc, nFlyDesc );
    2029             : 
    2030         713 :     KSHORT nTmpHeight = pCurrent->GetRealHeight();
    2031         713 :     KSHORT nAscent = pCurrent->GetAscent() + nTmpHeight - pCurrent->Height();
    2032         713 :     objectpositioning::AsCharFlags nFlags = AS_CHAR_ULSPACE;
    2033         713 :     if( GetMulti() )
    2034             :     {
    2035           0 :         aTmpInf.SetDirection( GetMulti()->GetDirection() );
    2036           0 :         if( GetMulti()->HasRotation() )
    2037             :         {
    2038           0 :             nFlags |= AS_CHAR_ROTATE;
    2039           0 :             if( GetMulti()->IsRevers() )
    2040             :             {
    2041           0 :                 nFlags |= AS_CHAR_REVERSE;
    2042           0 :                 aTmpInf.X( aTmpInf.X() - nAscent );
    2043             :             }
    2044             :             else
    2045           0 :                 aTmpInf.X( aTmpInf.X() + nAscent );
    2046             :         }
    2047             :         else
    2048             :         {
    2049           0 :             if ( GetMulti()->IsBidi() )
    2050           0 :                 nFlags |= AS_CHAR_BIDI;
    2051           0 :             aTmpInf.Y( aTmpInf.Y() + nAscent );
    2052             :         }
    2053             :     }
    2054             :     else
    2055         713 :         aTmpInf.Y( aTmpInf.Y() + nAscent );
    2056             : 
    2057        2349 :     while( pPos )
    2058             :     {
    2059             :         // We only know one case where changing the position (caused by the
    2060             :         // adjustment) could be relevant for a portion: We need to SetRefPoint
    2061             :         // for FlyCntPortions.
    2062        1087 :         if( ( pPos->IsFlyCntPortion() || pPos->IsGrfNumPortion() )
    2063         164 :             && ( bAllWays || !IsQuick() ) )
    2064             :         {
    2065         165 :             pCurrent->MaxAscentDescent( nTmpAscent, nTmpDescent, nFlyAsc, nFlyDesc, pPos );
    2066             : 
    2067         165 :             if( pPos->IsGrfNumPortion() )
    2068             :             {
    2069           0 :                 if( !nFlyAsc && !nFlyDesc )
    2070             :                 {
    2071           0 :                     nTmpAscent = nAscent;
    2072           0 :                     nFlyAsc = nAscent;
    2073           0 :                     nTmpDescent = nTmpHeight - nAscent;
    2074           0 :                     nFlyDesc = nTmpDescent;
    2075             :                 }
    2076             :                 ((SwGrfNumPortion*)pPos)->SetBase( nTmpAscent, nTmpDescent,
    2077           0 :                                                    nFlyAsc, nFlyDesc );
    2078             :             }
    2079             :             else
    2080             :             {
    2081         165 :                 Point aBase( aTmpInf.GetPos() );
    2082         165 :                 if ( GetInfo().GetTxtFrm()->IsVertical() )
    2083           0 :                     GetInfo().GetTxtFrm()->SwitchHorizontalToVertical( aBase );
    2084             : 
    2085         165 :                 ((SwFlyCntPortion*)pPos)->SetBase( *aTmpInf.GetTxtFrm(),
    2086             :                     aBase, nTmpAscent, nTmpDescent, nFlyAsc,
    2087         330 :                     nFlyDesc, nFlags );
    2088             :             }
    2089             :         }
    2090         923 :         if( pPos->IsMultiPortion() && ((SwMultiPortion*)pPos)->HasFlyInCntnt() )
    2091             :         {
    2092             :             OSL_ENSURE( !GetMulti(), "Too much multi" );
    2093           0 :             ((SwTxtFormatter*)this)->pMulti = (SwMultiPortion*)pPos;
    2094           0 :             SwLineLayout *pLay = &GetMulti()->GetRoot();
    2095           0 :             Point aSt( aTmpInf.X(), aStart.Y() );
    2096             : 
    2097           0 :             if ( GetMulti()->HasBrackets() )
    2098             :             {
    2099             :                 OSL_ENSURE( GetMulti()->IsDouble(), "Brackets only for doubles");
    2100           0 :                 aSt.X() += ((SwDoubleLinePortion*)GetMulti())->PreWidth();
    2101             :             }
    2102           0 :             else if( GetMulti()->HasRotation() )
    2103             :             {
    2104           0 :                 aSt.Y() += pCurrent->GetAscent() - GetMulti()->GetAscent();
    2105           0 :                 if( GetMulti()->IsRevers() )
    2106           0 :                     aSt.X() += GetMulti()->Width();
    2107             :                 else
    2108           0 :                     aSt.Y() += GetMulti()->Height();
    2109             :                }
    2110           0 :             else if ( GetMulti()->IsBidi() )
    2111             :                 // jump to end of the bidi portion
    2112           0 :                 aSt.X() += pLay->Width();
    2113             : 
    2114           0 :             xub_StrLen nStIdx = aTmpInf.GetIdx();
    2115           0 :             do
    2116             :             {
    2117           0 :                 UpdatePos( pLay, aSt, nStIdx, bAllWays );
    2118           0 :                 nStIdx = nStIdx + pLay->GetLen();
    2119           0 :                 aSt.Y() += pLay->Height();
    2120           0 :                 pLay = pLay->GetNext();
    2121             :             } while ( pLay );
    2122           0 :             ((SwTxtFormatter*)this)->pMulti = NULL;
    2123             :         }
    2124         923 :         pPos->Move( aTmpInf );
    2125         923 :         pPos = pPos->GetPortion();
    2126         713 :     }
    2127             : }
    2128             : 
    2129             : 
    2130         130 : void SwTxtFormatter::AlignFlyInCntBase( long nBaseLine ) const
    2131             : {
    2132             :     OSL_ENSURE( ! pFrm->IsVertical() || pFrm->IsSwapped(),
    2133             :             "SwTxtFormatter::AlignFlyInCntBase with unswapped frame" );
    2134             : 
    2135         130 :     if( GetInfo().IsTest() )
    2136         130 :         return;
    2137         130 :     SwLinePortion *pFirst = pCurr->GetFirstPortion();
    2138         130 :     SwLinePortion *pPos = pFirst;
    2139         130 :     objectpositioning::AsCharFlags nFlags = AS_CHAR_NOFLAG;
    2140         130 :     if( GetMulti() && GetMulti()->HasRotation() )
    2141             :     {
    2142           0 :         nFlags |= AS_CHAR_ROTATE;
    2143           0 :         if( GetMulti()->IsRevers() )
    2144           0 :             nFlags |= AS_CHAR_REVERSE;
    2145             :     }
    2146             : 
    2147             :     long nTmpAscent, nTmpDescent, nFlyAsc, nFlyDesc;
    2148             : 
    2149         426 :     while( pPos )
    2150             :     {
    2151         166 :         if( pPos->IsFlyCntPortion() || pPos->IsGrfNumPortion() )
    2152             :         {
    2153         164 :             pCurr->MaxAscentDescent( nTmpAscent, nTmpDescent, nFlyAsc, nFlyDesc, pPos );
    2154             : 
    2155         164 :             if( pPos->IsGrfNumPortion() )
    2156             :                 ((SwGrfNumPortion*)pPos)->SetBase( nTmpAscent, nTmpDescent,
    2157           0 :                                                    nFlyAsc, nFlyDesc );
    2158             :             else
    2159             :             {
    2160         164 :                 Point aBase;
    2161         164 :                 if ( GetInfo().GetTxtFrm()->IsVertical() )
    2162             :                 {
    2163           0 :                     nBaseLine = GetInfo().GetTxtFrm()->SwitchHorizontalToVertical( nBaseLine );
    2164           0 :                     aBase = Point( nBaseLine, ((SwFlyCntPortion*)pPos)->GetRefPoint().Y() );
    2165             :                 }
    2166             :                 else
    2167         164 :                     aBase = Point( ((SwFlyCntPortion*)pPos)->GetRefPoint().X(), nBaseLine );
    2168             : 
    2169         164 :                 ((SwFlyCntPortion*)pPos)->SetBase( *GetInfo().GetTxtFrm(), aBase, nTmpAscent, nTmpDescent,
    2170         328 :                     nFlyAsc, nFlyDesc, nFlags );
    2171             :             }
    2172             :         }
    2173         166 :         pPos = pPos->GetPortion();
    2174             :     }
    2175             : }
    2176             : 
    2177             : 
    2178          61 : sal_Bool SwTxtFormatter::ChkFlyUnderflow( SwTxtFormatInfo &rInf ) const
    2179             : {
    2180             :     OSL_ENSURE( rInf.GetTxtFly()->IsOn(), "SwTxtFormatter::ChkFlyUnderflow: why?" );
    2181          61 :     if( GetCurr() )
    2182             :     {
    2183             :         // First we check, whether a fly overlaps with the line.
    2184             :         // = GetLineHeight()
    2185          61 :         const long nHeight = GetCurr()->GetRealHeight();
    2186          61 :         SwRect aLine( GetLeftMargin(), Y(), rInf.RealWidth(), nHeight );
    2187             : 
    2188          61 :         SwRect aLineVert( aLine );
    2189          61 :         if ( pFrm->IsVertical() )
    2190           0 :             pFrm->SwitchHorizontalToVertical( aLineVert );
    2191          61 :         SwRect aInter( rInf.GetTxtFly()->GetFrm( aLineVert ) );
    2192          61 :         if ( pFrm->IsVertical() )
    2193           0 :             pFrm->SwitchVerticalToHorizontal( aInter );
    2194             : 
    2195          61 :         if( !aInter.HasArea() )
    2196          21 :             return sal_False;
    2197             : 
    2198             :         // We now check every portion that could have lowered for overlapping
    2199             :         // with the fly.
    2200          40 :         const SwLinePortion *pPos = GetCurr()->GetFirstPortion();
    2201          40 :         aLine.Pos().Y() = Y() + GetCurr()->GetRealHeight() - GetCurr()->Height();
    2202          40 :         aLine.Height( GetCurr()->Height() );
    2203             : 
    2204         120 :         while( pPos )
    2205             :         {
    2206          40 :             aLine.Width( pPos->Width() );
    2207             : 
    2208          40 :             aLineVert = aLine;
    2209          40 :             if ( pFrm->IsVertical() )
    2210           0 :                 pFrm->SwitchHorizontalToVertical( aLineVert );
    2211          40 :             aInter = rInf.GetTxtFly()->GetFrm( aLineVert );
    2212          40 :             if ( pFrm->IsVertical() )
    2213           0 :                 pFrm->SwitchVerticalToHorizontal( aInter );
    2214             : 
    2215             :             // New flys from below?
    2216          40 :             if( !pPos->IsFlyPortion() )
    2217             :             {
    2218          32 :                 if( aInter.IsOver( aLine ) )
    2219             :                 {
    2220           0 :                     aInter._Intersection( aLine );
    2221           0 :                     if( aInter.HasArea() )
    2222             :                     {
    2223             :                         // To be evaluated during reformat of this line:
    2224             :                         // RealHeight including spacing
    2225           0 :                         rInf.SetLineHeight( KSHORT(nHeight) );
    2226             :                         // Height without extra spacing
    2227           0 :                         rInf.SetLineNettoHeight( KSHORT( pCurr->Height() ) );
    2228           0 :                         return sal_True;
    2229             :                     }
    2230             :                 }
    2231             :             }
    2232             :             else
    2233             :             {
    2234             :                 // The fly portion is not intersected by a fly anymore
    2235           8 :                 if ( ! aInter.IsOver( aLine ) )
    2236             :                 {
    2237           0 :                     rInf.SetLineHeight( KSHORT(nHeight) );
    2238           0 :                     rInf.SetLineNettoHeight( KSHORT( pCurr->Height() ) );
    2239           0 :                     return sal_True;
    2240             :                 }
    2241             :                 else
    2242             :                 {
    2243           8 :                     aInter._Intersection( aLine );
    2244             : 
    2245             :                     // No area means a fly has become invalid because of
    2246             :                     // lowering the line => reformat the line
    2247             :                     // we also have to reformat the line, if the fly size
    2248             :                     // differs from the intersection interval's size.
    2249          24 :                     if( ! aInter.HasArea() ||
    2250          16 :                         ((SwFlyPortion*)pPos)->GetFixWidth() != aInter.Width() )
    2251             :                     {
    2252           0 :                         rInf.SetLineHeight( KSHORT(nHeight) );
    2253           0 :                         rInf.SetLineNettoHeight( KSHORT( pCurr->Height() ) );
    2254           0 :                         return sal_True;
    2255             :                     }
    2256             :                 }
    2257             :             }
    2258             : 
    2259          40 :             aLine.Left( aLine.Left() + pPos->Width() );
    2260          40 :             pPos = pPos->GetPortion();
    2261             :         }
    2262             :     }
    2263          40 :     return sal_False;
    2264             : }
    2265             : 
    2266        2417 : void SwTxtFormatter::CalcFlyWidth( SwTxtFormatInfo &rInf )
    2267             : {
    2268        2417 :     if( GetMulti() || rInf.GetFly() )
    2269             :         return;
    2270             : 
    2271        2412 :     SwTxtFly *pTxtFly = rInf.GetTxtFly();
    2272        2412 :     if( !pTxtFly->IsOn() || rInf.IsIgnoreFly() )
    2273             :         return;
    2274             : 
    2275         191 :     const SwLinePortion *pLast = rInf.GetLast();
    2276             : 
    2277             :     long nAscent;
    2278         191 :     long nTop = Y();
    2279             :     long nHeight;
    2280             : 
    2281         191 :     if( rInf.GetLineHeight() )
    2282             :     {
    2283             :         // Real line height has already been calculated, we only have to
    2284             :         // search for intersections in the lower part of the strip
    2285           0 :         nAscent = pCurr->GetAscent();
    2286           0 :         nHeight = rInf.GetLineNettoHeight();
    2287           0 :         nTop += rInf.GetLineHeight() - nHeight;
    2288             :     }
    2289             :     else
    2290             :     {
    2291         191 :         nAscent = pLast->GetAscent();
    2292         191 :         nHeight = pLast->Height();
    2293             : 
    2294             :         // We make a first guess for the lines real height
    2295         191 :         if ( ! pCurr->GetRealHeight() )
    2296         126 :             CalcRealHeight();
    2297             : 
    2298         191 :         if ( pCurr->GetRealHeight() > nHeight )
    2299           0 :             nTop += pCurr->GetRealHeight() - nHeight;
    2300             :         else
    2301             :             // Important for fixed space between lines
    2302         191 :             nHeight = pCurr->GetRealHeight();
    2303             :     }
    2304             : 
    2305         191 :     const long nLeftMar = GetLeftMargin();
    2306         191 :     const long nLeftMin = (rInf.X() || GetDropLeft()) ? nLeftMar : GetLeftMin();
    2307             : 
    2308         573 :     SwRect aLine( rInf.X() + nLeftMin, nTop, rInf.RealWidth() - rInf.X()
    2309         573 :                   + nLeftMar - nLeftMin , nHeight );
    2310             : 
    2311         191 :     SwRect aLineVert( aLine );
    2312         191 :     if ( pFrm->IsRightToLeft() )
    2313           0 :         pFrm->SwitchLTRtoRTL( aLineVert );
    2314             : 
    2315         191 :     if ( pFrm->IsVertical() )
    2316           0 :         pFrm->SwitchHorizontalToVertical( aLineVert );
    2317         191 :     SwRect aInter( pTxtFly->GetFrm( aLineVert ) );
    2318             : 
    2319         191 :     if ( pFrm->IsRightToLeft() )
    2320           0 :         pFrm->SwitchRTLtoLTR( aInter );
    2321             : 
    2322         191 :     if ( pFrm->IsVertical() )
    2323           0 :         pFrm->SwitchVerticalToHorizontal( aInter );
    2324             : 
    2325         191 :     if( aInter.IsOver( aLine ) )
    2326             :     {
    2327          75 :         aLine.Left( rInf.X() + nLeftMar );
    2328          75 :         sal_Bool bForced = sal_False;
    2329          75 :         if( aInter.Left() <= nLeftMin )
    2330             :         {
    2331           8 :             SwTwips nFrmLeft = GetTxtFrm()->Frm().Left();
    2332           8 :             if( GetTxtFrm()->Prt().Left() < 0 )
    2333           0 :                 nFrmLeft += GetTxtFrm()->Prt().Left();
    2334           8 :             if( aInter.Left() < nFrmLeft )
    2335           8 :                 aInter.Left( nFrmLeft );
    2336             : 
    2337           8 :             long nAddMar = 0;
    2338           8 :             if ( pFrm->IsRightToLeft() )
    2339             :             {
    2340           0 :                 nAddMar = pFrm->Frm().Right() - Right();
    2341           0 :                 if ( nAddMar < 0 )
    2342           0 :                     nAddMar = 0;
    2343             :             }
    2344             :             else
    2345           8 :                 nAddMar = nLeftMar - nFrmLeft;
    2346             : 
    2347           8 :             aInter.Width( aInter.Width() + nAddMar );
    2348             :             // For a negative first line indent, we set this flag to show
    2349             :             // that the indentation/margin has been moved.
    2350             :             // This needs to be respected by the DefaultTab at the zero position.
    2351           8 :             if( IsFirstTxtLine() && HasNegFirst() )
    2352           0 :                 bForced = sal_True;
    2353             :         }
    2354          75 :         aInter.Intersection( aLine );
    2355          75 :         if( !aInter.HasArea() )
    2356             :             return;
    2357             : 
    2358          75 :         const sal_Bool bFullLine =  aLine.Left()  == aInter.Left() &&
    2359          75 :                                 aLine.Right() == aInter.Right();
    2360             : 
    2361             :         // Although no text is left, we need to format another line,
    2362             :         // because also empty lines need to avoid a Fly with no wrapping.
    2363          75 :         if( bFullLine && rInf.GetIdx() == rInf.GetTxt().Len() )
    2364             :         {
    2365           2 :             rInf.SetNewLine( sal_True );
    2366             :             // 8221: We know that for dummies, it holds ascent == height
    2367           2 :             pCurr->SetDummy(sal_True);
    2368             :         }
    2369             : 
    2370             :         // aInter becomes frame-local
    2371          75 :         aInter.Pos().X() -= nLeftMar;
    2372          75 :         SwFlyPortion *pFly = new SwFlyPortion( aInter );
    2373          75 :         if( bForced )
    2374             :         {
    2375           0 :             pCurr->SetForcedLeftMargin( sal_True );
    2376           0 :             rInf.ForcedLeftMargin( (sal_uInt16)aInter.Width() );
    2377             :         }
    2378             : 
    2379          75 :         if( bFullLine )
    2380             :         {
    2381             :             // 8110: In order to properly flow around Flys with different
    2382             :             // wrapping attributes, we need to increase by units of line height.
    2383             :             // The last avoiding line should be adjusted in height, so that
    2384             :             // we don't get a frame spacing effect.
    2385             :             // 8221: It is important that ascent == height, because the FlyPortion
    2386             :             // values are transferred to pCurr in CalcLine and IsDummy() relies
    2387             :             // on this behaviour.
    2388             :             // To my knowledge we only have two places where DummyLines can be
    2389             :             // created: here and in MakeFlyDummies.
    2390             :             // IsDummy() is evaluated in IsFirstTxtLine(), when moving lines
    2391             :             // and in relation with DropCaps.
    2392           2 :             pFly->Height( KSHORT(aInter.Height()) );
    2393             : 
    2394             :             // nNextTop now contains the margin's bottom edge, which we avoid
    2395             :             // or the next margin's top edge, which we need to respect.
    2396             :             // That means we can comfortably grow up to this value; that's how
    2397             :             // we save a few empty lines.
    2398           2 :             long nNextTop = pTxtFly->GetNextTop();
    2399           2 :             if ( pFrm->IsVertical() )
    2400           0 :                 nNextTop = pFrm->SwitchVerticalToHorizontal( nNextTop );
    2401           2 :             if( nNextTop > aInter.Bottom() )
    2402             :             {
    2403           2 :                 SwTwips nH = nNextTop - aInter.Top();
    2404           2 :                 if( nH < KSHRT_MAX )
    2405           2 :                     pFly->Height( KSHORT( nH ) );
    2406             :             }
    2407           2 :             if( nAscent < pFly->Height() )
    2408           2 :                 pFly->SetAscent( KSHORT(nAscent) );
    2409             :             else
    2410           0 :                 pFly->SetAscent( pFly->Height() );
    2411             :         }
    2412             :         else
    2413             :         {
    2414          73 :             if( rInf.GetIdx() == rInf.GetTxt().Len() )
    2415             :             {
    2416             :                 // Don't use nHeight, or we have a huge descent
    2417          69 :                 pFly->Height( pLast->Height() );
    2418          69 :                 pFly->SetAscent( pLast->GetAscent() );
    2419             :             }
    2420             :             else
    2421             :             {
    2422           4 :                 pFly->Height( KSHORT(aInter.Height()) );
    2423           4 :                 if( nAscent < pFly->Height() )
    2424           4 :                     pFly->SetAscent( KSHORT(nAscent) );
    2425             :                 else
    2426           0 :                     pFly->SetAscent( pFly->Height() );
    2427             :             }
    2428             :         }
    2429             : 
    2430          75 :         rInf.SetFly( pFly );
    2431             : 
    2432          75 :         if( pFly->Fix() < rInf.Width() )
    2433          43 :             rInf.Width( pFly->Fix() );
    2434             : 
    2435          75 :         GETGRID( pFrm->FindPageFrm() )
    2436          75 :         if ( pGrid )
    2437             :         {
    2438           0 :             const SwPageFrm* pPageFrm = pFrm->FindPageFrm();
    2439           0 :             const SwLayoutFrm* pBody = pPageFrm->FindBodyCont();
    2440             : 
    2441           0 :             SWRECTFN( pPageFrm )
    2442             : 
    2443             :             const long nGridOrigin = pBody ?
    2444           0 :                                     (pBody->*fnRect->fnGetPrtLeft)() :
    2445           0 :                                     (pPageFrm->*fnRect->fnGetPrtLeft)();
    2446             : 
    2447           0 :             const SwDoc *pDoc = rInf.GetTxtFrm()->GetNode()->GetDoc();
    2448           0 :             const sal_uInt16 nGridWidth = GETGRIDWIDTH( pGrid, pDoc);   //For textgrid refactor
    2449             : 
    2450           0 :             SwTwips nStartX = GetLeftMargin();
    2451           0 :             if ( bVert )
    2452             :             {
    2453           0 :                 Point aPoint( nStartX, 0 );
    2454           0 :                 pFrm->SwitchHorizontalToVertical( aPoint );
    2455           0 :                 nStartX = aPoint.Y();
    2456             :             }
    2457             : 
    2458           0 :             const SwTwips nOfst = nStartX - nGridOrigin;
    2459           0 :             const SwTwips nTmpWidth = rInf.Width() + nOfst;
    2460             : 
    2461           0 :             const sal_uLong i = nTmpWidth / nGridWidth + 1;
    2462             : 
    2463           0 :             const long nNewWidth = ( i - 1 ) * nGridWidth - nOfst;
    2464           0 :             if ( nNewWidth > 0 )
    2465           0 :                 rInf.Width( (sal_uInt16)nNewWidth );
    2466             :             else
    2467           0 :                 rInf.Width( 0 );
    2468             :         }
    2469             :     }
    2470             : }
    2471             : 
    2472             : 
    2473         165 : SwFlyCntPortion *SwTxtFormatter::NewFlyCntPortion( SwTxtFormatInfo &rInf,
    2474             :                                                    SwTxtAttr *pHint ) const
    2475             : {
    2476         165 :     SwFlyCntPortion *pRet = 0;
    2477         165 :     const SwFrm *pFrame = (SwFrm*)pFrm;
    2478             : 
    2479             :     SwFlyInCntFrm *pFly;
    2480         165 :     SwFrmFmt* pFrmFmt = ((SwTxtFlyCnt*)pHint)->GetFlyCnt().GetFrmFmt();
    2481         165 :     if( RES_FLYFRMFMT == pFrmFmt->Which() )
    2482         157 :         pFly = ((SwTxtFlyCnt*)pHint)->GetFlyFrm(pFrame);
    2483             :     else
    2484           8 :         pFly = NULL;
    2485             :     // aBase is the document-global position, from which the new extra portion is placed
    2486             :     // aBase.X() = Offset in in the line after the current position
    2487             :     // aBase.Y() = LineIter.Y() + Ascent of the current position
    2488             : 
    2489             :     long nTmpAscent, nTmpDescent, nFlyAsc, nFlyDesc;
    2490             :     // OD 08.01.2004 #i11859# - use new method <SwLineLayout::MaxAscentDescent(..)>
    2491             :     //SwLinePortion *pPos = pCurr->GetFirstPortion();
    2492             :     //lcl_MaxAscDescent( pPos, nTmpAscent, nTmpDescent, nFlyAsc, nFlyDesc );
    2493         165 :     pCurr->MaxAscentDescent( nTmpAscent, nTmpDescent, nFlyAsc, nFlyDesc );
    2494             : 
    2495             :     // If the ascent of the frame is larger than the ascent of the current position,
    2496             :     // we use this one when calculating the base, or the frame would be positioned
    2497             :     // too much to the top, sliding down after all causing a repaint in an area
    2498             :     // he actually never was in.
    2499         165 :     KSHORT nAscent = 0;
    2500             : 
    2501         165 :     const bool bTxtFrmVertical = GetInfo().GetTxtFrm()->IsVertical();
    2502             : 
    2503         157 :     const bool bUseFlyAscent = pFly && pFly->GetValidPosFlag() &&
    2504             :                                0 != ( bTxtFrmVertical ?
    2505           0 :                                       pFly->GetRefPoint().X() :
    2506         322 :                                       pFly->GetRefPoint().Y() );
    2507             : 
    2508         165 :     if ( bUseFlyAscent )
    2509             :          nAscent = static_cast<sal_uInt16>( Abs( int( bTxtFrmVertical ?
    2510           1 :                                                   pFly->GetRelPos().X() :
    2511           1 :                                                   pFly->GetRelPos().Y() ) ) );
    2512             : 
    2513             :     // Check if be prefer to use the ascent of the last portion:
    2514         331 :     if ( IsQuick() ||
    2515         165 :          !bUseFlyAscent ||
    2516           1 :          nAscent < rInf.GetLast()->GetAscent() )
    2517             :     {
    2518         164 :         nAscent = rInf.GetLast()->GetAscent();
    2519             :     }
    2520           1 :     else if( nAscent > nFlyAsc )
    2521           1 :         nFlyAsc = nAscent;
    2522             : 
    2523         165 :     Point aBase( GetLeftMargin() + rInf.X(), Y() + nAscent );
    2524         165 :     objectpositioning::AsCharFlags nMode = IsQuick() ? AS_CHAR_QUICK : 0;
    2525         165 :     if( GetMulti() && GetMulti()->HasRotation() )
    2526             :     {
    2527           0 :         nMode |= AS_CHAR_ROTATE;
    2528           0 :         if( GetMulti()->IsRevers() )
    2529           0 :             nMode |= AS_CHAR_REVERSE;
    2530             :     }
    2531             : 
    2532         165 :     Point aTmpBase( aBase );
    2533         165 :     if ( GetInfo().GetTxtFrm()->IsVertical() )
    2534           0 :         GetInfo().GetTxtFrm()->SwitchHorizontalToVertical( aTmpBase );
    2535             : 
    2536         165 :     if( pFly )
    2537             :     {
    2538         157 :         pRet = new SwFlyCntPortion( *GetInfo().GetTxtFrm(), pFly, aTmpBase,
    2539         157 :                                     nTmpAscent, nTmpDescent, nFlyAsc, nFlyDesc, nMode );
    2540             :         // We need to make sure that our font is set again in the OutputDevice
    2541             :         // It could be that the FlyInCnt was added anew and GetFlyFrm() would
    2542             :         // in turn cause, that it'd be created anew again.
    2543             :         // This one's frames get formatted right away, which change the font and
    2544             :         // we have a bug (3322).
    2545         157 :         rInf.SelectFont();
    2546         157 :         if( pRet->GetAscent() > nAscent )
    2547             :         {
    2548         111 :             aBase.Y() = Y() + pRet->GetAscent();
    2549         111 :             nMode |= AS_CHAR_ULSPACE;
    2550         111 :             if( !rInf.IsTest() )
    2551             :             {
    2552         111 :                 aTmpBase = aBase;
    2553         111 :                 if ( GetInfo().GetTxtFrm()->IsVertical() )
    2554           0 :                     GetInfo().GetTxtFrm()->SwitchHorizontalToVertical( aTmpBase );
    2555             : 
    2556         111 :                 pRet->SetBase( *rInf.GetTxtFrm(), aTmpBase, nTmpAscent,
    2557         222 :                                nTmpDescent, nFlyAsc, nFlyDesc, nMode );
    2558             :             }
    2559             :         }
    2560             :     }
    2561             :     else
    2562             :     {
    2563           8 :         pRet = new SwFlyCntPortion( *rInf.GetTxtFrm(), (SwDrawContact*)pFrmFmt->FindContactObj(),
    2564           8 :            aTmpBase, nTmpAscent, nTmpDescent, nFlyAsc, nFlyDesc, nMode );
    2565             :     }
    2566         165 :     return pRet;
    2567             : }
    2568             : 
    2569             : namespace {
    2570             :     /*************************************************************************
    2571             :     *                      ::CalcOptRepaint()
    2572             :     *
    2573             :     * calculates and sets optimal repaint offset for the current line
    2574             :     *************************************************************************/
    2575           0 :     long lcl_CalcOptRepaint( SwTxtFormatter &rThis,
    2576             :                          SwLineLayout &rCurr,
    2577             :                          const xub_StrLen nOldLineEnd,
    2578             :                          const std::vector<long> &rFlyStarts )
    2579             :     {
    2580           0 :         SwTxtFormatInfo txtFmtInfo = rThis.GetInfo();
    2581           0 :         if ( txtFmtInfo.GetIdx() < txtFmtInfo.GetReformatStart() )
    2582             :         // the reformat position is behind our new line, that means
    2583             :         // something of our text has moved to the next line
    2584           0 :             return 0;
    2585             : 
    2586           0 :         xub_StrLen nReformat = Min( txtFmtInfo.GetReformatStart(), nOldLineEnd );
    2587             : 
    2588             :         // in case we do not have any fly in our line, our repaint position
    2589             :         // is the changed position - 1
    2590           0 :         if ( rFlyStarts.empty() && ! rCurr.IsFly() )
    2591             :         {
    2592             :             // this is the maximum repaint offset determined during formatting
    2593             :             // for example: the beginning of the first right tab stop
    2594             :             // if this value is 0, this means that we do not have an upper
    2595             :             // limit for the repaint offset
    2596           0 :             const long nFormatRepaint = txtFmtInfo.GetPaintOfst();
    2597             : 
    2598           0 :             if ( nReformat < txtFmtInfo.GetLineStart() + 3 )
    2599           0 :                 return 0;
    2600             : 
    2601             :             // step back two positions for smoother repaint
    2602           0 :             nReformat -= 2;
    2603             : 
    2604             :     #ifndef QUARTZ
    2605             :     #ifndef ENABLE_GRAPHITE
    2606             :             // #i28795#, #i34607#, #i38388#
    2607             :             // step back six(!) more characters for complex scripts
    2608             :             // this is required e.g., for Khmer (thank you, Javier!)
    2609             :             const SwScriptInfo& rSI = txtFmtInfo.GetParaPortion()->GetScriptInfo();
    2610             :             xub_StrLen nMaxContext = 0;
    2611             :             if( ::i18n::ScriptType::COMPLEX == rSI.ScriptType( nReformat ) )
    2612             :                 nMaxContext = 6;
    2613             :     #else
    2614             :             // Some Graphite fonts need context for scripts not marked as complex
    2615             :             static const xub_StrLen nMaxContext = 10;
    2616             :     #endif
    2617             :     #else
    2618             :             // some fonts like Quartz's Zapfino need more context
    2619             :             // TODO: query FontInfo for maximum unicode context
    2620             :             static const xub_StrLen nMaxContext = 8;
    2621             :     #endif
    2622             :             if( nMaxContext > 0 )
    2623             :             {
    2624           0 :                 if ( nReformat > txtFmtInfo.GetLineStart() + nMaxContext )
    2625           0 :                     nReformat = nReformat - nMaxContext;
    2626             :                 else
    2627           0 :                     nReformat = txtFmtInfo.GetLineStart();
    2628             :             }
    2629             : 
    2630             :             // Weird situation: Our line used to end with a hole portion
    2631             :             // and we delete some characters at the end of our line. We have
    2632             :             // to take care for repainting the blanks which are not anymore
    2633             :             // covered by the hole portion
    2634           0 :             while ( nReformat > txtFmtInfo.GetLineStart() &&
    2635           0 :                     CH_BLANK == txtFmtInfo.GetChar( nReformat ) )
    2636           0 :                 --nReformat;
    2637             : 
    2638             :             OSL_ENSURE( nReformat < txtFmtInfo.GetIdx(), "Reformat too small for me!" );
    2639           0 :             SwRect aRect;
    2640             : 
    2641             :             // Note: GetChareRect is not const. It definitely changes the
    2642             :             // bMulti flag. We have to save and resore the old value.
    2643           0 :             bool bOldMulti = txtFmtInfo.IsMulti();
    2644           0 :             rThis.GetCharRect( &aRect, nReformat );
    2645           0 :             txtFmtInfo.SetMulti( bOldMulti );
    2646             : 
    2647           0 :             return nFormatRepaint ? Min( aRect.Left(), nFormatRepaint ) :
    2648           0 :                                     aRect.Left();
    2649             :         }
    2650             :         else
    2651             :         {
    2652             :             // nReformat may be wrong, if something around flys has changed:
    2653             :             // we compare the former and the new fly positions in this line
    2654             :             // if anything has changed, we carefully have to adjust the right
    2655             :             // repaint position
    2656           0 :             long nPOfst = 0;
    2657           0 :             sal_uInt16 nCnt = 0;
    2658           0 :             sal_uInt16 nX = 0;
    2659           0 :             sal_uInt16 nIdx = rThis.GetInfo().GetLineStart();
    2660           0 :             SwLinePortion* pPor = rCurr.GetFirstPortion();
    2661             : 
    2662           0 :             while ( pPor )
    2663             :             {
    2664           0 :                 if ( pPor->IsFlyPortion() )
    2665             :                 {
    2666             :                     // compare start of fly with former start of fly
    2667           0 :                     if (nCnt < rFlyStarts.size() &&
    2668           0 :                         nX == rFlyStarts[ nCnt ] &&
    2669             :                         nIdx < nReformat
    2670             :                     )
    2671             :                         // found fix position, nothing has changed left from nX
    2672           0 :                         nPOfst = nX + pPor->Width();
    2673             :                     else
    2674           0 :                         break;
    2675             : 
    2676           0 :                     nCnt++;
    2677             :                 }
    2678           0 :                 nX = nX + pPor->Width();
    2679           0 :                 nIdx = nIdx + pPor->GetLen();
    2680           0 :                 pPor = pPor->GetPortion();
    2681             :             }
    2682             : 
    2683           0 :             return nPOfst + rThis.GetLeftMargin();
    2684           0 :         }
    2685             :     }
    2686             : 
    2687             :     // Determine if we need to build hidden portions
    2688        1541 :     bool lcl_BuildHiddenPortion( const SwTxtSizeInfo& rInf, xub_StrLen &rPos )
    2689             :     {
    2690             :         // Only if hidden text should not be shown:
    2691             :     //    if ( rInf.GetVsh() && rInf.GetVsh()->GetWin() && rInf.GetOpt().IsShowHiddenChar() )
    2692        1541 :         const bool bShowInDocView = rInf.GetVsh() && rInf.GetVsh()->GetWin() && rInf.GetOpt().IsShowHiddenChar();
    2693        1541 :         const bool bShowForPrinting = rInf.GetOpt().IsShowHiddenChar( sal_True ) && rInf.GetOpt().IsPrinting();
    2694        1541 :         if (bShowInDocView || bShowForPrinting)
    2695           0 :             return false;
    2696             : 
    2697        1541 :         const SwScriptInfo& rSI = rInf.GetParaPortion()->GetScriptInfo();
    2698             :         xub_StrLen nHiddenStart;
    2699             :         xub_StrLen nHiddenEnd;
    2700        1541 :         rSI.GetBoundsOfHiddenRange( rPos, nHiddenStart, nHiddenEnd );
    2701        1541 :         if ( nHiddenEnd )
    2702             :         {
    2703           0 :             rPos = nHiddenEnd;
    2704           0 :             return true;
    2705             :         }
    2706             : 
    2707        1541 :         return false;
    2708             :     }
    2709             : 
    2710             : } //end unnamed namespace
    2711             : 
    2712             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10