LCOV - code coverage report
Current view: top level - sw/source/core/text - pormulti.cxx (source / functions) Hit Total Coverage
Test: commit 0e63ca4fde4e446f346e35849c756a30ca294aab Lines: 829 1211 68.5 %
Date: 2014-04-11 Functions: 29 42 69.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             : #include <deque>
      21             : 
      22             : #include <hintids.hxx>
      23             : 
      24             : #include <com/sun/star/i18n/ScriptType.hpp>
      25             : #include <editeng/twolinesitem.hxx>
      26             : #include <editeng/charrotateitem.hxx>
      27             : #include <vcl/outdev.hxx>
      28             : #include <fmtfld.hxx>
      29             : #include <fldbas.hxx>
      30             : #include <txatbase.hxx>
      31             : #include <fmtruby.hxx>
      32             : #include <txtatr.hxx>
      33             : #include <charfmt.hxx>
      34             : #include <txtinet.hxx>
      35             : #include <fchrfmt.hxx>
      36             : #include <layfrm.hxx>
      37             : #include <SwPortionHandler.hxx>
      38             : #include <pormulti.hxx>
      39             : #include <inftxt.hxx>
      40             : #include <itrpaint.hxx>
      41             : #include <viewopt.hxx>
      42             : #include <itrform2.hxx>
      43             : #include <porfld.hxx>
      44             : #include <porglue.hxx>
      45             : #include <breakit.hxx>
      46             : #include <pagefrm.hxx>
      47             : #include <rowfrm.hxx>
      48             : #include <pagedesc.hxx>
      49             : #include <tgrditem.hxx>
      50             : #include <swtable.hxx>
      51             : #include <fmtfsize.hxx>
      52             : 
      53             : using namespace ::com::sun::star;
      54             : 
      55             : /*--------------------------------------------------
      56             :  *  class SwMultiPortion
      57             :  *
      58             :  * A SwMultiPortion is not a simple portion,
      59             :  * it's a container, which contains almost a SwLineLayoutPortion.
      60             :  * This SwLineLayout could be followed by other textportions via pPortion
      61             :  * and by another SwLineLayout via pNext to realize a doubleline portion.
      62             :  * --------------------------------------------------*/
      63             : 
      64        1078 : SwMultiPortion::~SwMultiPortion()
      65             : {
      66         539 :     delete pFldRest;
      67         539 : }
      68             : 
      69           0 : void SwMultiPortion::Paint( const SwTxtPaintInfo & ) const
      70             : {
      71             :     OSL_FAIL( "Don't try SwMultiPortion::Paint, try SwTxtPainter::PaintMultiPortion" );
      72           0 : }
      73             : 
      74             : /*--------------------------------------------------
      75             :  * Summarize the internal lines to calculate the (external) size.
      76             :  * The internal line has to calculate first.
      77             :  * --------------------------------------------------*/
      78             : 
      79         827 : void SwMultiPortion::CalcSize( SwTxtFormatter& rLine, SwTxtFormatInfo &rInf )
      80             : {
      81         827 :     Width( 0 );
      82         827 :     Height( 0 );
      83         827 :     SetAscent( 0 );
      84         827 :     SetFlyInCntnt( false );
      85         827 :     SwLineLayout *pLay = &GetRoot();
      86        1133 :     do
      87             :     {
      88        1133 :         pLay->CalcLine( rLine, rInf );
      89        1133 :         if( rLine.IsFlyInCntBase() )
      90           0 :             SetFlyInCntnt( true );
      91        1133 :         if( IsRuby() && ( OnTop() == ( pLay == &GetRoot() ) ) )
      92             :         {
      93             :             // An empty phonetic line don't need an ascent or a height.
      94         336 :             if( !pLay->Width() )
      95             :             {
      96          28 :                 pLay->SetAscent( 0 );
      97          28 :                 pLay->Height( 0 );
      98             :             }
      99         336 :             if( OnTop() )
     100         280 :                 SetAscent( GetAscent() + pLay->Height() );
     101             :         }
     102             :         else
     103         797 :             SetAscent( GetAscent() + pLay->GetAscent() );
     104        1133 :         Height( Height() + pLay->Height() );
     105        1133 :         if( Width() < pLay->Width() )
     106         461 :             Width( pLay->Width() );
     107        1133 :         pLay = pLay->GetNext();
     108             :     } while ( pLay );
     109         827 :     if( HasBrackets() )
     110             :     {
     111         104 :         KSHORT nTmp = ((SwDoubleLinePortion*)this)->GetBrackets()->nHeight;
     112         104 :         if( nTmp > Height() )
     113             :         {
     114          16 :             KSHORT nAdd = ( nTmp - Height() ) / 2;
     115          16 :             GetRoot().SetAscent( GetRoot().GetAscent() + nAdd );
     116          16 :             GetRoot().Height( GetRoot().Height() + nAdd );
     117          16 :             Height( nTmp );
     118             :         }
     119         104 :         nTmp = ((SwDoubleLinePortion*)this)->GetBrackets()->nAscent;
     120         104 :         if( nTmp > GetAscent() )
     121          16 :             SetAscent( nTmp );
     122             :     }
     123         827 : }
     124             : 
     125           0 : long SwMultiPortion::CalcSpacing( long , const SwTxtSizeInfo & ) const
     126             : {
     127           0 :     return 0;
     128             : }
     129             : 
     130         177 : bool SwMultiPortion::ChgSpaceAdd( SwLineLayout*, long ) const
     131             : {
     132         177 :     return false;
     133             : }
     134             : 
     135             : /*************************************************************************
     136             :  *              virtual SwMultiPortion::HandlePortion()
     137             :  *************************************************************************/
     138             : 
     139           0 : void SwMultiPortion::HandlePortion( SwPortionHandler& rPH ) const
     140             : {
     141           0 :     rPH.Text( GetLen(), GetWhichPor() );
     142           0 : }
     143             : 
     144             : /*--------------------------------------------------
     145             :  * SwMultiPortion::ActualizeTabulator()
     146             :  * sets the tabulator-flag, if there's any tabulator-portion inside.
     147             :  * --------------------------------------------------*/
     148             : 
     149         529 : void SwMultiPortion::ActualizeTabulator()
     150             : {
     151         529 :     SwLinePortion* pPor = GetRoot().GetFirstPortion();
     152             :     // First line
     153        1062 :     for( bTab1 = bTab2 = false; pPor; pPor = pPor->GetPortion() )
     154         533 :         if( pPor->InTabGrp() )
     155           0 :             SetTab1( true );
     156         529 :     if( GetRoot().GetNext() )
     157             :     {
     158             :         // Second line
     159         168 :         pPor = GetRoot().GetNext()->GetFirstPortion();
     160         255 :         do
     161             :         {
     162         255 :             if( pPor->InTabGrp() )
     163           0 :                 SetTab2( true );
     164         255 :             pPor = pPor->GetPortion();
     165             :         } while ( pPor );
     166             :     }
     167         529 : }
     168             : 
     169             : /*--------------------------------------------------
     170             :  * SwRotatedPortion::SwRotatedPortion(..)
     171             :  * --------------------------------------------------*/
     172             : 
     173         285 : SwRotatedPortion::SwRotatedPortion( const SwMultiCreator& rCreate,
     174         285 :     sal_Int32 nEnd, bool bRTL ) : SwMultiPortion( nEnd )
     175             : {
     176         285 :     const SvxCharRotateItem* pRot = (SvxCharRotateItem*)rCreate.pItem;
     177         285 :     if( !pRot )
     178             :     {
     179           0 :         const SwTxtAttr& rAttr = *rCreate.pAttr;
     180             :         const SfxPoolItem *const pItem =
     181           0 :                 CharFmt::GetItem(rAttr, RES_CHRATR_ROTATE);
     182           0 :         if ( pItem )
     183             :         {
     184           0 :             pRot = static_cast<const SvxCharRotateItem*>(pItem);
     185             :         }
     186             :     }
     187         285 :     if( pRot )
     188             :     {
     189             :         sal_uInt8 nDir;
     190         285 :         if ( bRTL )
     191           0 :             nDir = pRot->IsBottomToTop() ? 3 : 1;
     192             :         else
     193         285 :             nDir = pRot->IsBottomToTop() ? 1 : 3;
     194             : 
     195         285 :         SetDirection( nDir );
     196             :     }
     197         285 : }
     198             : 
     199             : /*---------------------------------------------------
     200             :  * SwBidiPortion::SwBidiPortion(..)
     201             :  * --------------------------------------------------*/
     202             : 
     203          21 : SwBidiPortion::SwBidiPortion( sal_Int32 nEnd, sal_uInt8 nLv )
     204          21 :     : SwMultiPortion( nEnd ), nLevel( nLv )
     205             : {
     206          21 :     SetBidi();
     207             : 
     208          21 :     if ( nLevel % 2 )
     209           4 :         SetDirection( DIR_RIGHT2LEFT );
     210             :     else
     211          17 :         SetDirection( DIR_LEFT2RIGHT );
     212          21 : }
     213             : 
     214           4 : long SwBidiPortion::CalcSpacing( long nSpaceAdd, const SwTxtSizeInfo& rInf ) const
     215             : {
     216           4 :     return HasTabulator() ? 0 : GetSpaceCnt(rInf) * nSpaceAdd / SPACING_PRECISION_FACTOR;
     217             : }
     218             : 
     219           0 : bool SwBidiPortion::ChgSpaceAdd( SwLineLayout* pCurr, long nSpaceAdd ) const
     220             : {
     221           0 :     if( !HasTabulator() && nSpaceAdd > 0 && !pCurr->IsSpaceAdd() )
     222             :     {
     223           0 :         pCurr->CreateSpaceAdd();
     224           0 :         pCurr->SetLLSpaceAdd( nSpaceAdd, 0 );
     225           0 :         return true;
     226             :     }
     227             : 
     228           0 :     return false;
     229             : }
     230             : 
     231           4 : sal_Int32 SwBidiPortion::GetSpaceCnt( const SwTxtSizeInfo &rInf ) const
     232             : {
     233             :     // Calculate number of blanks for justified alignment
     234           4 :     SwLinePortion* pPor = GetRoot().GetFirstPortion();
     235           4 :     sal_Int32 nTmpStart = rInf.GetIdx();
     236           4 :     sal_Int32 nNull = 0;
     237             :     sal_Int32 nBlanks;
     238             : 
     239           8 :     for( nBlanks = 0; pPor; pPor = pPor->GetPortion() )
     240             :     {
     241           4 :         if( pPor->InTxtGrp() )
     242           4 :             nBlanks = nBlanks + ((SwTxtPortion*)pPor)->GetSpaceCnt( rInf, nNull );
     243           0 :         else if ( pPor->IsMultiPortion() &&
     244           0 :                  ((SwMultiPortion*)pPor)->IsBidi() )
     245           0 :             nBlanks = nBlanks + ((SwBidiPortion*)pPor)->GetSpaceCnt( rInf );
     246             : 
     247           4 :         ((SwTxtSizeInfo &)rInf).SetIdx( rInf.GetIdx() + pPor->GetLen() );
     248             :     }
     249           4 :     ((SwTxtSizeInfo &)rInf).SetIdx( nTmpStart );
     250           4 :     return nBlanks;
     251             : }
     252             : 
     253             : /*--------------------------------------------------
     254             :  * SwDoubleLinePortion::SwDoubleLinePortion(..)
     255             :  * This constructor is for the continuation of a doubleline portion
     256             :  * in the next line.
     257             :  * It takes the same brackets and if the original has no content except
     258             :  * brackets, these will be deleted.
     259             :  * --------------------------------------------------*/
     260             : 
     261           0 : SwDoubleLinePortion::SwDoubleLinePortion(SwDoubleLinePortion& rDouble, sal_Int32 nEnd)
     262             :     : SwMultiPortion(nEnd)
     263             :     , pBracket(0)
     264             :     , nLineDiff(0)
     265             :     , nBlank1(0)
     266           0 :     , nBlank2(0)
     267             : {
     268           0 :     SetDirection( rDouble.GetDirection() );
     269           0 :     SetDouble();
     270           0 :     if( rDouble.GetBrackets() )
     271             :     {
     272           0 :         SetBrackets( rDouble );
     273             :         // An empty multiportion needs no brackets.
     274             :         // Notice: GetLen() might be zero, if the multiportion contains
     275             :         // the second part of a field and the width might be zero, if
     276             :         // it contains a note only. In this cases the brackets are okay.
     277             :         // But if the length and the width are both zero, the portion
     278             :         // is really empty.
     279           0 :         if( rDouble.Width() ==  rDouble.BracketWidth() )
     280           0 :             rDouble.ClearBrackets();
     281             :     }
     282           0 : }
     283             : 
     284             : /*--------------------------------------------------
     285             :  * SwDoubleLinePortion::SwDoubleLinePortion(..)
     286             :  * This constructor uses the textattribut to get the right brackets.
     287             :  * The textattribut could be a 2-line-attribute or a character- or
     288             :  * internetstyle, which contains the 2-line-attribute.
     289             :  * --------------------------------------------------*/
     290             : 
     291          10 : SwDoubleLinePortion::SwDoubleLinePortion(const SwMultiCreator& rCreate, sal_Int32 nEnd)
     292             :     : SwMultiPortion(nEnd)
     293             :     , pBracket(new SwBracket())
     294             :     , nLineDiff(0)
     295             :     , nBlank1(0)
     296          10 :     , nBlank2(0)
     297             : {
     298          10 :     SetDouble();
     299          10 :     const SvxTwoLinesItem* pTwo = (SvxTwoLinesItem*)rCreate.pItem;
     300          10 :     if( pTwo )
     301           0 :         pBracket->nStart = 0;
     302             :     else
     303             :     {
     304          10 :         const SwTxtAttr& rAttr = *rCreate.pAttr;
     305          10 :         pBracket->nStart = *rAttr.GetStart();
     306             : 
     307             :         const SfxPoolItem * const pItem =
     308          10 :             CharFmt::GetItem( rAttr, RES_CHRATR_TWO_LINES );
     309          10 :         if ( pItem )
     310             :         {
     311          10 :             pTwo = static_cast<const SvxTwoLinesItem*>(pItem);
     312             :         }
     313             :     }
     314          10 :     if( pTwo )
     315             :     {
     316          10 :         pBracket->cPre = pTwo->GetStartBracket();
     317          10 :         pBracket->cPost = pTwo->GetEndBracket();
     318             :     }
     319             :     else
     320             :     {
     321           0 :         pBracket->cPre = 0;
     322           0 :         pBracket->cPost = 0;
     323             :     }
     324          10 :     sal_uInt8 nTmp = SW_SCRIPTS;
     325          10 :     if( pBracket->cPre > 255 )
     326             :     {
     327           0 :         OUString aTxt = OUString(pBracket->cPre);
     328           0 :         nTmp = SwScriptInfo::WhichFont( 0, &aTxt, 0 );
     329             :     }
     330          10 :     pBracket->nPreScript = nTmp;
     331          10 :     nTmp = SW_SCRIPTS;
     332          10 :     if( pBracket->cPost > 255 )
     333             :     {
     334           0 :         OUString aTxt = OUString(pBracket->cPost);
     335           0 :         nTmp = SwScriptInfo::WhichFont( 0, &aTxt, 0 );
     336             :     }
     337          10 :     pBracket->nPostScript = nTmp;
     338             : 
     339          10 :     if( !pBracket->cPre && !pBracket->cPost )
     340             :     {
     341           2 :         delete pBracket;
     342           2 :         pBracket = 0;
     343             :     }
     344             : 
     345             :     // double line portions have the same direction as the frame directions
     346          10 :     if ( rCreate.nLevel % 2 )
     347           0 :         SetDirection( DIR_RIGHT2LEFT );
     348             :     else
     349          10 :         SetDirection( DIR_LEFT2RIGHT );
     350          10 : }
     351             : 
     352             : /*--------------------------------------------------
     353             :  * SwMultiPortion::PaintBracket paints the wished bracket,
     354             :  * if the multiportion has surrounding brackets.
     355             :  * The X-position of the SwTxtPaintInfo will be modified:
     356             :  * the open bracket sets position behind itself,
     357             :  * the close bracket in front of itself.
     358             :  * --------------------------------------------------*/
     359             : 
     360          22 : void SwDoubleLinePortion::PaintBracket( SwTxtPaintInfo &rInf,
     361             :                                         long nSpaceAdd,
     362             :                                         bool bOpen ) const
     363             : {
     364          22 :     sal_Unicode cCh = bOpen ? pBracket->cPre : pBracket->cPost;
     365          22 :     if( !cCh )
     366           4 :         return;
     367          20 :     KSHORT nChWidth = bOpen ? PreWidth() : PostWidth();
     368          20 :     if( !nChWidth )
     369           0 :         return;
     370          20 :     if( !bOpen )
     371           9 :         rInf.X( rInf.X() + Width() - PostWidth() +
     372           9 :             ( nSpaceAdd > 0 ? CalcSpacing( nSpaceAdd, rInf ) : 0 ) );
     373             : 
     374          20 :     SwBlankPortion aBlank( cCh, true );
     375          20 :     aBlank.SetAscent( pBracket->nAscent );
     376          20 :     aBlank.Width( nChWidth );
     377          20 :     aBlank.Height( pBracket->nHeight );
     378             :     {
     379          20 :         SwFont* pTmpFnt = new SwFont( *rInf.GetFont() );
     380          20 :         sal_uInt8 nAct = bOpen ? pBracket->nPreScript : pBracket->nPostScript;
     381          20 :         if( SW_SCRIPTS > nAct )
     382           0 :             pTmpFnt->SetActual( nAct );
     383          20 :         pTmpFnt->SetProportion( 100 );
     384          20 :         SwFontSave aSave( rInf, pTmpFnt );
     385          20 :         aBlank.Paint( rInf );
     386          20 :         delete pTmpFnt;
     387             :     }
     388          20 :     if( bOpen )
     389          11 :         rInf.X( rInf.X() + PreWidth() );
     390             : }
     391             : 
     392             : /*--------------------------------------------------
     393             :  * SwDoubleLinePortion::SetBrackets creates the bracket-structur
     394             :  * and fills it, if not both characters are 0x00.
     395             :  * --------------------------------------------------*/
     396             : 
     397           0 : void SwDoubleLinePortion::SetBrackets( const SwDoubleLinePortion& rDouble )
     398             : {
     399           0 :     if( rDouble.pBracket )
     400             :     {
     401           0 :         pBracket = new SwBracket;
     402           0 :         pBracket->cPre = rDouble.pBracket->cPre;
     403           0 :         pBracket->cPost = rDouble.pBracket->cPost;
     404           0 :         pBracket->nPreScript = rDouble.pBracket->nPreScript;
     405           0 :         pBracket->nPostScript = rDouble.pBracket->nPostScript;
     406           0 :         pBracket->nStart = rDouble.pBracket->nStart;
     407             :     }
     408           0 : }
     409             : 
     410             : /*--------------------------------------------------
     411             :  * SwDoubleLinePortion::FormatBrackets
     412             :  * calculates the size of the brackets => pBracket,
     413             :  * reduces the nMaxWidth-parameter ( minus bracket-width )
     414             :  * and moves the rInf-x-position behind the opening bracket.
     415             :  * --------------------------------------------------*/
     416             : 
     417           8 : void SwDoubleLinePortion::FormatBrackets( SwTxtFormatInfo &rInf, SwTwips& nMaxWidth )
     418             : {
     419           8 :     nMaxWidth -= rInf.X();
     420           8 :     SwFont* pTmpFnt = new SwFont( *rInf.GetFont() );
     421           8 :     pTmpFnt->SetProportion( 100 );
     422           8 :     pBracket->nAscent = 0;
     423           8 :     pBracket->nHeight = 0;
     424           8 :     if( pBracket->cPre )
     425             :     {
     426           8 :         OUString aStr( pBracket->cPre );
     427           8 :         sal_uInt8 nActualScr = pTmpFnt->GetActual();
     428           8 :         if( SW_SCRIPTS > pBracket->nPreScript )
     429           0 :             pTmpFnt->SetActual( pBracket->nPreScript );
     430          16 :         SwFontSave aSave( rInf, pTmpFnt );
     431           8 :         SwPosSize aSize = rInf.GetTxtSize( aStr );
     432           8 :         pBracket->nAscent = rInf.GetAscent();
     433           8 :         pBracket->nHeight = aSize.Height();
     434           8 :         pTmpFnt->SetActual( nActualScr );
     435           8 :         if( nMaxWidth > aSize.Width() )
     436             :         {
     437           8 :             pBracket->nPreWidth = aSize.Width();
     438           8 :             nMaxWidth -= aSize.Width();
     439           8 :             rInf.X( rInf.X() + aSize.Width() );
     440             :         }
     441             :         else
     442             :         {
     443           0 :             pBracket->nPreWidth = 0;
     444           0 :             nMaxWidth = 0;
     445           8 :         }
     446             :     }
     447             :     else
     448           0 :         pBracket->nPreWidth = 0;
     449           8 :     if( pBracket->cPost )
     450             :     {
     451           6 :         OUString aStr( pBracket->cPost );
     452           6 :         if( SW_SCRIPTS > pBracket->nPostScript )
     453           0 :             pTmpFnt->SetActual( pBracket->nPostScript );
     454          12 :         SwFontSave aSave( rInf, pTmpFnt );
     455           6 :         SwPosSize aSize = rInf.GetTxtSize( aStr );
     456           6 :         KSHORT nTmpAsc = rInf.GetAscent();
     457           6 :         if( nTmpAsc > pBracket->nAscent )
     458             :         {
     459           0 :             pBracket->nHeight += nTmpAsc - pBracket->nAscent;
     460           0 :             pBracket->nAscent = nTmpAsc;
     461             :         }
     462           6 :         if( aSize.Height() > pBracket->nHeight )
     463           0 :             pBracket->nHeight = aSize.Height();
     464           6 :         if( nMaxWidth > aSize.Width() )
     465             :         {
     466           6 :             pBracket->nPostWidth = aSize.Width();
     467           6 :             nMaxWidth -= aSize.Width();
     468             :         }
     469             :         else
     470             :         {
     471           0 :             pBracket->nPostWidth = 0;
     472           0 :             nMaxWidth = 0;
     473           6 :         }
     474             :     }
     475             :     else
     476           2 :         pBracket->nPostWidth = 0;
     477           8 :     nMaxWidth += rInf.X();
     478           8 :     delete(pTmpFnt);
     479           8 : }
     480             : 
     481             : /*--------------------------------------------------
     482             :  * SwDoubleLinePortion::CalcBlanks
     483             :  * calculates the number of blanks in each line and
     484             :  * the difference of the width of the two lines.
     485             :  * These results are used from the text adjustment.
     486             :  * --------------------------------------------------*/
     487             : 
     488          10 : void SwDoubleLinePortion::CalcBlanks( SwTxtFormatInfo &rInf )
     489             : {
     490          10 :     SwLinePortion* pPor = GetRoot().GetFirstPortion();
     491          10 :     sal_Int32 nNull = 0;
     492          10 :     sal_Int32 nStart = rInf.GetIdx();
     493          10 :     SetTab1( false );
     494          10 :     SetTab2( false );
     495          20 :     for( nBlank1 = 0; pPor; pPor = pPor->GetPortion() )
     496             :     {
     497          10 :         if( pPor->InTxtGrp() )
     498          10 :             nBlank1 = nBlank1 + ((SwTxtPortion*)pPor)->GetSpaceCnt( rInf, nNull );
     499          10 :         rInf.SetIdx( rInf.GetIdx() + pPor->GetLen() );
     500          10 :         if( pPor->InTabGrp() )
     501           0 :             SetTab1( true );
     502             :     }
     503          10 :     nLineDiff = GetRoot().Width();
     504          10 :     if( GetRoot().GetNext() )
     505             :     {
     506          10 :         pPor = GetRoot().GetNext()->GetFirstPortion();
     507          10 :         nLineDiff -= GetRoot().GetNext()->Width();
     508             :     }
     509          20 :     for( nBlank2 = 0; pPor; pPor = pPor->GetPortion() )
     510             :     {
     511          10 :         if( pPor->InTxtGrp() )
     512          10 :             nBlank2 = nBlank2 + ((SwTxtPortion*)pPor)->GetSpaceCnt( rInf, nNull );
     513          10 :         rInf.SetIdx( rInf.GetIdx() + pPor->GetLen() );
     514          10 :         if( pPor->InTabGrp() )
     515           0 :             SetTab2( true );
     516             :     }
     517          10 :     rInf.SetIdx( nStart );
     518          10 : }
     519             : 
     520           0 : long SwDoubleLinePortion::CalcSpacing( long nSpaceAdd, const SwTxtSizeInfo & ) const
     521             : {
     522           0 :     return HasTabulator() ? 0 : GetSpaceCnt() * nSpaceAdd / SPACING_PRECISION_FACTOR;
     523             : }
     524             : 
     525             : /*--------------------------------------------------
     526             :  * SwDoubleLinePortion::ChangeSpaceAdd(..)
     527             :  * merges the spaces for text adjustment from the inner and outer part.
     528             :  * Inside the doubleline portion the wider line has no spaceadd-array, the
     529             :  * smaller line has such an array to reach width of the wider line.
     530             :  * If the surrounding line has text adjustment and the doubleline portion
     531             :  * contains no tabulator, it is necessary to create/manipulate the inner
     532             :  * space arrays.
     533             :  * --------------------------------------------------*/
     534             : 
     535          39 : bool SwDoubleLinePortion::ChgSpaceAdd( SwLineLayout* pCurr,
     536             :                                            long nSpaceAdd ) const
     537             : {
     538          39 :     bool bRet = false;
     539          39 :     if( !HasTabulator() && nSpaceAdd > 0 )
     540             :     {
     541           0 :         if( !pCurr->IsSpaceAdd() )
     542             :         {
     543             :             // The wider line gets the spaceadd from the surrounding line direct
     544           0 :             pCurr->CreateSpaceAdd();
     545           0 :             pCurr->SetLLSpaceAdd( nSpaceAdd, 0 );
     546           0 :             bRet = true;
     547             :         }
     548             :         else
     549             :         {
     550           0 :             sal_Int32 nMyBlank = GetSmallerSpaceCnt();
     551           0 :             sal_Int32 nOther = GetSpaceCnt();
     552           0 :             SwTwips nMultiSpace = pCurr->GetLLSpaceAdd( 0 ) * nMyBlank + nOther * nSpaceAdd;
     553             : 
     554           0 :             if( nMyBlank )
     555           0 :                 nMultiSpace /= nMyBlank;
     556             : 
     557           0 :             if( nMultiSpace < KSHRT_MAX * SPACING_PRECISION_FACTOR )
     558             :             {
     559             : //                pCurr->SetLLSpaceAdd( nMultiSpace, 0 );
     560             :                 // #i65711# SetLLSpaceAdd replaces the first value,
     561             :                 // instead we want to insert a new first value:
     562           0 :                 std::vector<long>* pVec = pCurr->GetpLLSpaceAdd();
     563           0 :                 pVec->insert( pVec->begin(), nMultiSpace );
     564           0 :                 bRet = true;
     565             :             }
     566             :         }
     567             :     }
     568          39 :     return bRet;
     569             : }
     570             : /*--------------------------------------------------
     571             :  * SwDoubleLinePortion::ResetSpaceAdd(..)
     572             :  * cancels the manipulation from SwDoubleLinePortion::ChangeSpaceAdd(..)
     573             :  * --------------------------------------------------*/
     574             : 
     575           0 : void SwDoubleLinePortion::ResetSpaceAdd( SwLineLayout* pCurr )
     576             : {
     577           0 :     pCurr->RemoveFirstLLSpaceAdd();;
     578           0 :     if( !pCurr->GetLLSpaceAddCount() )
     579           0 :         pCurr->FinishSpaceAdd();
     580           0 : }
     581             : 
     582          30 : SwDoubleLinePortion::~SwDoubleLinePortion()
     583             : {
     584          10 :     delete pBracket;
     585          20 : }
     586             : 
     587             : /*--------------------------------------------------
     588             :  * SwRubyPortion::SwRubyPortion(..)
     589             :  * constructs a ruby portion, i.e. an additional text is displayed
     590             :  * beside the main text, e.g. phonetic characters.
     591             :  * --------------------------------------------------*/
     592             : 
     593           0 : SwRubyPortion::SwRubyPortion( const SwRubyPortion& rRuby, sal_Int32 nEnd ) :
     594             :     SwMultiPortion( nEnd ),
     595           0 :     nRubyOffset( rRuby.GetRubyOffset() ),
     596           0 :     nAdjustment( rRuby.GetAdjustment() )
     597             : {
     598           0 :     SetDirection( rRuby.GetDirection() ),
     599           0 :     SetTop( rRuby.OnTop() );
     600           0 :     SetRuby();
     601           0 : }
     602             : 
     603             : /*--------------------------------------------------
     604             :  * SwRubyPortion::SwRubyPortion(..)
     605             :  * constructs a ruby portion, i.e. an additional text is displayed
     606             :  * beside the main text, e.g. phonetic characters.
     607             :  * --------------------------------------------------*/
     608             : 
     609         168 : SwRubyPortion::SwRubyPortion( const SwMultiCreator& rCreate, const SwFont& rFnt,
     610             :                               const IDocumentSettingAccess& rIDocumentSettingAccess,
     611             :                               sal_Int32 nEnd, sal_Int32 nOffs,
     612             :                               const bool* pForceRubyPos )
     613         168 :      : SwMultiPortion( nEnd )
     614             : {
     615         168 :     SetRuby();
     616             :     OSL_ENSURE( SW_MC_RUBY == rCreate.nId, "Ruby expected" );
     617             :     OSL_ENSURE( RES_TXTATR_CJK_RUBY == rCreate.pAttr->Which(), "Wrong attribute" );
     618         168 :     const SwFmtRuby& rRuby = rCreate.pAttr->GetRuby();
     619         168 :     nAdjustment = rRuby.GetAdjustment();
     620         168 :     nRubyOffset = nOffs;
     621             : 
     622             :     // in grid mode we force the ruby text to the upper or lower line
     623         168 :     if ( pForceRubyPos )
     624           0 :         SetTop( *pForceRubyPos );
     625             :     else
     626         168 :         SetTop( ! rRuby.GetPosition() );
     627             : 
     628         168 :     const SwCharFmt* pFmt = ((SwTxtRuby*)rCreate.pAttr)->GetCharFmt();
     629             :     SwFont *pRubyFont;
     630         168 :     if( pFmt )
     631             :     {
     632         168 :         const SwAttrSet& rSet = pFmt->GetAttrSet();
     633         168 :          pRubyFont = new SwFont( rFnt );
     634         168 :         pRubyFont->SetDiffFnt( &rSet, &rIDocumentSettingAccess );
     635             : 
     636             :         // we do not allow a vertical font for the ruby text
     637         168 :         pRubyFont->SetVertical( rFnt.GetOrientation() );
     638             :     }
     639             :     else
     640           0 :         pRubyFont = NULL;
     641             : 
     642         168 :     OUString aStr = rRuby.GetText().copy( nOffs );
     643         168 :     SwFldPortion *pFld = new SwFldPortion( aStr, pRubyFont );
     644         168 :     pFld->SetNextOffset( nOffs );
     645         168 :     pFld->SetFollow( true );
     646             : 
     647         168 :     if( OnTop() )
     648         140 :         GetRoot().SetPortion( pFld );
     649             :     else
     650             :     {
     651          28 :         GetRoot().SetNext( new SwLineLayout() );
     652          28 :         GetRoot().GetNext()->SetPortion( pFld );
     653             :     }
     654             : 
     655             :     // ruby portions have the same direction as the frame directions
     656         168 :     if ( rCreate.nLevel % 2 )
     657             :     {
     658             :         // switch right and left ruby adjustment in rtl environment
     659           0 :         if ( 0 == nAdjustment )
     660           0 :             nAdjustment = 2;
     661           0 :         else if ( 2 == nAdjustment )
     662           0 :             nAdjustment = 0;
     663             : 
     664           0 :         SetDirection( DIR_RIGHT2LEFT );
     665             :     }
     666             :     else
     667         168 :         SetDirection( DIR_LEFT2RIGHT );
     668         168 : }
     669             : 
     670             : /*--------------------------------------------------
     671             :  * SwRubyPortion::_Adjust(..)
     672             :  * In ruby portion there are different alignments for
     673             :  * the ruby text and the main text.
     674             :  * Left, right, centered and two possibilities of block adjustment
     675             :  * The block adjustment is realized by spacing between the characteres,
     676             :  * either with a half space or no space in front of the first letter and
     677             :  * a half space at the end of the last letter.
     678             :  * Notice: the smaller line will be manipulated, normally it's the ruby line,
     679             :  * but it could be the main text, too.
     680             :  * If there is a tabulator in smaller line, no adjustment is possible.
     681             :  * --------------------------------------------------*/
     682             : 
     683          32 : void SwRubyPortion::_Adjust( SwTxtFormatInfo &rInf )
     684             : {
     685          32 :     SwTwips nLineDiff = GetRoot().Width() - GetRoot().GetNext()->Width();
     686          32 :     sal_Int32 nOldIdx = rInf.GetIdx();
     687          32 :     if( !nLineDiff )
     688           0 :         return;
     689             :     SwLineLayout *pCurr;
     690          32 :     if( nLineDiff < 0 )
     691             :     {   // The first line has to be adjusted.
     692           4 :         if( GetTab1() )
     693           0 :             return;
     694           4 :         pCurr = &GetRoot();
     695           4 :         nLineDiff = -nLineDiff;
     696             :     }
     697             :     else
     698             :     {   // The second line has to be adjusted.
     699          28 :         if( GetTab2() )
     700           0 :             return;
     701          28 :         pCurr = GetRoot().GetNext();
     702          28 :         rInf.SetIdx( nOldIdx + GetRoot().GetLen() );
     703             :     }
     704          32 :     KSHORT nLeft = 0;   // the space in front of the first letter
     705          32 :     KSHORT nRight = 0;  // the space at the end of the last letter
     706          32 :     sal_uInt16 nSub = 0;
     707          32 :     switch ( nAdjustment )
     708             :     {
     709          32 :         case 1: nRight = static_cast<sal_uInt16>(nLineDiff / 2);    // no break
     710          32 :         case 2: nLeft  = static_cast<sal_uInt16>(nLineDiff - nRight); break;
     711           0 :         case 3: nSub   = 1; // no break
     712             :         case 4:
     713             :         {
     714           0 :             sal_Int32 nCharCnt = 0;
     715             :             SwLinePortion *pPor;
     716           0 :             for( pPor = pCurr->GetFirstPortion(); pPor; pPor = pPor->GetPortion() )
     717             :             {
     718           0 :                 if( pPor->InTxtGrp() )
     719           0 :                     ((SwTxtPortion*)pPor)->GetSpaceCnt( rInf, nCharCnt );
     720           0 :                 rInf.SetIdx( rInf.GetIdx() + pPor->GetLen() );
     721             :             }
     722           0 :             if( nCharCnt > nSub )
     723             :             {
     724           0 :                 SwTwips nCalc = nLineDiff / ( nCharCnt - nSub );
     725             :                 short nTmp;
     726           0 :                 if( nCalc < SHRT_MAX )
     727           0 :                     nTmp = -short(nCalc);
     728             :                 else
     729           0 :                     nTmp = SHRT_MIN;
     730             : 
     731           0 :                 pCurr->CreateSpaceAdd( SPACING_PRECISION_FACTOR * nTmp );
     732           0 :                 nLineDiff -= nCalc * ( nCharCnt - 1 );
     733             :             }
     734           0 :             if( nLineDiff > 1 )
     735             :             {
     736           0 :                 nRight = static_cast<sal_uInt16>(nLineDiff / 2);
     737           0 :                 nLeft  = static_cast<sal_uInt16>(nLineDiff - nRight);
     738             :             }
     739           0 :             break;
     740             :         }
     741             :         default: OSL_FAIL( "New ruby adjustment" );
     742             :     }
     743          32 :     if( nLeft || nRight )
     744             :     {
     745          32 :         if( !pCurr->GetPortion() )
     746           0 :             pCurr->SetPortion( new SwTxtPortion( *pCurr ) );
     747          32 :         if( nLeft )
     748             :         {
     749          32 :             SwMarginPortion *pMarg = new SwMarginPortion( 0 );
     750          32 :             pMarg->AddPrtWidth( nLeft );
     751          32 :             pMarg->SetPortion( pCurr->GetPortion() );
     752          32 :             pCurr->SetPortion( pMarg );
     753             :         }
     754          32 :         if( nRight )
     755             :         {
     756          32 :             SwMarginPortion *pMarg = new SwMarginPortion( 0 );
     757          32 :             pMarg->AddPrtWidth( nRight );
     758          32 :             pCurr->FindLastPortion()->Append( pMarg );
     759             :         }
     760             :     }
     761             : 
     762          32 :     pCurr->Width( Width() );
     763          32 :     rInf.SetIdx( nOldIdx );
     764             : }
     765             : 
     766             : /*--------------------------------------------------
     767             :  * CalcRubyOffset()
     768             :  * has to change the nRubyOffset, if there's a fieldportion
     769             :  * in the phonetic line.
     770             :  * The nRubyOffset is the position in the rubystring, where the
     771             :  * next SwRubyPortion has start the displaying of the phonetics.
     772             :  * --------------------------------------------------*/
     773             : 
     774         168 : void SwRubyPortion::CalcRubyOffset()
     775             : {
     776         168 :     const SwLineLayout *pCurr = &GetRoot();
     777         168 :     if( !OnTop() )
     778             :     {
     779          28 :         pCurr = pCurr->GetNext();
     780          28 :         if( !pCurr )
     781         168 :             return;
     782             :     }
     783         168 :     const SwLinePortion *pPor = pCurr->GetFirstPortion();
     784         168 :     const SwFldPortion *pFld = NULL;
     785         568 :     while( pPor )
     786             :     {
     787         232 :         if( pPor->InFldGrp() )
     788         168 :             pFld = (SwFldPortion*)pPor;
     789         232 :         pPor = pPor->GetPortion();
     790             :     }
     791         168 :     if( pFld )
     792             :     {
     793         168 :         if( pFld->HasFollow() )
     794           0 :             nRubyOffset = pFld->GetNextOffset();
     795             :         else
     796         168 :             nRubyOffset = COMPLETE_STRING;
     797             :     }
     798             : }
     799             : 
     800             : /*--------------------------------------------------
     801             :  * SwTxtSizeInfo::GetMultiCreator(..)
     802             :  * If we (e.g. the position rPos) are inside a two-line-attribute or
     803             :  * a ruby-attribute, the attribute will be returned in a SwMultiCreator-struct,
     804             :  * otherwise the function returns zero.
     805             :  * The rPos parameter is set to the end of the multiportion,
     806             :  * normally this is the end of the attribute,
     807             :  * but sometimes it is the start of another attribute, which finished or
     808             :  * interrupts the first attribute.
     809             :  * E.g. a ruby portion interrupts a 2-line-attribute, a 2-line-attribute
     810             :  * with different brackets interrupts another 2-line-attribute.
     811             :  * --------------------------------------------------*/
     812             : 
     813             : /*--------------------------------------------------
     814             :  * lcl_Has2Lines(..)
     815             :  * is a little help function for GetMultiCreator(..)
     816             :  * It extracts the 2-line-format from a 2-line-attribute or a character style.
     817             :  * The rValue is set to true, if the 2-line-attribute's value is set and
     818             :  * no 2-line-format reference is passed. If there is a 2-line-format reference,
     819             :  * then the rValue is set only, if the 2-line-attribute's value is set _and_
     820             :  * the 2-line-formats has the same brackets.
     821             :  * --------------------------------------------------*/
     822             : 
     823       42158 : static bool lcl_Has2Lines( const SwTxtAttr& rAttr, const SvxTwoLinesItem* &rpRef,
     824             :     bool &rValue )
     825             : {
     826       42158 :     const SfxPoolItem* pItem = CharFmt::GetItem( rAttr, RES_CHRATR_TWO_LINES );
     827       42158 :     if( pItem )
     828             :     {
     829          54 :         rValue = ((SvxTwoLinesItem*)pItem)->GetValue();
     830          54 :         if( !rpRef )
     831          44 :             rpRef = (SvxTwoLinesItem*)pItem;
     832          20 :         else if( ((SvxTwoLinesItem*)pItem)->GetEndBracket() !=
     833          20 :                     rpRef->GetEndBracket() ||
     834          10 :                     ((SvxTwoLinesItem*)pItem)->GetStartBracket() !=
     835          10 :                     rpRef->GetStartBracket() )
     836           0 :             rValue = false;
     837          54 :         return true;
     838             :     }
     839       42104 :     return false;
     840             : }
     841             : 
     842             : /*--------------------------------------------------
     843             :  * lcl_HasRotation(..)
     844             :  * is a little help function for GetMultiCreator(..)
     845             :  * It extracts the charrotation from a charrotate-attribute or a character style.
     846             :  * The rValue is set to true, if the charrotate-attribute's value is set and
     847             :  * no charrotate-format reference is passed.
     848             :  * If there is a charrotate-format reference, then the rValue is set only,
     849             :  * if the charrotate-attribute's value is set _and_ identical
     850             :  * to the charrotate-format's value.
     851             :  * --------------------------------------------------*/
     852             : 
     853       42138 : static bool lcl_HasRotation( const SwTxtAttr& rAttr,
     854             :     const SvxCharRotateItem* &rpRef, bool &rValue )
     855             : {
     856       42138 :     const SfxPoolItem* pItem = CharFmt::GetItem( rAttr, RES_CHRATR_ROTATE );
     857       42138 :     if ( pItem )
     858             :     {
     859          26 :         rValue = ((SvxCharRotateItem*)pItem)->GetValue();
     860          26 :         if( !rpRef )
     861          26 :             rpRef = (SvxCharRotateItem*)pItem;
     862           0 :         else if( ((SvxCharRotateItem*)pItem)->GetValue() !=
     863           0 :                     rpRef->GetValue() )
     864           0 :             rValue = false;
     865          26 :         return true;
     866             :     }
     867             : 
     868       42112 :     return false;
     869             : }
     870             : 
     871      100352 : SwMultiCreator* SwTxtSizeInfo::GetMultiCreator( sal_Int32 &rPos,
     872             :                                                 SwMultiPortion* pMulti ) const
     873             : {
     874      100352 :     SwScriptInfo& rSI = ((SwParaPortion*)GetParaPortion())->GetScriptInfo();
     875             : 
     876             :     // get the last embedding level
     877             :     sal_uInt8 nCurrLevel;
     878      100352 :     if ( pMulti )
     879             :     {
     880             :         OSL_ENSURE( pMulti->IsBidi(), "Nested MultiPortion is not BidiPortion" );
     881             :         // level associated with bidi-portion;
     882          38 :         nCurrLevel = ((SwBidiPortion*)pMulti)->GetLevel();
     883             :     }
     884             :     else
     885             :         // no nested bidi portion required
     886      100314 :         nCurrLevel = GetTxtFrm()->IsRightToLeft() ? 1 : 0;
     887             : 
     888             :     // check if there is a field at rPos:
     889      100352 :     sal_uInt8 nNextLevel = nCurrLevel;
     890      100352 :     bool bFldBidi = false;
     891             : 
     892      100352 :     if ( rPos < GetTxt().getLength() && CH_TXTATR_BREAKWORD == GetChar( rPos ) )
     893             :     {
     894        2830 :         bFldBidi = true;
     895             :     }
     896             :     else
     897       97522 :         nNextLevel = rSI.DirType( rPos );
     898             : 
     899      100352 :     if ( GetTxt().getLength() != rPos && nNextLevel > nCurrLevel )
     900             :     {
     901          17 :         rPos = bFldBidi ? rPos + 1 : rSI.NextDirChg( rPos, &nCurrLevel );
     902          17 :         if ( COMPLETE_STRING == rPos )
     903           0 :             return NULL;
     904          17 :         SwMultiCreator *pRet = new SwMultiCreator;
     905          17 :         pRet->pItem = NULL;
     906          17 :         pRet->pAttr = NULL;
     907          17 :         pRet->nId = SW_MC_BIDI;
     908          17 :         pRet->nLevel = nCurrLevel + 1;
     909          17 :         return pRet;
     910             :     }
     911             : 
     912             :     // a bidi portion can only contain other bidi portions
     913      100335 :     if ( pMulti )
     914          38 :         return NULL;
     915             : 
     916      100297 :     const SvxCharRotateItem* pRotate = NULL;
     917             :     const SfxPoolItem* pRotItem;
     918      200594 :     if( SFX_ITEM_SET == m_pFrm->GetTxtNode()->GetSwAttrSet().
     919      100756 :         GetItemState( RES_CHRATR_ROTATE, true, &pRotItem ) &&
     920         459 :         ((SvxCharRotateItem*)pRotItem)->GetValue() )
     921         441 :         pRotate = (SvxCharRotateItem*)pRotItem;
     922             :     else
     923       99856 :         pRotItem = NULL;
     924      100297 :     const SvxTwoLinesItem* p2Lines = NULL;
     925      100297 :     const SwTxtNode *pLclTxtNode = m_pFrm->GetTxtNode();
     926      100297 :     if( !pLclTxtNode )
     927           0 :         return NULL;
     928             :     const SfxPoolItem* pItem;
     929      200594 :     if( SFX_ITEM_SET == pLclTxtNode->GetSwAttrSet().
     930      100571 :         GetItemState( RES_CHRATR_TWO_LINES, true, &pItem ) &&
     931         274 :         ((SvxTwoLinesItem*)pItem)->GetValue() )
     932         256 :         p2Lines = (SvxTwoLinesItem*)pItem;
     933             :     else
     934      100041 :         pItem = NULL;
     935             : 
     936      100297 :     const SwpHints *pHints = pLclTxtNode->GetpSwpHints();
     937      100297 :     if( !pHints && !p2Lines && !pRotate )
     938       38826 :         return NULL;
     939       61471 :     const SwTxtAttr *pRuby = NULL;
     940       61471 :     bool bTwo = false;
     941       61471 :     bool bRot = false;
     942       61471 :     sal_uInt16 n2Lines = USHRT_MAX;
     943       61471 :     sal_uInt16 nRotate = USHRT_MAX;
     944       61471 :     sal_uInt16 nCount = pHints ? pHints->Count() : 0;
     945             :     sal_uInt16 i;
     946      187755 :     for( i = 0; i < nCount; ++i )
     947             :     {
     948      163733 :         const SwTxtAttr *pTmp = (*pHints)[i];
     949      163733 :         sal_Int32 nStart = *pTmp->GetStart();
     950      163733 :         if( rPos < nStart )
     951       37449 :             break;
     952      126284 :         if( *pTmp->GetAnyEnd() > rPos )
     953             :         {
     954       41742 :             if( RES_TXTATR_CJK_RUBY == pTmp->Which() )
     955         168 :                 pRuby = pTmp;
     956             :             else
     957             :             {
     958       41574 :                 const SvxCharRotateItem* pRoTmp = NULL;
     959       41574 :                 if( lcl_HasRotation( *pTmp, pRoTmp, bRot ) )
     960             :                 {
     961          26 :                     nRotate = bRot ? i : nCount;
     962          26 :                     pRotate = pRoTmp;
     963             :                 }
     964       41574 :                 const SvxTwoLinesItem* p2Tmp = NULL;
     965       41574 :                 if( lcl_Has2Lines( *pTmp, p2Tmp, bTwo ) )
     966             :                 {
     967          44 :                     n2Lines = bTwo ? i : nCount;
     968          44 :                     p2Lines = p2Tmp;
     969             :                 }
     970             :             }
     971             :         }
     972             :     }
     973       61471 :     if( pRuby )
     974             :     {   // The winner is ... a ruby attribute and so
     975             :         // the end of the multiportion is the end of the ruby attribute.
     976         168 :         rPos = *pRuby->End();
     977         168 :         SwMultiCreator *pRet = new SwMultiCreator;
     978         168 :         pRet->pItem = NULL;
     979         168 :         pRet->pAttr = pRuby;
     980         168 :         pRet->nId = SW_MC_RUBY;
     981         168 :         pRet->nLevel = GetTxtFrm()->IsRightToLeft() ? 1 : 0;
     982         168 :         return pRet;
     983             :     }
     984       61559 :     if( n2Lines < nCount || ( pItem && pItem == p2Lines &&
     985         256 :         rPos < GetTxt().getLength() ) )
     986             :     {   // The winner is a 2-line-attribute,
     987             :         // the end of the multiportion depends on the following attributes...
     988          10 :         SwMultiCreator *pRet = new SwMultiCreator;
     989             : 
     990             :         // We note the endpositions of the 2-line attributes in aEnd as stack
     991          10 :         std::deque< sal_Int32 > aEnd;
     992             : 
     993             :         // The bOn flag signs the state of the last 2-line attribute in the
     994             :         // aEnd-stack, it is compatible with the winner-attribute or
     995             :         // it interrupts the other attribute.
     996          10 :         bool bOn = true;
     997             : 
     998          10 :         if( n2Lines < nCount )
     999             :         {
    1000          10 :             pRet->pItem = NULL;
    1001          10 :             pRet->pAttr = (*pHints)[n2Lines];
    1002          10 :             aEnd.push_front( *pRet->pAttr->End() );
    1003          10 :             if( pItem )
    1004             :             {
    1005           0 :                 aEnd.front() = GetTxt().getLength();
    1006           0 :                 bOn = ((SvxTwoLinesItem*)pItem)->GetEndBracket() ==
    1007           0 :                         p2Lines->GetEndBracket() &&
    1008           0 :                       ((SvxTwoLinesItem*)pItem)->GetStartBracket() ==
    1009           0 :                         p2Lines->GetStartBracket();
    1010             :             }
    1011             :         }
    1012             :         else
    1013             :         {
    1014           0 :             pRet->pItem = pItem;
    1015           0 :             pRet->pAttr = NULL;
    1016           0 :             aEnd.push_front( GetTxt().getLength() );
    1017             :         }
    1018          10 :         pRet->nId = SW_MC_DOUBLE;
    1019          10 :         pRet->nLevel = GetTxtFrm()->IsRightToLeft() ? 1 : 0;
    1020             : 
    1021             :         // n2Lines is the index of the last 2-line-attribute, which contains
    1022             :         // the actual position.
    1023          10 :         i = 0;
    1024             :         // At this moment we know that at position rPos the "winner"-attribute
    1025             :         // causes a 2-line-portion. The end of the attribute is the end of the
    1026             :         // portion, if there's no interrupting attribute.
    1027             :         // There are two kinds of interruptors:
    1028             :         // - ruby attributes stops the 2-line-attribute, the end of the
    1029             :         //   multiline is the start of the ruby attribute
    1030             :         // - 2-line-attributes with value "Off" or with different brackets,
    1031             :         //   these attributes may interrupt the winner, but they could be
    1032             :         //   neutralized by another 2-line-attribute starting at the same
    1033             :         //   position with the same brackets as the winner-attribute.
    1034             : 
    1035             :         // In the following loop rPos is the critical position and it will be
    1036             :         // evaluated, if at rPos starts a interrupting or a maintaining
    1037             :         // continuity attribute.
    1038          40 :         while( i < nCount )
    1039             :         {
    1040          20 :             const SwTxtAttr *pTmp = (*pHints)[i++];
    1041          20 :             if( *pTmp->GetAnyEnd() <= rPos )
    1042           0 :                 continue;
    1043          20 :             if( rPos < *pTmp->GetStart() )
    1044             :             {
    1045             :                 // If bOn is false and the next attribute starts later than rPos
    1046             :                 // the winner attribute is interrupted at rPos.
    1047             :                 // If the start of the next attribute is behind the end of
    1048             :                 // the last attribute on the aEnd-stack, this is the endposition
    1049             :                 // on the stack is the end of the 2-line portion.
    1050           0 :                 if( !bOn || aEnd.back() < *pTmp->GetStart() )
    1051           0 :                     break;
    1052             :                 // At this moment, bOn is true and the next attribute starts
    1053             :                 // behind rPos, so we could move rPos to the next startpoint
    1054           0 :                 rPos = *pTmp->GetStart();
    1055             :                 // We clean up the aEnd-stack, endpositions equal to rPos are
    1056             :                 // superfluous.
    1057           0 :                 while( !aEnd.empty() && aEnd.back() <= rPos )
    1058             :                 {
    1059           0 :                     bOn = !bOn;
    1060           0 :                     aEnd.pop_back();
    1061             :                 }
    1062             :                 // If the endstack is empty, we simulate an attribute with
    1063             :                 // state true and endposition rPos
    1064           0 :                 if( aEnd.empty() )
    1065             :                 {
    1066           0 :                     aEnd.push_front( rPos );
    1067           0 :                     bOn = true;
    1068             :                 }
    1069             :             }
    1070             :             // A ruby attribute stops the 2-line immediately
    1071          20 :             if( RES_TXTATR_CJK_RUBY == pTmp->Which() )
    1072           0 :                 return pRet;
    1073          20 :             if( lcl_Has2Lines( *pTmp, p2Lines, bTwo ) )
    1074             :             {   // We have an interesting attribute..
    1075          10 :                 if( bTwo == bOn )
    1076             :                 {   // .. with the same state, so the last attribute could
    1077             :                     // be continued.
    1078          10 :                     if( aEnd.back() < *pTmp->End() )
    1079           0 :                         aEnd.back() = *pTmp->End();
    1080             :                 }
    1081             :                 else
    1082             :                 {   // .. with a different state.
    1083           0 :                     bOn = bTwo;
    1084             :                     // If this is smaller than the last on the stack, we put
    1085             :                     // it on the stack. If it has the same endposition, the last
    1086             :                     // could be removed.
    1087           0 :                     if( aEnd.back() > *pTmp->End() )
    1088           0 :                         aEnd.push_back( *pTmp->End() );
    1089           0 :                     else if( aEnd.size() > 1 )
    1090           0 :                         aEnd.pop_back();
    1091             :                     else
    1092           0 :                         aEnd.back() = *pTmp->End();
    1093             :                 }
    1094             :             }
    1095             :         }
    1096          10 :         if( bOn && !aEnd.empty() )
    1097          10 :             rPos = aEnd.back();
    1098          10 :         return pRet;
    1099             :     }
    1100       61734 :     if( nRotate < nCount || ( pRotItem && pRotItem == pRotate &&
    1101         441 :         rPos < GetTxt().getLength() ) )
    1102             :     {   // The winner is a rotate-attribute,
    1103             :         // the end of the multiportion depends on the following attributes...
    1104         285 :         SwMultiCreator *pRet = new SwMultiCreator;
    1105         285 :         pRet->nId = SW_MC_ROTATE;
    1106             : 
    1107             :         // We note the endpositions of the 2-line attributes in aEnd as stack
    1108         285 :         std::deque< sal_Int32 > aEnd;
    1109             : 
    1110             :         // The bOn flag signs the state of the last 2-line attribute in the
    1111             :         // aEnd-stack, which could interrupts the winning rotation attribute.
    1112         285 :         bool bOn = pItem;
    1113         285 :         aEnd.push_front( GetTxt().getLength() );
    1114             :         // n2Lines is the index of the last 2-line-attribute, which contains
    1115             :         // the actual position.
    1116         285 :         i = 0;
    1117         285 :         sal_Int32 n2Start = rPos;
    1118        1134 :         while( i < nCount )
    1119             :         {
    1120         564 :             const SwTxtAttr *pTmp = (*pHints)[i++];
    1121         564 :             if( *pTmp->GetAnyEnd() <= n2Start )
    1122           0 :                 continue;
    1123         564 :             if( n2Start < *pTmp->GetStart() )
    1124             :             {
    1125         280 :                 if( bOn || aEnd.back() < *pTmp->GetStart() )
    1126           0 :                     break;
    1127         280 :                 n2Start = *pTmp->GetStart();
    1128         840 :                 while( !aEnd.empty() && aEnd.back() <= n2Start )
    1129             :                 {
    1130         280 :                     bOn = !bOn;
    1131         280 :                     aEnd.pop_back();
    1132             :                 }
    1133         280 :                 if( aEnd.empty() )
    1134             :                 {
    1135         280 :                     aEnd.push_front( n2Start );
    1136         280 :                     bOn = false;
    1137             :                 }
    1138             :             }
    1139             :             // A ruby attribute stops immediately
    1140         564 :             if( RES_TXTATR_CJK_RUBY == pTmp->Which() )
    1141             :             {
    1142           0 :                 bOn = true;
    1143           0 :                 break;
    1144             :             }
    1145         564 :             p2Lines = NULL;
    1146         564 :             if( lcl_Has2Lines( *pTmp, p2Lines, bTwo ) )
    1147             :             {
    1148           0 :                 if( bTwo == bOn )
    1149             :                 {
    1150           0 :                     if( aEnd.back() < *pTmp->End() )
    1151           0 :                         aEnd.back() = *pTmp->End();
    1152             :                 }
    1153             :                 else
    1154             :                 {
    1155           0 :                     bOn = bTwo;
    1156           0 :                     if( aEnd.back() > *pTmp->End() )
    1157           0 :                         aEnd.push_back( *pTmp->End() );
    1158           0 :                     else if( aEnd.size() > 1 )
    1159           0 :                         aEnd.pop_back();
    1160             :                     else
    1161           0 :                         aEnd.back() = *pTmp->End();
    1162             :                 }
    1163             :             }
    1164             :         }
    1165         285 :         if( !bOn && !aEnd.empty() )
    1166         285 :             n2Start = aEnd.back();
    1167             : 
    1168         285 :         if( !aEnd.empty() )
    1169         285 :             aEnd.clear();
    1170             : 
    1171         285 :         bOn = true;
    1172         285 :         if( nRotate < nCount )
    1173             :         {
    1174           0 :             pRet->pItem = NULL;
    1175           0 :             pRet->pAttr = (*pHints)[nRotate];
    1176           0 :             aEnd.push_front( *pRet->pAttr->End() );
    1177           0 :             if( pRotItem )
    1178             :             {
    1179           0 :                 aEnd.front() = GetTxt().getLength();
    1180           0 :                 bOn = ((SvxCharRotateItem*)pRotItem)->GetValue() ==
    1181           0 :                         pRotate->GetValue();
    1182             :             }
    1183             :         }
    1184             :         else
    1185             :         {
    1186         285 :             pRet->pItem = pRotItem;
    1187         285 :             pRet->pAttr = NULL;
    1188         285 :             aEnd.push_front( GetTxt().getLength() );
    1189             :         }
    1190         285 :         i = 0;
    1191        1134 :         while( i < nCount )
    1192             :         {
    1193         564 :             const SwTxtAttr *pTmp = (*pHints)[i++];
    1194         564 :             if( *pTmp->GetAnyEnd() <= rPos )
    1195           0 :                 continue;
    1196         564 :             if( rPos < *pTmp->GetStart() )
    1197             :             {
    1198         280 :                 if( !bOn || aEnd.back() < *pTmp->GetStart() )
    1199           0 :                     break;
    1200         280 :                 rPos = *pTmp->GetStart();
    1201         840 :                 while( !aEnd.empty() && aEnd.back() <= rPos )
    1202             :                 {
    1203         280 :                     bOn = !bOn;
    1204         280 :                     aEnd.pop_back();
    1205             :                 }
    1206         280 :                 if( aEnd.empty() )
    1207             :                 {
    1208         280 :                     aEnd.push_front( rPos );
    1209         280 :                     bOn = true;
    1210             :                 }
    1211             :             }
    1212         564 :             if( RES_TXTATR_CJK_RUBY == pTmp->Which() )
    1213             :             {
    1214           0 :                 bOn = false;
    1215           0 :                 break;
    1216             :             }
    1217         564 :             if( lcl_HasRotation( *pTmp, pRotate, bTwo ) )
    1218             :             {
    1219           0 :                 if( bTwo == bOn )
    1220             :                 {
    1221           0 :                     if( aEnd.back() < *pTmp->End() )
    1222           0 :                         aEnd.back() = *pTmp->End();
    1223             :                 }
    1224             :                 else
    1225             :                 {
    1226           0 :                     bOn = bTwo;
    1227           0 :                     if( aEnd.back() > *pTmp->End() )
    1228           0 :                         aEnd.push_back( *pTmp->End() );
    1229           0 :                     else if( aEnd.size() > 1 )
    1230           0 :                         aEnd.pop_back();
    1231             :                     else
    1232           0 :                         aEnd.back() = *pTmp->End();
    1233             :                 }
    1234             :             }
    1235             :         }
    1236         285 :         if( bOn && !aEnd.empty() )
    1237         285 :             rPos = aEnd.back();
    1238         285 :         if( rPos > n2Start )
    1239           0 :             rPos = n2Start;
    1240         285 :         return pRet;
    1241             :     }
    1242       61008 :     return NULL;
    1243             : }
    1244             : 
    1245             : /*--------------------------------------------------
    1246             :  * SwSpaceManipulator
    1247             :  * is a little helper class to manage the spaceadd-arrays of the text adjustment
    1248             :  * during a PaintMultiPortion.
    1249             :  * The constructor prepares the array for the first line of multiportion,
    1250             :  * the SecondLine-function restores the values for the first line and prepares
    1251             :  * the second line.
    1252             :  * The destructor restores the values of the last manipulation.
    1253             :  * --------------------------------------------------*/
    1254             : 
    1255             : class SwSpaceManipulator
    1256             : {
    1257             :     SwTxtPaintInfo& rInfo;
    1258             :     SwMultiPortion& rMulti;
    1259             :     std::vector<long>* pOldSpaceAdd;
    1260             :     MSHORT nOldSpIdx;
    1261             :     long nSpaceAdd;
    1262             :     bool bSpaceChg;
    1263             :     sal_uInt8 nOldDir;
    1264             : public:
    1265             :     SwSpaceManipulator( SwTxtPaintInfo& rInf, SwMultiPortion& rMult );
    1266             :     ~SwSpaceManipulator();
    1267             :     void SecondLine();
    1268          11 :     inline long GetSpaceAdd() const { return nSpaceAdd; }
    1269             : };
    1270             : 
    1271         190 : SwSpaceManipulator::SwSpaceManipulator( SwTxtPaintInfo& rInf,
    1272             :                                         SwMultiPortion& rMult )
    1273             :     : rInfo(rInf)
    1274             :     , rMulti(rMult)
    1275         190 :     , nSpaceAdd(0)
    1276             : {
    1277         190 :     pOldSpaceAdd = rInfo.GetpSpaceAdd();
    1278         190 :     nOldSpIdx = rInfo.GetSpaceIdx();
    1279         190 :     nOldDir = rInfo.GetDirection();
    1280         190 :     rInfo.SetDirection( rMulti.GetDirection() );
    1281         190 :     bSpaceChg = false;
    1282             : 
    1283         190 :     if( rMulti.IsDouble() )
    1284             :     {
    1285           0 :         nSpaceAdd = ( pOldSpaceAdd && !rMulti.HasTabulator() ) ?
    1286          13 :                       rInfo.GetSpaceAdd() : 0;
    1287          13 :         if( rMulti.GetRoot().IsSpaceAdd() )
    1288             :         {
    1289           0 :             rInfo.SetpSpaceAdd( rMulti.GetRoot().GetpLLSpaceAdd() );
    1290           0 :             rInfo.ResetSpaceIdx();
    1291           0 :             bSpaceChg = rMulti.ChgSpaceAdd( &rMulti.GetRoot(), nSpaceAdd );
    1292             :         }
    1293          13 :         else if( rMulti.HasTabulator() )
    1294           0 :             rInfo.SetpSpaceAdd( NULL );
    1295             :     }
    1296         177 :     else if ( ! rMulti.IsBidi() )
    1297             :     {
    1298         173 :         rInfo.SetpSpaceAdd( rMulti.GetRoot().GetpLLSpaceAdd() );
    1299         173 :         rInfo.ResetSpaceIdx();
    1300             :     }
    1301         190 : }
    1302             : 
    1303         185 : void SwSpaceManipulator::SecondLine()
    1304             : {
    1305         185 :     if( bSpaceChg )
    1306             :     {
    1307           0 :         rInfo.RemoveFirstSpaceAdd();
    1308           0 :         bSpaceChg = false;
    1309             :     }
    1310         185 :     SwLineLayout *pLay = rMulti.GetRoot().GetNext();
    1311         185 :     if( pLay->IsSpaceAdd() )
    1312             :     {
    1313          13 :         rInfo.SetpSpaceAdd( pLay->GetpLLSpaceAdd() );
    1314          13 :         rInfo.ResetSpaceIdx();
    1315          13 :         bSpaceChg = rMulti.ChgSpaceAdd( pLay, nSpaceAdd );
    1316             :     }
    1317             :     else
    1318             :     {
    1319         172 :         rInfo.SetpSpaceAdd( (!rMulti.IsDouble() || rMulti.HasTabulator() ) ?
    1320         172 :                                 0 : pOldSpaceAdd );
    1321         172 :         rInfo.SetSpaceIdx( nOldSpIdx);
    1322             :     }
    1323         185 : }
    1324             : 
    1325         190 : SwSpaceManipulator::~SwSpaceManipulator()
    1326             : {
    1327         190 :     if( bSpaceChg )
    1328             :     {
    1329           0 :         rInfo.RemoveFirstSpaceAdd();
    1330           0 :         bSpaceChg = false;
    1331             :     }
    1332         190 :     rInfo.SetpSpaceAdd( pOldSpaceAdd );
    1333         190 :     rInfo.SetSpaceIdx( nOldSpIdx);
    1334         190 :     rInfo.SetDirection( nOldDir );
    1335         190 : }
    1336             : 
    1337             : /*--------------------------------------------------
    1338             :  * SwTxtPainter::PaintMultiPortion manages the paint for a SwMultiPortion.
    1339             :  * External, for the calling function, it seems to be a normal Paint-function,
    1340             :  * internal it is like a SwTxtFrm::Paint with multiple DrawTextLines
    1341             :  * --------------------------------------------------*/
    1342             : 
    1343         190 : void SwTxtPainter::PaintMultiPortion( const SwRect &rPaint,
    1344             :     SwMultiPortion& rMulti, const SwMultiPortion* pEnvPor )
    1345             : {
    1346         190 :     SwTextGridItem const*const pGrid(GetGridItem(pFrm->FindPageFrm()));
    1347         190 :     const bool bHasGrid = pGrid && GetInfo().SnapToGrid();
    1348         190 :     sal_uInt16 nRubyHeight = 0;
    1349         190 :     bool bRubyTop = false;
    1350             : 
    1351         190 :     if ( bHasGrid )
    1352             :     {
    1353           0 :         nRubyHeight = pGrid->GetRubyHeight();
    1354           0 :         bRubyTop = ! pGrid->GetRubyTextBelow();
    1355             :     }
    1356             : 
    1357             :     // do not allow grid mode for first line in ruby portion
    1358         190 :     const bool bRubyInGrid = bHasGrid && rMulti.IsRuby();
    1359             : 
    1360         190 :     const sal_uInt16 nOldHeight = rMulti.Height();
    1361         190 :     const bool bOldGridModeAllowed = GetInfo().SnapToGrid();
    1362             : 
    1363         190 :     if ( bRubyInGrid )
    1364             :     {
    1365           0 :         GetInfo().SetSnapToGrid( ! bRubyTop );
    1366           0 :         rMulti.Height( pCurr->Height() );
    1367             :     }
    1368             : 
    1369         190 :     SwLayoutModeModifier aLayoutModeModifier( *GetInfo().GetOut() );
    1370         190 :     sal_uInt8 nEnvDir = 0;
    1371         190 :     sal_uInt8 nThisDir = 0;
    1372         190 :     sal_uInt8 nFrmDir = 0;
    1373         190 :     if ( rMulti.IsBidi() )
    1374             :     {
    1375             :         // these values are needed for the calculation of the x coordinate
    1376             :         // and the layout mode
    1377             :         OSL_ENSURE( ! pEnvPor || pEnvPor->IsBidi(),
    1378             :                 "Oh no, I expected a BidiPortion" );
    1379           4 :         nFrmDir = GetInfo().GetTxtFrm()->IsRightToLeft() ? 1 : 0;
    1380           4 :         nEnvDir = pEnvPor ? ((SwBidiPortion*)pEnvPor)->GetLevel() % 2 : nFrmDir;
    1381           4 :         nThisDir = ((SwBidiPortion&)rMulti).GetLevel() % 2;
    1382             :     }
    1383             : 
    1384             : #if OSL_DEBUG_LEVEL > 1
    1385             :     // only paint first level bidi portions
    1386             :     if( rMulti.Width() > 1 && ! pEnvPor )
    1387             :         GetInfo().DrawViewOpt( rMulti, POR_FLD );
    1388             : #endif
    1389             : 
    1390         190 :     if ( bRubyInGrid )
    1391           0 :         rMulti.Height( nOldHeight );
    1392             : 
    1393             :     // do we have to repaint a post it portion?
    1394         300 :     if( GetInfo().OnWin() && rMulti.GetPortion() &&
    1395         110 :         ! rMulti.GetPortion()->Width() )
    1396          22 :         rMulti.GetPortion()->PrePaint( GetInfo(), &rMulti );
    1397             : 
    1398             :     // old values must be saved and restored at the end
    1399         190 :     sal_Int32 nOldLen = GetInfo().GetLen();
    1400         190 :     KSHORT nOldX = KSHORT(GetInfo().X());
    1401         190 :     long nOldY = GetInfo().Y();
    1402         190 :     sal_Int32 nOldIdx = GetInfo().GetIdx();
    1403             : 
    1404         380 :     SwSpaceManipulator aManip( GetInfo(), rMulti );
    1405             : 
    1406             :     SwFontSave *pFontSave;
    1407             :     SwFont* pTmpFnt;
    1408             : 
    1409         190 :     if( rMulti.IsDouble() )
    1410             :     {
    1411          13 :         pTmpFnt = new SwFont( *GetInfo().GetFont() );
    1412          13 :         if( rMulti.IsDouble() )
    1413             :         {
    1414          13 :             SetPropFont( 50 );
    1415          13 :             pTmpFnt->SetProportion( GetPropFont() );
    1416             :         }
    1417          13 :         pFontSave = new SwFontSave( GetInfo(), pTmpFnt, this );
    1418             :     }
    1419             :     else
    1420             :     {
    1421         177 :         pFontSave = NULL;
    1422         177 :         pTmpFnt = NULL;
    1423             :     }
    1424             : 
    1425         190 :     if( rMulti.HasBrackets() )
    1426             :     {
    1427          11 :         sal_Int32 nTmpOldIdx = GetInfo().GetIdx();
    1428          11 :         GetInfo().SetIdx(((SwDoubleLinePortion&)rMulti).GetBrackets()->nStart);
    1429          11 :         SeekAndChg( GetInfo() );
    1430          11 :         ((SwDoubleLinePortion&)rMulti).PaintBracket( GetInfo(), 0, true );
    1431          11 :         GetInfo().SetIdx( nTmpOldIdx );
    1432             :     }
    1433             : 
    1434         190 :     KSHORT nTmpX = KSHORT(GetInfo().X());
    1435             : 
    1436         190 :     SwLineLayout* pLay = &rMulti.GetRoot();// the first line of the multiportion
    1437         190 :     SwLinePortion* pPor = pLay->GetFirstPortion();//first portion of these line
    1438         190 :     SwTwips nOfst = 0;
    1439             : 
    1440             :     // GetInfo().Y() is the baseline from the surrounding line. We must switch
    1441             :     // this temporary to the baseline of the inner lines of the multiportion.
    1442         190 :     if( rMulti.HasRotation() )
    1443             :     {
    1444           1 :         if( rMulti.IsRevers() )
    1445             :         {
    1446           0 :             GetInfo().Y( nOldY - rMulti.GetAscent() );
    1447           0 :             nOfst = nTmpX + rMulti.Width();
    1448             :         }
    1449             :         else
    1450             :         {
    1451           1 :             GetInfo().Y( nOldY - rMulti.GetAscent() + rMulti.Height() );
    1452           1 :             nOfst = nTmpX;
    1453             :         }
    1454             :     }
    1455         189 :     else if ( rMulti.IsBidi() )
    1456             :     {
    1457             :         // does the current bidi portion has the same direction
    1458             :         // as its environment?
    1459           4 :         if ( nEnvDir != nThisDir )
    1460             :         {
    1461             :             // different directions, we have to adjust the x coordinate
    1462           4 :             SwTwips nMultiWidth = rMulti.Width() +
    1463           4 :                     rMulti.CalcSpacing( GetInfo().GetSpaceAdd(), GetInfo() );
    1464             : 
    1465           4 :             if ( nFrmDir == nThisDir )
    1466           0 :                 GetInfo().X( GetInfo().X() - nMultiWidth );
    1467             :             else
    1468           4 :                 GetInfo().X( GetInfo().X() + nMultiWidth );
    1469             :         }
    1470             : 
    1471           4 :         nOfst = nOldY - rMulti.GetAscent();
    1472             : 
    1473             :         // set layout mode
    1474           4 :         aLayoutModeModifier.Modify( nThisDir );
    1475             :     }
    1476             :     else
    1477         185 :         nOfst = nOldY - rMulti.GetAscent();
    1478             : 
    1479         190 :     bool bRest = pLay->IsRest();
    1480         190 :     bool bFirst = true;
    1481             : 
    1482             :     OSL_ENSURE( 0 == GetInfo().GetUnderFnt() || rMulti.IsBidi(),
    1483             :             " Only BiDi portions are allowed to use the common underlining font" );
    1484             : 
    1485         531 :     do
    1486             :     {
    1487         531 :         if ( bHasGrid )
    1488             :         {
    1489           0 :             if( rMulti.HasRotation() )
    1490             :             {
    1491           0 :                 const sal_uInt16 nAdjustment = ( pLay->Height() - pPor->Height() ) / 2 +
    1492           0 :                                             pPor->GetAscent();
    1493           0 :                 if( rMulti.IsRevers() )
    1494           0 :                     GetInfo().X( nOfst - nAdjustment );
    1495             :                 else
    1496           0 :                     GetInfo().X( nOfst + nAdjustment );
    1497             :             }
    1498             :             else
    1499             :             {
    1500             :                 // special treatment for ruby portions in grid mode
    1501           0 :                 SwTwips nAdjustment = 0;
    1502           0 :                 if ( rMulti.IsRuby() )
    1503             :                 {
    1504           0 :                     if ( bRubyTop != ( pLay == &rMulti.GetRoot() ) )
    1505             :                         // adjust base text
    1506           0 :                         nAdjustment = ( pCurr->Height() - nRubyHeight - pPor->Height() ) / 2;
    1507           0 :                     else if ( bRubyTop )
    1508             :                         // adjust upper ruby text
    1509           0 :                         nAdjustment = nRubyHeight - pPor->Height();
    1510             :                     // else adjust lower ruby text
    1511             :                 }
    1512             : 
    1513           0 :                 GetInfo().Y( nOfst + nAdjustment + pPor->GetAscent() );
    1514             :             }
    1515             :         }
    1516         531 :         else if( rMulti.HasRotation() )
    1517             :         {
    1518           1 :             if( rMulti.IsRevers() )
    1519           0 :                 GetInfo().X( nOfst - AdjustBaseLine( *pLay, pPor, 0, 0, true ) );
    1520             :             else
    1521           1 :                 GetInfo().X( nOfst + AdjustBaseLine( *pLay, pPor ) );
    1522             :         }
    1523             :         else
    1524         530 :             GetInfo().Y( nOfst + AdjustBaseLine( *pLay, pPor ) );
    1525             : 
    1526         531 :         bool bSeeked = true;
    1527         531 :         GetInfo().SetLen( pPor->GetLen() );
    1528             : 
    1529         531 :         if( bRest && pPor->InFldGrp() && !pPor->GetLen() )
    1530             :         {
    1531         172 :             if( ((SwFldPortion*)pPor)->HasFont() )
    1532         172 :                  bSeeked = false;
    1533             :             else
    1534           0 :                 SeekAndChgBefore( GetInfo() );
    1535             :         }
    1536         359 :         else if( pPor->InTxtGrp() || pPor->InFldGrp() || pPor->InTabGrp() )
    1537         291 :             SeekAndChg( GetInfo() );
    1538          68 :         else if ( !bFirst && pPor->IsBreakPortion() && GetInfo().GetOpt().IsParagraph() )
    1539             :         {
    1540           0 :             if( GetRedln() )
    1541           0 :                 SeekAndChg( GetInfo() );
    1542             :             else
    1543           0 :                 SeekAndChgBefore( GetInfo() );
    1544             :         }
    1545             :         else
    1546          68 :             bSeeked = false;
    1547             : 
    1548         531 :         SwLinePortion *pNext = pPor->GetPortion();
    1549         531 :         if(GetInfo().OnWin() && pNext && !pNext->Width() )
    1550             :         {
    1551          15 :             if ( !bSeeked )
    1552           0 :                 SeekAndChg( GetInfo() );
    1553          15 :             pNext->PrePaint( GetInfo(), pPor );
    1554             :         }
    1555             : 
    1556         531 :         CheckSpecialUnderline( pPor );
    1557         531 :         SwUnderlineFont* pUnderLineFnt = GetInfo().GetUnderFnt();
    1558         531 :         if ( pUnderLineFnt )
    1559             :         {
    1560           2 :             if ( rMulti.IsDouble() )
    1561           0 :                 pUnderLineFnt->GetFont().SetProportion( 50 );
    1562           2 :             pUnderLineFnt->SetPos( GetInfo().GetPos() );
    1563             :         }
    1564             : 
    1565         531 :         if ( rMulti.IsBidi() )
    1566             :         {
    1567             :             // we do not allow any rotation inside a bidi portion
    1568           4 :             SwFont* pTmpFont = GetInfo().GetFont();
    1569           4 :             pTmpFont->SetVertical( 0, GetInfo().GetTxtFrm()->IsVertical() );
    1570             :         }
    1571             : 
    1572         531 :         if( pPor->IsMultiPortion() && ((SwMultiPortion*)pPor)->IsBidi() )
    1573             :         {
    1574             :             // but we do allow nested bidi portions
    1575             :             OSL_ENSURE( rMulti.IsBidi(), "Only nesting of bidi portions is allowed" );
    1576           0 :             PaintMultiPortion( rPaint, (SwMultiPortion&)*pPor, &rMulti );
    1577             :         }
    1578             :         else
    1579         531 :             pPor->Paint( GetInfo() );
    1580             : 
    1581         531 :         if( GetFnt()->IsURL() && pPor->InTxtGrp() )
    1582           0 :             GetInfo().NotifyURL( *pPor );
    1583             : 
    1584         531 :         bFirst &= !pPor->GetLen();
    1585         531 :         if( pNext || !pPor->IsMarginPortion() )
    1586         497 :             pPor->Move( GetInfo() );
    1587             : 
    1588         531 :         pPor = pNext;
    1589             : 
    1590             :         // If there's no portion left, we go to the next line
    1591         531 :         if( !pPor && pLay->GetNext() )
    1592             :         {
    1593         185 :             pLay = pLay->GetNext();
    1594         185 :             pPor = pLay->GetFirstPortion();
    1595         185 :             bRest = pLay->IsRest();
    1596         185 :             aManip.SecondLine();
    1597             : 
    1598             :             // delete underline font
    1599         185 :             delete GetInfo().GetUnderFnt();
    1600         185 :             GetInfo().SetUnderFnt( 0 );
    1601             : 
    1602         185 :             if( rMulti.HasRotation() )
    1603             :             {
    1604           0 :                 if( rMulti.IsRevers() )
    1605             :                 {
    1606           0 :                     nOfst += pLay->Height();
    1607           0 :                     GetInfo().Y( nOldY - rMulti.GetAscent() );
    1608             :                 }
    1609             :                 else
    1610             :                 {
    1611           0 :                     nOfst -= pLay->Height();
    1612           0 :                     GetInfo().Y( nOldY - rMulti.GetAscent() + rMulti.Height() );
    1613             :                 }
    1614             :             }
    1615         185 :             else if ( bHasGrid && rMulti.IsRuby() )
    1616             :             {
    1617           0 :                 GetInfo().X( nTmpX );
    1618           0 :                 if ( bRubyTop )
    1619             :                 {
    1620           0 :                     nOfst += nRubyHeight;
    1621           0 :                     GetInfo().SetSnapToGrid( true );
    1622             :                 }
    1623             :                 else
    1624             :                 {
    1625           0 :                     nOfst += pCurr->Height() - nRubyHeight;
    1626           0 :                     GetInfo().SetSnapToGrid( false );
    1627             :                 }
    1628             :             } else
    1629             :             {
    1630         185 :                 GetInfo().X( nTmpX );
    1631             :                 // We switch to the baseline of the next inner line
    1632         185 :                 nOfst += rMulti.GetRoot().Height();
    1633             :             }
    1634             :         }
    1635             :     } while( pPor );
    1636             : 
    1637         190 :     if ( bRubyInGrid )
    1638           0 :         GetInfo().SetSnapToGrid( bOldGridModeAllowed );
    1639             : 
    1640             :     // delete underline font
    1641         190 :     if ( ! rMulti.IsBidi() )
    1642             :     {
    1643         186 :         delete GetInfo().GetUnderFnt();
    1644         186 :         GetInfo().SetUnderFnt( 0 );
    1645             :     }
    1646             : 
    1647         190 :     GetInfo().SetIdx( nOldIdx );
    1648         190 :     GetInfo().Y( nOldY );
    1649             : 
    1650         190 :     if( rMulti.HasBrackets() )
    1651             :     {
    1652          11 :         sal_Int32 nTmpOldIdx = GetInfo().GetIdx();
    1653          11 :         GetInfo().SetIdx(((SwDoubleLinePortion&)rMulti).GetBrackets()->nStart);
    1654          11 :         SeekAndChg( GetInfo() );
    1655          11 :         GetInfo().X( nOldX );
    1656          11 :         ((SwDoubleLinePortion&)rMulti).PaintBracket( GetInfo(),
    1657          22 :             aManip.GetSpaceAdd(), false );
    1658          11 :         GetInfo().SetIdx( nTmpOldIdx );
    1659             :     }
    1660             :     // Restore the saved values
    1661         190 :     GetInfo().X( nOldX );
    1662         190 :     GetInfo().SetLen( nOldLen );
    1663         190 :     delete pFontSave;
    1664         190 :     delete pTmpFnt;
    1665         380 :     SetPropFont( 0 );
    1666         190 : }
    1667             : 
    1668           0 : static bool lcl_ExtractFieldFollow( SwLineLayout* pLine, SwLinePortion* &rpFld )
    1669             : {
    1670           0 :     SwLinePortion* pLast = pLine;
    1671           0 :     rpFld = pLine->GetPortion();
    1672           0 :     while( rpFld && !rpFld->InFldGrp() )
    1673             :     {
    1674           0 :         pLast = rpFld;
    1675           0 :         rpFld = rpFld->GetPortion();
    1676             :     }
    1677           0 :     bool bRet = rpFld != 0;
    1678           0 :     if( bRet )
    1679             :     {
    1680           0 :         if( ((SwFldPortion*)rpFld)->IsFollow() )
    1681             :         {
    1682           0 :             rpFld->Truncate();
    1683           0 :             pLast->SetPortion( NULL );
    1684             :         }
    1685             :         else
    1686           0 :             rpFld = NULL;
    1687             :     }
    1688           0 :     pLine->Truncate();
    1689           0 :     return bRet;
    1690             : }
    1691             : 
    1692             : /*----------------------------------------------------
    1693             :  *              lcl_TruncateMultiPortion
    1694             :  * If a multi portion completely has to go to the
    1695             :  * next line, this function is called to trunctate
    1696             :  * the rest of the remaining multi portion
    1697             :  * --------------------------------------------------*/
    1698             : 
    1699          55 : static void lcl_TruncateMultiPortion( SwMultiPortion& rMulti, SwTxtFormatInfo& rInf,
    1700             :                                sal_Int32 nStartIdx )
    1701             : {
    1702          55 :     rMulti.GetRoot().Truncate();
    1703          55 :     rMulti.GetRoot().SetLen(0);
    1704          55 :     rMulti.GetRoot().Width(0);
    1705             : //  rMulti.CalcSize( *this, aInf );
    1706          55 :     if ( rMulti.GetRoot().GetNext() )
    1707             :     {
    1708           0 :         rMulti.GetRoot().GetNext()->Truncate();
    1709           0 :         rMulti.GetRoot().GetNext()->SetLen( 0 );
    1710           0 :         rMulti.GetRoot().GetNext()->Width( 0 );
    1711             :     }
    1712          55 :     rMulti.Width( 0 );
    1713          55 :     rMulti.SetLen(0);
    1714          55 :     rInf.SetIdx( nStartIdx );
    1715          55 : }
    1716             : 
    1717             : /*-----------------------------------------------------------------------------
    1718             :  *              SwTxtFormatter::BuildMultiPortion
    1719             :  * manages the formatting of a SwMultiPortion. External, for the calling
    1720             :  * function, it seems to be a normal Format-function, internal it is like a
    1721             :  * SwTxtFrm::_Format with multiple BuildPortions
    1722             :  *---------------------------------------------------------------------------*/
    1723             : 
    1724         539 : bool SwTxtFormatter::BuildMultiPortion( SwTxtFormatInfo &rInf,
    1725             :     SwMultiPortion& rMulti )
    1726             : {
    1727         539 :     SwTwips nMaxWidth = rInf.Width();
    1728         539 :     KSHORT nOldX = 0;
    1729             : 
    1730         539 :     if( rMulti.HasBrackets() )
    1731             :     {
    1732           8 :         sal_Int32 nOldIdx = rInf.GetIdx();
    1733           8 :         rInf.SetIdx( ((SwDoubleLinePortion&)rMulti).GetBrackets()->nStart );
    1734           8 :         SeekAndChg( rInf );
    1735           8 :         nOldX = KSHORT(GetInfo().X());
    1736           8 :         ((SwDoubleLinePortion&)rMulti).FormatBrackets( rInf, nMaxWidth );
    1737           8 :         rInf.SetIdx( nOldIdx );
    1738             :     }
    1739             : 
    1740         539 :     SeekAndChg( rInf );
    1741         539 :     boost::scoped_ptr<SwFontSave> xFontSave;
    1742         539 :     if( rMulti.IsDouble() )
    1743             :     {
    1744          10 :         SwFont* pTmpFnt = new SwFont( *rInf.GetFont() );
    1745          10 :         if( rMulti.IsDouble() )
    1746             :         {
    1747          10 :             SetPropFont( 50 );
    1748          10 :             pTmpFnt->SetProportion( GetPropFont() );
    1749             :         }
    1750          10 :         xFontSave.reset(new SwFontSave(rInf, pTmpFnt, this));
    1751             :     }
    1752             : 
    1753        1078 :     SwLayoutModeModifier aLayoutModeModifier( *GetInfo().GetOut() );
    1754         539 :     if ( rMulti.IsBidi() )
    1755             :     {
    1756             :         // set layout mode
    1757          21 :         aLayoutModeModifier.Modify( ! rInf.GetTxtFrm()->IsRightToLeft() );
    1758             :     }
    1759             : 
    1760         539 :     SwTwips nTmpX = 0;
    1761             : 
    1762         539 :     if( rMulti.HasRotation() )
    1763             :     {
    1764             :         // For nMaxWidth we take the height of the body frame.
    1765             :         // #i25067#: If the current frame is inside a table, we restrict
    1766             :         // nMaxWidth to the current frame height, unless the frame size
    1767             :         // attribute is set to variable size:
    1768             : 
    1769             :         // We set nTmpX (which is used for portion calculating) to the
    1770             :         // current Y value
    1771         340 :         const SwPageFrm* pPage = pFrm->FindPageFrm();
    1772             :         OSL_ENSURE( pPage, "No page in frame!");
    1773         340 :         const SwLayoutFrm* pUpperFrm = pPage;
    1774             : 
    1775         340 :         if ( pFrm->IsInTab() )
    1776             :         {
    1777         336 :             pUpperFrm = pFrm->GetUpper();
    1778         672 :             while ( pUpperFrm && !pUpperFrm->IsCellFrm() )
    1779           0 :                 pUpperFrm = pUpperFrm->GetUpper();
    1780             :             assert(pUpperFrm); //pFrm is in table but does not have an upper cell frame
    1781         336 :             if (!pUpperFrm)
    1782           0 :                 return false;
    1783         336 :             const SwTableLine* pLine = ((SwRowFrm*)pUpperFrm->GetUpper())->GetTabLine();
    1784         336 :             const SwFmtFrmSize& rFrmFmtSize = pLine->GetFrmFmt()->GetFrmSize();
    1785         336 :             if ( ATT_VAR_SIZE == rFrmFmtSize.GetHeightSizeType() )
    1786           1 :                 pUpperFrm = pPage;
    1787             :         }
    1788         340 :         if ( pUpperFrm == pPage && !pFrm->IsInFtn() )
    1789           5 :             pUpperFrm = pPage->FindBodyCont();
    1790             : 
    1791             :         nMaxWidth = pUpperFrm ?
    1792         340 :                     ( rInf.GetTxtFrm()->IsVertical() ?
    1793           0 :                       pUpperFrm->Prt().Width() :
    1794         340 :                       pUpperFrm->Prt().Height() ) :
    1795        1020 :                     USHRT_MAX;
    1796             :     }
    1797             :     else
    1798         199 :         nTmpX = rInf.X();
    1799             : 
    1800         539 :     SwMultiPortion* pOldMulti = pMulti;
    1801             : 
    1802         539 :     pMulti = &rMulti;
    1803         539 :     SwLineLayout *pOldCurr = pCurr;
    1804         539 :     sal_Int32 nOldStart = GetStart();
    1805         539 :     SwTwips nMinWidth = nTmpX + 1;
    1806         539 :     SwTwips nActWidth = nMaxWidth;
    1807         539 :     const sal_Int32 nStartIdx = rInf.GetIdx();
    1808         539 :     sal_Int32 nMultiLen = rMulti.GetLen();
    1809             : 
    1810             :     SwLinePortion *pFirstRest;
    1811             :     SwLinePortion *pSecondRest;
    1812         539 :     if( rMulti.IsFormatted() )
    1813             :     {
    1814           0 :         if( !lcl_ExtractFieldFollow( &rMulti.GetRoot(), pFirstRest )
    1815           0 :             && rMulti.IsDouble() && rMulti.GetRoot().GetNext() )
    1816           0 :             lcl_ExtractFieldFollow( rMulti.GetRoot().GetNext(), pFirstRest );
    1817           0 :         if( !rMulti.IsDouble() && rMulti.GetRoot().GetNext() )
    1818           0 :             lcl_ExtractFieldFollow( rMulti.GetRoot().GetNext(), pSecondRest );
    1819             :         else
    1820           0 :             pSecondRest = NULL;
    1821             :     }
    1822             :     else
    1823             :     {
    1824         539 :         pFirstRest = rMulti.GetRoot().GetPortion();
    1825         539 :         pSecondRest = rMulti.GetRoot().GetNext() ?
    1826         539 :                       rMulti.GetRoot().GetNext()->GetPortion() : NULL;
    1827         539 :         if( pFirstRest )
    1828         140 :             rMulti.GetRoot().SetPortion( NULL );
    1829         539 :         if( pSecondRest )
    1830          28 :             rMulti.GetRoot().GetNext()->SetPortion( NULL );
    1831         539 :         rMulti.SetFormatted();
    1832         539 :         nMultiLen = nMultiLen - rInf.GetIdx();
    1833             :     }
    1834             : 
    1835             :     // save some values
    1836         539 :     const OUString* pOldTxt = &(rInf.GetTxt());
    1837         539 :     const SwTwips nOldPaintOfst = rInf.GetPaintOfst();
    1838             : 
    1839        1078 :     OUString const aMultiStr( rInf.GetTxt().copy(0, nMultiLen + rInf.GetIdx()) );
    1840         539 :     rInf.SetTxt( aMultiStr );
    1841        1078 :     SwTxtFormatInfo aInf( rInf, rMulti.GetRoot(), nActWidth );
    1842             :     // Do we allow break cuts? The FirstMulti-Flag is evaluated during
    1843             :     // line break determination.
    1844         539 :     bool bFirstMulti = rInf.GetIdx() != rInf.GetLineStart();
    1845             : 
    1846         539 :     SwLinePortion *pNextFirst = NULL;
    1847         539 :     SwLinePortion *pNextSecond = NULL;
    1848         539 :     bool bRet = false;
    1849             : 
    1850         539 :     SwTextGridItem const*const pGrid(GetGridItem(pFrm->FindPageFrm()));
    1851         539 :     const bool bHasGrid = pGrid && GRID_LINES_CHARS == pGrid->GetGridType();
    1852             : 
    1853         539 :     bool bRubyTop = false;
    1854             : 
    1855         539 :     if ( bHasGrid )
    1856           0 :         bRubyTop = ! pGrid->GetRubyTextBelow();
    1857             : 
    1858             :     do
    1859             :     {
    1860         619 :         pCurr = &rMulti.GetRoot();
    1861         619 :         nStart = nStartIdx;
    1862         619 :         bRet = false;
    1863         619 :         FormatReset( aInf );
    1864         619 :         aInf.X( nTmpX );
    1865         619 :         aInf.Width( KSHORT(nActWidth) );
    1866         619 :         aInf.RealWidth( KSHORT(nActWidth) );
    1867         619 :         aInf.SetFirstMulti( bFirstMulti );
    1868         619 :         aInf.SetNumDone( rInf.IsNumDone() );
    1869         619 :         aInf.SetFtnDone( rInf.IsFtnDone() );
    1870             : 
    1871         619 :         if( pFirstRest )
    1872             :         {
    1873             :             OSL_ENSURE( pFirstRest->InFldGrp(), "BuildMulti: Fieldrest expected");
    1874             :             SwFldPortion *pFld =
    1875             :                 ((SwFldPortion*)pFirstRest)->Clone(
    1876         140 :                     ((SwFldPortion*)pFirstRest)->GetExp() );
    1877         140 :             pFld->SetFollow( true );
    1878         140 :             aInf.SetRest( pFld );
    1879             :         }
    1880         619 :         aInf.SetRuby( rMulti.IsRuby() && rMulti.OnTop() );
    1881             : 
    1882             :         // in grid mode we temporarily have to disable the grid for the ruby line
    1883         619 :         const bool bOldGridModeAllowed = GetInfo().SnapToGrid();
    1884         619 :         if ( bHasGrid && aInf.IsRuby() && bRubyTop )
    1885           0 :             aInf.SetSnapToGrid( false );
    1886             : 
    1887             :         // If there's no more rubytext, then buildportion is forbidden
    1888         619 :         if( pFirstRest || !aInf.IsRuby() )
    1889         619 :             BuildPortions( aInf );
    1890             : 
    1891         619 :         aInf.SetSnapToGrid( bOldGridModeAllowed );
    1892             : 
    1893         619 :         rMulti.CalcSize( *this, aInf );
    1894         619 :         pCurr->SetRealHeight( pCurr->Height() );
    1895             : 
    1896         619 :         if( rMulti.IsBidi() )
    1897             :         {
    1898          21 :             pNextFirst = aInf.GetRest();
    1899          21 :             break;
    1900             :         }
    1901             : 
    1902         598 :         if( rMulti.HasRotation() && !rMulti.IsDouble() )
    1903         340 :             break;
    1904             :         // second line has to be formatted
    1905         258 :         else if( pCurr->GetLen()<nMultiLen || rMulti.IsRuby() || aInf.GetRest())
    1906             :         {
    1907         208 :             sal_Int32 nFirstLen = pCurr->GetLen();
    1908         208 :             delete pCurr->GetNext();
    1909         208 :             pCurr->SetNext( new SwLineLayout() );
    1910         208 :             pCurr = pCurr->GetNext();
    1911         208 :             nStart = aInf.GetIdx();
    1912         208 :             aInf.X( nTmpX );
    1913         208 :             SwTxtFormatInfo aTmp( aInf, *pCurr, nActWidth );
    1914         208 :             if( rMulti.IsRuby() )
    1915             :             {
    1916         168 :                 aTmp.SetRuby( !rMulti.OnTop() );
    1917         168 :                 pNextFirst = aInf.GetRest();
    1918         168 :                 if( pSecondRest )
    1919             :                 {
    1920             :                     OSL_ENSURE( pSecondRest->InFldGrp(), "Fieldrest expected");
    1921             :                     SwFldPortion *pFld = ((SwFldPortion*)pSecondRest)->Clone(
    1922          28 :                                     ((SwFldPortion*)pSecondRest)->GetExp() );
    1923          28 :                     pFld->SetFollow( true );
    1924          28 :                     aTmp.SetRest( pFld );
    1925             :                 }
    1926         168 :                 if( !rMulti.OnTop() && nFirstLen < nMultiLen )
    1927           0 :                     bRet = true;
    1928             :             }
    1929             :             else
    1930          40 :                 aTmp.SetRest( aInf.GetRest() );
    1931         208 :             aInf.SetRest( NULL );
    1932             : 
    1933             :             // in grid mode we temporarily have to disable the grid for the ruby line
    1934         208 :             if ( bHasGrid && aTmp.IsRuby() && ! bRubyTop )
    1935           0 :                 aTmp.SetSnapToGrid( false );
    1936             : 
    1937         208 :             BuildPortions( aTmp );
    1938             : 
    1939         208 :             aTmp.SetSnapToGrid( bOldGridModeAllowed );
    1940             : 
    1941         208 :             rMulti.CalcSize( *this, aInf );
    1942         208 :             rMulti.GetRoot().SetRealHeight( rMulti.GetRoot().Height() );
    1943         208 :             pCurr->SetRealHeight( pCurr->Height() );
    1944         208 :             if( rMulti.IsRuby() )
    1945             :             {
    1946         168 :                 pNextSecond = aTmp.GetRest();
    1947         168 :                 if( pNextFirst )
    1948           0 :                     bRet = true;
    1949             :             }
    1950             :             else
    1951          40 :                 pNextFirst = aTmp.GetRest();
    1952         596 :             if( ( !aTmp.IsRuby() && nFirstLen + pCurr->GetLen() < nMultiLen )
    1953         376 :                 || aTmp.GetRest() )
    1954             :                 // our guess for width of multiportion was too small,
    1955             :                 // text did not fit into multiportion
    1956          40 :                 bRet = true;
    1957             :         }
    1958         258 :         if( rMulti.IsRuby() )
    1959         168 :             break;
    1960          90 :         if( bRet )
    1961             :         {
    1962             :             // our guess for multiportion width was too small,
    1963             :             // we set min to act
    1964          40 :             nMinWidth = nActWidth;
    1965          40 :             nActWidth = ( 3 * nMaxWidth + nMinWidth + 3 ) / 4;
    1966          40 :             if ( nActWidth == nMaxWidth && rInf.GetLineStart() == rInf.GetIdx() )
    1967             :             // we have too less space, we must allow break cuts
    1968             :             // ( the first multi flag is considered during TxtPortion::_Format() )
    1969           0 :                 bFirstMulti = false;
    1970          40 :             if( nActWidth <= nMinWidth )
    1971           0 :                 break;
    1972             :         }
    1973             :         else
    1974             :         {
    1975             :             // For Solaris, this optimization can causes trouble:
    1976             :             // Setting this to the portion width ( = rMulti.Width() )
    1977             :             // can make GetTextBreak inside SwTxtGuess::Guess return to small
    1978             :             // values. Therefore we add some extra twips.
    1979          50 :             if( nActWidth > nTmpX + rMulti.Width() + 6 )
    1980          10 :                 nActWidth = nTmpX + rMulti.Width() + 6;
    1981          50 :             nMaxWidth = nActWidth;
    1982          50 :             nActWidth = ( 3 * nMaxWidth + nMinWidth + 3 ) / 4;
    1983          50 :             if( nActWidth >= nMaxWidth )
    1984          10 :                 break;
    1985             :             // we do not allow break cuts during formatting
    1986          40 :             bFirstMulti = true;
    1987             :         }
    1988          80 :         delete pNextFirst;
    1989          80 :         pNextFirst = NULL;
    1990             :     } while ( true );
    1991             : 
    1992         539 :     pMulti = pOldMulti;
    1993             : 
    1994         539 :     pCurr = pOldCurr;
    1995         539 :     nStart = nOldStart;
    1996         539 :       SetPropFont( 0 );
    1997             : 
    1998         539 :     rMulti.SetLen( rMulti.GetRoot().GetLen() + ( rMulti.GetRoot().GetNext() ?
    1999         539 :         rMulti.GetRoot().GetNext()->GetLen() : 0 ) );
    2000             : 
    2001         539 :     if( rMulti.IsDouble() )
    2002             :     {
    2003          10 :         ((SwDoubleLinePortion&)rMulti).CalcBlanks( rInf );
    2004          10 :         if( ((SwDoubleLinePortion&)rMulti).GetLineDiff() )
    2005             :         {
    2006          10 :             SwLineLayout* pLine = &rMulti.GetRoot();
    2007          10 :             if( ((SwDoubleLinePortion&)rMulti).GetLineDiff() > 0 )
    2008             :             {
    2009          10 :                 rInf.SetIdx( nStartIdx + pLine->GetLen() );
    2010          10 :                 pLine = pLine->GetNext();
    2011             :             }
    2012          10 :             if( pLine )
    2013             :             {
    2014          10 :                 GetInfo().SetMulti( true );
    2015             : 
    2016             :                 // If the fourth element bSkipKashida of function CalcNewBlock is true, multiportion will be showed in justification.
    2017             :                 // Kashida (Persian) is a type of justification used in some cursive scripts, particularly Arabic.
    2018             :                 // In contrast to white-space justification, which increases the length of a line of text by expanding spaces between words or individual letters,
    2019             :                 // kashida justification is accomplished by elongating characters at certain chosen points.
    2020             :                 // Kashida justification can be combined with white-space justification to various extents.
    2021             :                 // The default value of bSkipKashida (the 4th parameter passed to 'CalcNewBlock') is false.
    2022             :                 // Only when Adjust is SVX_ADJUST_BLOCK ( alignment is justify ), multiportion will be showed in justification in new code.
    2023          10 :                 CalcNewBlock( pLine, NULL, rMulti.Width(), GetAdjust() != SVX_ADJUST_BLOCK );
    2024             : 
    2025          10 :                 GetInfo().SetMulti( false );
    2026             :             }
    2027          10 :             rInf.SetIdx( nStartIdx );
    2028             :         }
    2029          10 :         if( ((SwDoubleLinePortion&)rMulti).GetBrackets() )
    2030             :         {
    2031           8 :             rMulti.Width( rMulti.Width() +
    2032           8 :                     ((SwDoubleLinePortion&)rMulti).BracketWidth() );
    2033           8 :             GetInfo().X( nOldX );
    2034             :         }
    2035             :     }
    2036             :     else
    2037             :     {
    2038         529 :         rMulti.ActualizeTabulator();
    2039         529 :         if( rMulti.IsRuby() )
    2040             :         {
    2041         168 :             ((SwRubyPortion&)rMulti).Adjust( rInf );
    2042         168 :             ((SwRubyPortion&)rMulti).CalcRubyOffset();
    2043             :         }
    2044             :     }
    2045         539 :     if( rMulti.HasRotation() )
    2046             :     {
    2047         340 :         SwTwips nH = rMulti.Width();
    2048         340 :         SwTwips nAsc = rMulti.GetAscent() + ( nH - rMulti.Height() )/2;
    2049         340 :         if( nAsc > nH )
    2050         332 :             nAsc = nH;
    2051           8 :         else if( nAsc < 0 )
    2052           0 :             nAsc = 0;
    2053         340 :         rMulti.Width( rMulti.Height() );
    2054         340 :         rMulti.Height( KSHORT(nH) );
    2055         340 :         rMulti.SetAscent( KSHORT(nAsc) );
    2056         395 :         bRet = ( rInf.GetPos().X() + rMulti.Width() > rInf.Width() ) &&
    2057         395 :                  nStartIdx != rInf.GetLineStart();
    2058             :     }
    2059         199 :     else if ( rMulti.IsBidi() )
    2060             :     {
    2061          21 :         bRet = rMulti.GetLen() < nMultiLen || pNextFirst;
    2062             :     }
    2063             : 
    2064             :     // line break has to be performed!
    2065         539 :     if( bRet )
    2066             :     {
    2067             :         OSL_ENSURE( !pNextFirst || pNextFirst->InFldGrp(),
    2068             :             "BuildMultiPortion: Surprising restportion, field expected" );
    2069             :         SwMultiPortion *pTmp;
    2070          59 :         if( rMulti.IsDouble() )
    2071             :             pTmp = new SwDoubleLinePortion( ((SwDoubleLinePortion&)rMulti),
    2072           0 :                                             nMultiLen + rInf.GetIdx() );
    2073          59 :         else if( rMulti.IsRuby() )
    2074             :         {
    2075             :             OSL_ENSURE( !pNextSecond || pNextSecond->InFldGrp(),
    2076             :                 "BuildMultiPortion: Surprising restportion, field expected" );
    2077             : 
    2078           0 :             if ( rInf.GetIdx() == rInf.GetLineStart() )
    2079             :             {
    2080             :                 // the ruby portion has to be split in two portions
    2081             :                 pTmp = new SwRubyPortion( ((SwRubyPortion&)rMulti),
    2082           0 :                                           nMultiLen + rInf.GetIdx() );
    2083             : 
    2084           0 :                 if( pNextSecond )
    2085             :                 {
    2086           0 :                     pTmp->GetRoot().SetNext( new SwLineLayout() );
    2087           0 :                     pTmp->GetRoot().GetNext()->SetPortion( pNextSecond );
    2088             :                 }
    2089           0 :                 pTmp->SetFollowFld();
    2090             :             }
    2091             :             else
    2092             :             {
    2093             :                 // we try to keep our ruby portion together
    2094           0 :                 lcl_TruncateMultiPortion( rMulti, rInf, nStartIdx );
    2095           0 :                 pTmp = 0;
    2096             :             }
    2097             :         }
    2098          59 :         else if( rMulti.HasRotation() )
    2099             :         {
    2100             :             // we try to keep our rotated portion together
    2101          55 :             lcl_TruncateMultiPortion( rMulti, rInf, nStartIdx );
    2102          55 :             pTmp = new SwRotatedPortion( nMultiLen + rInf.GetIdx(),
    2103          55 :                                          rMulti.GetDirection() );
    2104             :         }
    2105             :         // during a recursion of BuildMultiPortions we may not build
    2106             :         // a new SwBidiPortion, this would cause a memory leak
    2107           4 :         else if( rMulti.IsBidi() && ! pMulti )
    2108             :         {
    2109           4 :             if ( ! rMulti.GetLen() )
    2110           0 :                 lcl_TruncateMultiPortion( rMulti, rInf, nStartIdx );
    2111             : 
    2112             :             // If there is a HolePortion at the end of the bidi portion,
    2113             :             // it has to be moved behind the bidi portion. Otherwise
    2114             :             // the visual cursor travelling gets into trouble.
    2115           4 :             SwLineLayout& aRoot = rMulti.GetRoot();
    2116           4 :             SwLinePortion* pPor = aRoot.GetFirstPortion();
    2117           8 :             while ( pPor )
    2118             :             {
    2119           4 :                 if ( pPor->GetPortion() && pPor->GetPortion()->IsHolePortion() )
    2120             :                 {
    2121           4 :                     SwLinePortion* pHolePor = pPor->GetPortion();
    2122           4 :                     pPor->SetPortion( NULL );
    2123           4 :                     aRoot.SetLen( aRoot.GetLen() - pHolePor->GetLen() );
    2124           4 :                     rMulti.SetLen( rMulti.GetLen() - pHolePor->GetLen() );
    2125           4 :                     rMulti.SetPortion( pHolePor );
    2126           4 :                     break;
    2127             :                 }
    2128           0 :                 pPor = pPor->GetPortion();
    2129             :             }
    2130             : 
    2131           4 :             pTmp = new SwBidiPortion( nMultiLen + rInf.GetIdx(),
    2132           4 :                                     ((SwBidiPortion&)rMulti).GetLevel() );
    2133             :         }
    2134             :         else
    2135           0 :             pTmp = NULL;
    2136             : 
    2137          59 :         if ( ! rMulti.GetLen() && rInf.GetLast() )
    2138             :         {
    2139          55 :             SeekAndChgBefore( rInf );
    2140          55 :             rInf.GetLast()->FormatEOL( rInf );
    2141             :         }
    2142             : 
    2143          59 :         if( pNextFirst && pTmp )
    2144             :         {
    2145           0 :             pTmp->SetFollowFld();
    2146           0 :             pTmp->GetRoot().SetPortion( pNextFirst );
    2147             :         }
    2148             :         else
    2149             :             // A follow field portion is still waiting. If nobody wants it,
    2150             :             // we delete it.
    2151          59 :             delete pNextFirst;
    2152             : 
    2153          59 :         rInf.SetRest( pTmp );
    2154             :     }
    2155             : 
    2156         539 :     rInf.SetTxt( *pOldTxt );
    2157         539 :     rInf.SetPaintOfst( nOldPaintOfst );
    2158         539 :     rInf.SetStop( aInf.IsStop() );
    2159         539 :     rInf.SetNumDone( true );
    2160         539 :     rInf.SetFtnDone( true );
    2161         539 :     SeekAndChg( rInf );
    2162         539 :     delete pFirstRest;
    2163         539 :     delete pSecondRest;
    2164         539 :     xFontSave.reset();
    2165        1078 :     return bRet;
    2166             : }
    2167             : 
    2168             : /*--------------------------------------------------
    2169             :  * SwTxtFormatter::MakeRestPortion(..)
    2170             :  * When a fieldportion at the end of line breaks and needs a following
    2171             :  * fieldportion in the next line, then the "restportion" of the formatinfo
    2172             :  * has to be set. Normally this happens during the formatting of the first
    2173             :  * part of the fieldportion.
    2174             :  * But sometimes the formatting starts at the line with the following part,
    2175             :  * especially when the following part is on the next page.
    2176             :  * In this case the MakeRestPortion-function has to create the following part.
    2177             :  * The first parameter is the line that contains possibly a first part
    2178             :  * of a field. When the function finds such field part, it creates the right
    2179             :  * restportion. This may be a multiportion, e.g. if the field is surrounded by
    2180             :  * a doubleline- or ruby-portion.
    2181             :  * The second parameter is the start index of the line.
    2182             :  * --------------------------------------------------*/
    2183             : 
    2184          67 : SwLinePortion* SwTxtFormatter::MakeRestPortion( const SwLineLayout* pLine,
    2185             :     sal_Int32 nPosition )
    2186             : {
    2187          67 :     if( !nPosition )
    2188           0 :         return NULL;
    2189          67 :     sal_Int32 nMultiPos = nPosition - pLine->GetLen();
    2190          67 :     const SwMultiPortion *pTmpMulti = NULL;
    2191          67 :     const SwMultiPortion *pHelpMulti = NULL;
    2192          67 :     const SwLinePortion* pPor = pLine->GetFirstPortion();
    2193          67 :     SwFldPortion *pFld = NULL;
    2194         201 :     while( pPor )
    2195             :     {
    2196          67 :         if( pPor->GetLen() )
    2197             :         {
    2198          67 :             if( !pHelpMulti )
    2199             :             {
    2200          67 :                 nMultiPos = nMultiPos + pPor->GetLen();
    2201          67 :                 pTmpMulti = NULL;
    2202             :             }
    2203             :         }
    2204          67 :         if( pPor->InFldGrp() )
    2205             :         {
    2206           0 :             if( !pHelpMulti )
    2207           0 :                 pTmpMulti = NULL;
    2208           0 :             pFld = (SwFldPortion*)pPor;
    2209             :         }
    2210          67 :         else if( pPor->IsMultiPortion() )
    2211             :         {
    2212             :             OSL_ENSURE( !pHelpMulti || pHelpMulti->IsBidi(),
    2213             :                     "Nested multiportions are forbidden." );
    2214             : 
    2215           0 :             pFld = NULL;
    2216           0 :             pTmpMulti = (SwMultiPortion*)pPor;
    2217             :         }
    2218          67 :         pPor = pPor->GetPortion();
    2219             :         // If the last portion is a multi-portion, we enter it
    2220             :         // and look for a field portion inside.
    2221             :         // If we are already in a multiportion, we could change to the
    2222             :         // next line
    2223          67 :         if( !pPor && pTmpMulti )
    2224             :         {
    2225           0 :             if( pHelpMulti )
    2226             :             {   // We're already inside the multiportion, let's take the second
    2227             :                 // line, if we are in a double line portion
    2228           0 :                 if( !pHelpMulti->IsRuby() )
    2229           0 :                     pPor = pHelpMulti->GetRoot().GetNext();
    2230           0 :                 pTmpMulti = NULL;
    2231             :             }
    2232             :             else
    2233             :             {   // Now we enter a multiportion, in a ruby portion we take the
    2234             :                 // main line, not the phonetic line, in a doublelineportion we
    2235             :                 // starts with the first line.
    2236           0 :                 pHelpMulti = pTmpMulti;
    2237           0 :                 nMultiPos = nMultiPos - pHelpMulti->GetLen();
    2238           0 :                 if( pHelpMulti->IsRuby() && pHelpMulti->OnTop() )
    2239           0 :                     pPor = pHelpMulti->GetRoot().GetNext();
    2240             :                 else
    2241           0 :                     pPor = pHelpMulti->GetRoot().GetFirstPortion();
    2242             :             }
    2243             :         }
    2244             :     }
    2245          67 :     if( pFld && !pFld->HasFollow() )
    2246           0 :         pFld = NULL;
    2247             : 
    2248          67 :     SwLinePortion *pRest = NULL;
    2249          67 :     if( pFld )
    2250             :     {
    2251           0 :         const SwTxtAttr *pHint = GetAttr( nPosition - 1 );
    2252           0 :         if ( pHint
    2253           0 :              && ( pHint->Which() == RES_TXTATR_FIELD
    2254           0 :                   || pHint->Which() == RES_TXTATR_ANNOTATION ) )
    2255             :         {
    2256           0 :             pRest = NewFldPortion( GetInfo(), pHint );
    2257           0 :             if( pRest->InFldGrp() )
    2258           0 :                 ((SwFldPortion*)pRest)->TakeNextOffset( pFld );
    2259             :             else
    2260             :             {
    2261           0 :                 delete pRest;
    2262           0 :                 pRest = NULL;
    2263             :             }
    2264             :         }
    2265             :     }
    2266          67 :     if( !pHelpMulti )
    2267          67 :         return pRest;
    2268             : 
    2269           0 :     nPosition = nMultiPos + pHelpMulti->GetLen();
    2270           0 :     SwMultiCreator* pCreate = GetInfo().GetMultiCreator( nMultiPos, 0 );
    2271             : 
    2272           0 :     if ( !pCreate )
    2273             :     {
    2274             :         OSL_ENSURE( !pHelpMulti->GetLen(), "Multiportion without attribut?" );
    2275           0 :         if ( nMultiPos )
    2276           0 :             --nMultiPos;
    2277           0 :         pCreate = GetInfo().GetMultiCreator( --nMultiPos, 0 );
    2278             :     }
    2279             : 
    2280           0 :     if (!pCreate)
    2281           0 :         return pRest;
    2282             : 
    2283           0 :     if( pRest || nMultiPos > nPosition || ( pHelpMulti->IsRuby() &&
    2284           0 :         ((SwRubyPortion*)pHelpMulti)->GetRubyOffset() < COMPLETE_STRING ) )
    2285             :     {
    2286             :         SwMultiPortion* pTmp;
    2287           0 :         if( pHelpMulti->IsDouble() )
    2288           0 :             pTmp = new SwDoubleLinePortion( *pCreate, nMultiPos );
    2289           0 :         else if( pHelpMulti->IsBidi() )
    2290           0 :             pTmp = new SwBidiPortion( nMultiPos, pCreate->nLevel );
    2291           0 :         else if( pHelpMulti->IsRuby() )
    2292             :         {
    2293             :             bool bRubyTop;
    2294           0 :             bool* pRubyPos = 0;
    2295             : 
    2296           0 :             if ( GetInfo().SnapToGrid() )
    2297             :             {
    2298             :                 SwTextGridItem const*const pGrid(
    2299           0 :                         GetGridItem(pFrm->FindPageFrm()));
    2300           0 :                 if ( pGrid )
    2301             :                 {
    2302           0 :                     bRubyTop = ! pGrid->GetRubyTextBelow();
    2303           0 :                     pRubyPos = &bRubyTop;
    2304             :                 }
    2305             :             }
    2306             : 
    2307           0 :             pTmp = new SwRubyPortion( *pCreate, *GetInfo().GetFont(),
    2308           0 :                                       *pFrm->GetTxtNode()->getIDocumentSettingAccess(),
    2309             :                                        nMultiPos, ((SwRubyPortion*)pHelpMulti)->GetRubyOffset(),
    2310           0 :                                        pRubyPos );
    2311             :         }
    2312           0 :         else if( pHelpMulti->HasRotation() )
    2313           0 :             pTmp = new SwRotatedPortion( nMultiPos, pHelpMulti->GetDirection() );
    2314             :         else
    2315             :         {
    2316           0 :             delete pCreate;
    2317           0 :             return pRest;
    2318             :         }
    2319           0 :         delete pCreate;
    2320           0 :         pTmp->SetFollowFld();
    2321           0 :         if( pRest )
    2322             :         {
    2323           0 :             SwLineLayout *pLay = &pTmp->GetRoot();
    2324           0 :             if( pTmp->IsRuby() && pTmp->OnTop() )
    2325             :             {
    2326           0 :                 pLay->SetNext( new SwLineLayout() );
    2327           0 :                 pLay = pLay->GetNext();
    2328             :             }
    2329           0 :             pLay->SetPortion( pRest );
    2330             :         }
    2331           0 :         return pTmp;
    2332             :     }
    2333           0 :     delete (pCreate);
    2334           0 :     return pRest;
    2335             : }
    2336             : 
    2337             : /*--------------------------------------------------
    2338             :  * SwTxtCursorSave notes the start and current line of a SwTxtCursor,
    2339             :  * sets them to the values for GetCrsrOfst inside a multiportion
    2340             :  * and restores them in the destructor.
    2341             :  * --------------------------------------------------*/
    2342             : 
    2343           0 : SwTxtCursorSave::SwTxtCursorSave( SwTxtCursor* pTxtCursor,
    2344             :                                   SwMultiPortion* pMulti,
    2345             :                                   SwTwips nY,
    2346             :                                   sal_uInt16& nX,
    2347             :                                   sal_Int32 nCurrStart,
    2348             :                                   long nSpaceAdd )
    2349             : {
    2350           0 :     pTxtCrsr = pTxtCursor;
    2351           0 :     nStart = pTxtCursor->nStart;
    2352           0 :     pTxtCursor->nStart = nCurrStart;
    2353           0 :     pCurr = pTxtCursor->pCurr;
    2354           0 :     pTxtCursor->pCurr = &pMulti->GetRoot();
    2355           0 :     while( pTxtCursor->Y() + pTxtCursor->GetLineHeight() < nY &&
    2356           0 :         pTxtCursor->Next() )
    2357             :         ; // nothing
    2358           0 :     nWidth = pTxtCursor->pCurr->Width();
    2359           0 :     nOldProp = pTxtCursor->GetPropFont();
    2360             : 
    2361           0 :     if ( pMulti->IsDouble() || pMulti->IsBidi() )
    2362             :     {
    2363           0 :         bSpaceChg = pMulti->ChgSpaceAdd( pTxtCursor->pCurr, nSpaceAdd );
    2364             : 
    2365             :         sal_uInt16 nSpaceCnt;
    2366           0 :         if ( pMulti->IsDouble() )
    2367             :         {
    2368           0 :             pTxtCursor->SetPropFont( 50 );
    2369           0 :             nSpaceCnt = ((SwDoubleLinePortion*)pMulti)->GetSpaceCnt();
    2370             :         }
    2371             :         else
    2372             :         {
    2373           0 :             const sal_Int32 nOldIdx = pTxtCursor->GetInfo().GetIdx();
    2374           0 :             pTxtCursor->GetInfo().SetIdx ( nCurrStart );
    2375           0 :             nSpaceCnt = ((SwBidiPortion*)pMulti)->GetSpaceCnt(pTxtCursor->GetInfo());
    2376           0 :             pTxtCursor->GetInfo().SetIdx ( nOldIdx );
    2377             :         }
    2378             : 
    2379           0 :         if( nSpaceAdd > 0 && !pMulti->HasTabulator() )
    2380           0 :             pTxtCursor->pCurr->Width( static_cast<sal_uInt16>(nWidth + nSpaceAdd * nSpaceCnt / SPACING_PRECISION_FACTOR ) );
    2381             : 
    2382             :         // For a BidiPortion we have to calculate the offset from the
    2383             :         // end of the portion
    2384           0 :         if ( nX && pMulti->IsBidi() )
    2385           0 :             nX = pTxtCursor->pCurr->Width() - nX;
    2386             :     }
    2387             :     else
    2388           0 :         bSpaceChg = false;
    2389           0 : }
    2390             : 
    2391           0 : SwTxtCursorSave::~SwTxtCursorSave()
    2392             : {
    2393           0 :     if( bSpaceChg )
    2394           0 :         SwDoubleLinePortion::ResetSpaceAdd( pTxtCrsr->pCurr );
    2395           0 :     pTxtCrsr->pCurr->Width( KSHORT(nWidth) );
    2396           0 :     pTxtCrsr->pCurr = pCurr;
    2397           0 :     pTxtCrsr->nStart = nStart;
    2398           0 :     pTxtCrsr->SetPropFont( nOldProp );
    2399           0 : }
    2400             : 
    2401             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10