LCOV - code coverage report
Current view: top level - usr/local/src/libreoffice/sw/source/core/text - pormulti.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 783 1209 64.8 %
Date: 2013-07-09 Functions: 29 44 65.9 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10