LCOV - code coverage report
Current view: top level - libreoffice/editeng/source/editeng - impedit3.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 1183 2287 51.7 %
Date: 2012-12-27 Functions: 42 64 65.6 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : 
      20             : 
      21             : #include <vcl/wrkwin.hxx>
      22             : #include <vcl/dialog.hxx>
      23             : #include <vcl/msgbox.hxx>
      24             : #include <vcl/svapp.hxx>
      25             : #include <vcl/metaact.hxx>
      26             : #include <vcl/gdimtf.hxx>
      27             : 
      28             : #include <editeng/adjitem.hxx>
      29             : #include <editeng/tstpitem.hxx>
      30             : #include <editeng/lspcitem.hxx>
      31             : #include <editeng/flditem.hxx>
      32             : #include <impedit.hxx>
      33             : #include <editeng/editeng.hxx>
      34             : #include <editeng/editview.hxx>
      35             : #include <editeng/txtrange.hxx>
      36             : #include <editeng/cscoitem.hxx>
      37             : #include <editeng/colritem.hxx>
      38             : #include <editeng/udlnitem.hxx>
      39             : #include <editeng/fhgtitem.hxx>
      40             : #include <editeng/kernitem.hxx>
      41             : #include <editeng/lrspitem.hxx>
      42             : #include <editeng/ulspitem.hxx>
      43             : #include <editeng/fontitem.hxx>
      44             : #include <editeng/wghtitem.hxx>
      45             : #include <editeng/postitem.hxx>
      46             : #include <editeng/langitem.hxx>
      47             : #include <editeng/scriptspaceitem.hxx>
      48             : #include <editeng/charscaleitem.hxx>
      49             : #include <editeng/numitem.hxx>
      50             : #include <editeng/justifyitem.hxx>
      51             : 
      52             : #include <svtools/colorcfg.hxx>
      53             : #include <svl/ctloptions.hxx>
      54             : 
      55             : #include <editeng/forbiddencharacterstable.hxx>
      56             : 
      57             : #include <unotools/localedatawrapper.hxx>
      58             : 
      59             : #include <editeng/unolingu.hxx>
      60             : 
      61             : #include <set>
      62             : #include <math.h>
      63             : #include <vcl/metric.hxx>
      64             : #include <com/sun/star/i18n/BreakIterator.hpp>
      65             : #include <com/sun/star/i18n/ScriptType.hpp>
      66             : #include <com/sun/star/text/CharacterCompressionType.hpp>
      67             : #include <vcl/pdfextoutdevdata.hxx>
      68             : #include <i18npool/mslangid.hxx>
      69             : 
      70             : #include <comphelper/processfactory.hxx>
      71             : #include <rtl/ustrbuf.hxx>
      72             : #include <comphelper/string.hxx>
      73             : 
      74             : using ::rtl::OUString;
      75             : using namespace ::com::sun::star;
      76             : using namespace ::com::sun::star::uno;
      77             : using namespace ::com::sun::star::beans;
      78             : using namespace ::com::sun::star::linguistic2;
      79             : 
      80             : #define CH_HYPH     '-'
      81             : 
      82             : #define RESDIFF     10
      83             : 
      84             : #define WRONG_SHOW_MIN       5
      85             : #define WRONG_SHOW_SMALL    11
      86             : #define WRONG_SHOW_MEDIUM   15
      87             : 
      88             : struct TabInfo
      89             : {
      90             :     sal_Bool        bValid;
      91             : 
      92             :     SvxTabStop  aTabStop;
      93             :     xub_StrLen  nCharPos;
      94             :     sal_uInt16      nTabPortion;
      95             :     long        nStartPosX;
      96             :     long        nTabPos;
      97             : 
      98        7058 :     TabInfo() { bValid = sal_False; }
      99             : };
     100             : 
     101           0 : Point Rotate( const Point& rPoint, short nOrientation, const Point& rOrigin )
     102             : {
     103           0 :     double nRealOrientation = nOrientation*F_PI1800;
     104           0 :     double nCos = cos( nRealOrientation );
     105           0 :     double nSin = sin( nRealOrientation );
     106             : 
     107           0 :     Point aRotatedPos;
     108           0 :     Point aTranslatedPos( rPoint );
     109             : 
     110             :     // Translation
     111           0 :     aTranslatedPos -= rOrigin;
     112             : 
     113             :     // Rotation...
     114           0 :     aRotatedPos.X() = (long)   ( nCos*aTranslatedPos.X() + nSin*aTranslatedPos.Y() );
     115           0 :     aRotatedPos.Y() = (long) - ( nSin*aTranslatedPos.X() - nCos*aTranslatedPos.Y() );
     116           0 :     aTranslatedPos = aRotatedPos;
     117             : 
     118             :     // Translation...
     119           0 :     aTranslatedPos += rOrigin;
     120           0 :     return aTranslatedPos;
     121             : }
     122             : 
     123           0 : sal_uInt8 GetCharTypeForCompression( sal_Unicode cChar )
     124             : {
     125           0 :     switch ( cChar )
     126             :     {
     127             :         case 0x3008: case 0x300A: case 0x300C: case 0x300E:
     128             :         case 0x3010: case 0x3014: case 0x3016: case 0x3018:
     129             :         case 0x301A: case 0x301D:
     130             :         {
     131           0 :             return CHAR_PUNCTUATIONRIGHT;
     132             :         }
     133             :         case 0x3001: case 0x3002: case 0x3009: case 0x300B:
     134             :         case 0x300D: case 0x300F: case 0x3011: case 0x3015:
     135             :         case 0x3017: case 0x3019: case 0x301B: case 0x301E:
     136             :         case 0x301F:
     137             :         {
     138           0 :             return CHAR_PUNCTUATIONLEFT;
     139             :         }
     140             :         default:
     141             :         {
     142           0 :             return ( ( 0x3040 <= cChar ) && ( 0x3100 > cChar ) ) ? CHAR_KANA : CHAR_NORMAL;
     143             :         }
     144             :     }
     145             : }
     146             : 
     147           0 : static void lcl_DrawRedLines(
     148             :     OutputDevice* pOutDev,
     149             :     long nFontHeight,
     150             :     const Point& rPnt,
     151             :     sal_uInt16 nIndex,
     152             :     sal_uInt16 nMaxEnd,
     153             :     const sal_Int32* pDXArray,
     154             :     WrongList* pWrongs,
     155             :     short nOrientation,
     156             :     const Point& rOrigin,
     157             :     sal_Bool bVertical,
     158             :     sal_Bool bIsRightToLeft )
     159             : {
     160             :     // But only if font is not too small ...
     161           0 :     long nHght = pOutDev->LogicToPixel( Size( 0, nFontHeight ) ).Height();
     162           0 :     if( WRONG_SHOW_MIN < nHght )
     163             :     {
     164             :         sal_uInt16 nStyle;
     165           0 :         if( WRONG_SHOW_MEDIUM < nHght )
     166           0 :             nStyle = WAVE_NORMAL;
     167           0 :         else if( WRONG_SHOW_SMALL < nHght )
     168           0 :             nStyle = WAVE_SMALL;
     169             :         else
     170           0 :             nStyle = WAVE_FLAT;
     171             : 
     172           0 :         sal_uInt16 nEnd, nStart = nIndex;
     173           0 :         sal_Bool bWrong = pWrongs->NextWrong( nStart, nEnd );
     174           0 :         while ( bWrong )
     175             :         {
     176           0 :             if ( nStart >= nMaxEnd )
     177             :                 break;
     178             : 
     179           0 :             if ( nStart < nIndex )  // Corrected
     180           0 :                 nStart = nIndex;
     181           0 :             if ( nEnd > nMaxEnd )
     182           0 :                 nEnd = nMaxEnd;
     183           0 :             Point aPnt1( rPnt );
     184           0 :             if ( bVertical && ( nStyle != WAVE_FLAT ) )
     185             :             {
     186             :                 // VCL doesn't know that the text is vertical, and is manipulating
     187             :                 // the positions a little bit in y direction...
     188           0 :                 long nOnePixel = pOutDev->PixelToLogic( Size( 0, 1 ) ).Height();
     189           0 :                 long nCorrect = ( nStyle == WAVE_NORMAL ) ? 2*nOnePixel : nOnePixel;
     190           0 :                 aPnt1.Y() -= nCorrect;
     191           0 :                 aPnt1.X() -= nCorrect;
     192             :             }
     193           0 :             if ( nStart > nIndex )
     194             :             {
     195           0 :                 if ( !bVertical )
     196             :                 {
     197             :                     // since for RTL portions rPnt is on the visual right end of the portion
     198             :                     // (i.e. at the start of the first RTL char) we need to subtract the offset
     199             :                     // for RTL portions...
     200           0 :                     aPnt1.X() += (bIsRightToLeft ? -1 : 1) * pDXArray[ nStart - nIndex - 1 ];
     201             :                 }
     202             :                 else
     203           0 :                     aPnt1.Y() += pDXArray[ nStart - nIndex - 1 ];
     204             :             }
     205           0 :             Point aPnt2( rPnt );
     206             :             DBG_ASSERT( nEnd > nIndex, "RedLine: aPnt2?" );
     207           0 :             if ( !bVertical )
     208             :             {
     209             :                 // since for RTL portions rPnt is on the visual right end of the portion
     210             :                 // (i.e. at the start of the first RTL char) we need to subtract the offset
     211             :                 // for RTL portions...
     212           0 :                 aPnt2.X() += (bIsRightToLeft ? -1 : 1) * pDXArray[ nEnd - nIndex - 1 ];
     213             :             }
     214             :             else
     215           0 :                 aPnt2.Y() += pDXArray[ nEnd - nIndex - 1 ];
     216           0 :             if ( nOrientation )
     217             :             {
     218           0 :                 aPnt1 = Rotate( aPnt1, nOrientation, rOrigin );
     219           0 :                 aPnt2 = Rotate( aPnt2, nOrientation, rOrigin );
     220             :             }
     221             : 
     222           0 :             pOutDev->DrawWaveLine( aPnt1, aPnt2, nStyle );
     223             : 
     224           0 :             nStart = nEnd+1;
     225           0 :             if ( nEnd < nMaxEnd )
     226           0 :                 bWrong = pWrongs->NextWrong( nStart, nEnd );
     227             :             else
     228           0 :                 bWrong = sal_False;
     229             :         }
     230             :     }
     231           0 : }
     232             : 
     233           0 : static Point lcl_ImplCalcRotatedPos( Point rPos, Point rOrigin, double nSin, double nCos )
     234             : {
     235           0 :     Point aRotatedPos;
     236             :     // Translation...
     237           0 :     Point aTranslatedPos( rPos);
     238           0 :     aTranslatedPos -= rOrigin;
     239             : 
     240           0 :     aRotatedPos.X() = (long)   ( nCos*aTranslatedPos.X() + nSin*aTranslatedPos.Y() );
     241           0 :     aRotatedPos.Y() = (long) - ( nSin*aTranslatedPos.X() - nCos*aTranslatedPos.Y() );
     242           0 :     aTranslatedPos = aRotatedPos;
     243             :     // Translation...
     244           0 :     aTranslatedPos += rOrigin;
     245             : 
     246           0 :     return aTranslatedPos;
     247             : }
     248             : 
     249           0 : static sal_Bool lcl_IsLigature( sal_Unicode cCh, sal_Unicode cNextCh ) // For Kashidas from sw/source/core/text/porlay.txt
     250             : {
     251             :             // Lam + Alef
     252             :     return ( 0x644 == cCh && 0x627 == cNextCh ) ||
     253             :             // Beh + Reh
     254           0 :            ( 0x628 == cCh && 0x631 == cNextCh );
     255             : }
     256             : 
     257           0 : static sal_Bool lcl_ConnectToPrev( sal_Unicode cCh, sal_Unicode cPrevCh )  // For Kashidas from sw/source/core/text/porlay.txt
     258             : {
     259             :     // Alef, Dal, Thal, Reh, Zain, and Waw do not connect to the left
     260             :     sal_Bool bRet = 0x627 != cPrevCh && 0x62F != cPrevCh && 0x630 != cPrevCh &&
     261           0 :                     0x631 != cPrevCh && 0x632 != cPrevCh && 0x648 != cPrevCh;
     262             : 
     263             :     // check for ligatures cPrevChar + cChar
     264           0 :     if ( bRet )
     265           0 :         bRet = ! lcl_IsLigature( cPrevCh, cCh );
     266             : 
     267           0 :     return bRet;
     268             : }
     269             : 
     270             : 
     271             : //  ----------------------------------------------------------------------
     272             : //  class ImpEditEngine
     273             : //  ----------------------------------------------------------------------
     274      115104 : void ImpEditEngine::UpdateViews( EditView* pCurView )
     275             : {
     276      115104 :     if ( !GetUpdateMode() || IsFormatting() || aInvalidRec.IsEmpty() )
     277      205727 :         return;
     278             : 
     279             :     DBG_ASSERT( IsFormatted(), "UpdateViews: Doc not formatted!" );
     280             : 
     281       24537 :     for (size_t nView = 0; nView < aEditViews.size(); ++nView)
     282             :     {
     283          56 :         EditView* pView = aEditViews[nView];
     284             :         DBG_CHKOBJ( pView, EditView, 0 );
     285          56 :         pView->HideCursor();
     286             : 
     287          56 :         Rectangle aClipRec( aInvalidRec );
     288          56 :         Rectangle aVisArea( pView->GetVisArea() );
     289          56 :         aClipRec.Intersection( aVisArea );
     290             : 
     291          56 :         if ( !aClipRec.IsEmpty() )
     292             :         {
     293             :             // convert to window coordinates ....
     294          56 :             aClipRec = pView->pImpEditView->GetWindowPos( aClipRec );
     295             : 
     296          56 :             if ( pView == pCurView )
     297          31 :                 Paint( pView->pImpEditView, aClipRec, sal_True );
     298             :             else
     299          25 :                 pView->GetWindow()->Invalidate( aClipRec );
     300             :         }
     301             :     }
     302             : 
     303       24481 :     if ( pCurView )
     304             :     {
     305          31 :         sal_Bool bGotoCursor = pCurView->pImpEditView->DoAutoScroll();
     306          31 :         pCurView->ShowCursor( bGotoCursor );
     307             :     }
     308             : 
     309       24481 :     aInvalidRec = Rectangle();
     310       24481 :     CallStatusHdl();
     311             : }
     312             : 
     313           6 : IMPL_LINK_NOARG(ImpEditEngine, OnlineSpellHdl)
     314             : {
     315           3 :     if ( !Application::AnyInput( VCL_INPUT_KEYBOARD ) && GetUpdateMode() && IsFormatted() )
     316           3 :         DoOnlineSpelling();
     317             :     else
     318           0 :         aOnlineSpellTimer.Start();
     319             : 
     320           3 :     return 0;
     321             : }
     322             : 
     323           0 : IMPL_LINK_NOARG_INLINE_START(ImpEditEngine, IdleFormatHdl)
     324             : {
     325           0 :     aIdleFormatter.ResetRestarts();
     326             : 
     327             :     // #i97146# check if that view is still available
     328             :     // else probably the idle format timer fired while we're already
     329             :     // downing
     330           0 :     EditView* pView = aIdleFormatter.GetView();
     331           0 :     for (size_t nView = 0; nView < aEditViews.size(); ++nView)
     332             :     {
     333           0 :         if( aEditViews[nView] == pView )
     334             :         {
     335           0 :             FormatAndUpdate( pView );
     336           0 :             break;
     337             :         }
     338             :     }
     339           0 :     return 0;
     340             : }
     341           0 : IMPL_LINK_NOARG_INLINE_END(ImpEditEngine, IdleFormatHdl)
     342             : 
     343         134 : void ImpEditEngine::CheckIdleFormatter()
     344             : {
     345         134 :     aIdleFormatter.ForceTimeout();
     346             :     // If not idle, but still not formatted:
     347         134 :     if ( !IsFormatted() )
     348           9 :         FormatDoc();
     349         134 : }
     350             : 
     351       14008 : void ImpEditEngine::FormatFullDoc()
     352             : {
     353       28022 :     for ( sal_uInt16 nPortion = 0; nPortion < GetParaPortions().Count(); nPortion++ )
     354       14014 :         GetParaPortions()[nPortion]->MarkSelectionInvalid( 0, GetParaPortions()[nPortion]->GetNode()->Len() );
     355       14008 :     FormatDoc();
     356       14008 : }
     357             : 
     358      117794 : void ImpEditEngine::FormatDoc()
     359             : {
     360      117794 :     if ( !GetUpdateMode() || IsFormatting() )
     361      117794 :         return;
     362             : 
     363       27101 :     EnterBlockNotifications();
     364             : 
     365       27101 :     bIsFormatting = true;
     366             : 
     367             :     // Then I can also start the spell-timer ...
     368       27101 :     if ( GetStatus().DoOnlineSpelling() )
     369        7417 :         StartOnlineSpellTimer();
     370             : 
     371       27101 :     long nY = 0;
     372       27101 :     sal_Bool bGrow = sal_False;
     373             : 
     374       27101 :     Font aOldFont( GetRefDevice()->GetFont() );
     375             : 
     376             :     // Here already, so that not always in CreateLines...
     377       27101 :     sal_Bool bMapChanged = ImpCheckRefMapMode();
     378             : 
     379       27101 :     aInvalidRec = Rectangle();  // make empty
     380       54809 :     for ( sal_uInt16 nPara = 0; nPara < GetParaPortions().Count(); nPara++ )
     381             :     {
     382       27708 :         ParaPortion* pParaPortion = GetParaPortions()[nPara];
     383       27708 :         if ( pParaPortion->MustRepaint() || ( pParaPortion->IsInvalid() && pParaPortion->IsVisible() ) )
     384             :         {
     385       25090 :             if ( pParaPortion->IsInvalid() )
     386             :             {
     387       25090 :                 sal_Bool bChangedByDerivedClass = GetEditEnginePtr()->FormattingParagraph( nPara );
     388       25090 :                 if ( bChangedByDerivedClass )
     389             :                 {
     390           0 :                     pParaPortion->GetTextPortions().Reset();
     391           0 :                     pParaPortion->MarkSelectionInvalid( 0, pParaPortion->GetNode()->Len() );
     392             :                 }
     393             :             }
     394             :             // No formatting should be necessary for MustRepaint()!
     395       50180 :             if ( ( pParaPortion->MustRepaint() && !pParaPortion->IsInvalid() )
     396       25090 :                     || CreateLines( nPara, nY ) )
     397             :             {
     398       19465 :                 if ( !bGrow && GetTextRanger() )
     399             :                 {
     400             :                     // For a change in height all below must be reformatted ...
     401           0 :                     for ( sal_uInt16 n = nPara+1; n < GetParaPortions().Count(); n++ )
     402             :                     {
     403           0 :                         ParaPortion* pPP = GetParaPortions()[n];
     404           0 :                         pPP->MarkSelectionInvalid( 0, pPP->GetNode()->Len() );
     405           0 :                         pPP->GetLines().Reset();
     406             :                     }
     407             :                 }
     408       19465 :                 bGrow = sal_True;
     409       19465 :                 if ( IsCallParaInsertedOrDeleted() )
     410       19465 :                     GetEditEnginePtr()->ParagraphHeightChanged( nPara );
     411       19465 :                 pParaPortion->SetMustRepaint( sal_False );
     412             :             }
     413             : 
     414             :             // InvalidRec set only once...
     415       25090 :             if ( aInvalidRec.IsEmpty() )
     416             :             {
     417             :                 // For Paperwidth 0 (AutoPageSize) it would otherwise be Empty()...
     418       24486 :                 long nWidth = Max( (long)1, ( !IsVertical() ? aPaperSize.Width() : aPaperSize.Height() ) );
     419       24486 :                 Range aInvRange( GetInvalidYOffsets( pParaPortion ) );
     420       24486 :                 aInvalidRec = Rectangle( Point( 0, nY+aInvRange.Min() ),
     421       48972 :                     Size( nWidth, aInvRange.Len() ) );
     422             :             }
     423             :             else
     424             :             {
     425         604 :                 aInvalidRec.Bottom() = nY + pParaPortion->GetHeight();
     426             :             }
     427             :         }
     428        2618 :         else if ( bGrow )
     429             :         {
     430           0 :             aInvalidRec.Bottom() = nY + pParaPortion->GetHeight();
     431             :         }
     432       27708 :         nY += pParaPortion->GetHeight();
     433             :     }
     434             : 
     435             :     // One can also get into the formatting through UpdateMode ON=>OFF=>ON...
     436             :     // enable optimization first after Vobis delivery ...
     437             :     {
     438             :         sal_uInt32 nNewHeightNTP;
     439       27101 :         sal_uInt32 nNewHeight = CalcTextHeight( &nNewHeightNTP );
     440       27101 :         long nDiff = nNewHeight - nCurTextHeight;
     441       27101 :         if ( nDiff )
     442       18918 :             aStatus.GetStatusWord() |= !IsVertical() ? EE_STAT_TEXTHEIGHTCHANGED : EE_STAT_TEXTWIDTHCHANGED;
     443       27101 :         if ( nNewHeight < nCurTextHeight )
     444             :         {
     445          44 :             aInvalidRec.Bottom() = (long)Max( nNewHeight, nCurTextHeight );
     446          44 :             if ( aInvalidRec.IsEmpty() )
     447             :             {
     448           0 :                 aInvalidRec.Top() = 0;
     449             :                 // Left and Right are not evaluated, are however set due to IsEmpty.
     450           0 :                 aInvalidRec.Left() = 0;
     451           0 :                 aInvalidRec.Right() = !IsVertical() ? aPaperSize.Width() : aPaperSize.Height();
     452             :             }
     453             :         }
     454             : 
     455       27101 :         nCurTextHeight = nNewHeight;
     456       27101 :         nCurTextHeightNTP = nNewHeightNTP;
     457             : 
     458       27101 :         if ( aStatus.AutoPageSize() )
     459         218 :             CheckAutoPageSize();
     460       26883 :         else if ( nDiff )
     461             :         {
     462       18746 :             for (size_t nView = 0; nView < aEditViews.size(); ++nView)
     463             :             {
     464          16 :                 EditView* pView = aEditViews[nView];
     465          16 :                 ImpEditView* pImpView = pView->pImpEditView;
     466          16 :                 if ( pImpView->DoAutoHeight() )
     467             :                 {
     468           0 :                     Size aSz( pImpView->GetOutputArea().GetWidth(), nCurTextHeight );
     469           0 :                     if ( aSz.Height() > aMaxAutoPaperSize.Height() )
     470           0 :                         aSz.Height() = aMaxAutoPaperSize.Height();
     471           0 :                     else if ( aSz.Height() < aMinAutoPaperSize.Height() )
     472           0 :                         aSz.Height() = aMinAutoPaperSize.Height();
     473             :                     pImpView->ResetOutputArea( Rectangle(
     474           0 :                         pImpView->GetOutputArea().TopLeft(), aSz ) );
     475             :                 }
     476             :             }
     477             :         }
     478             :     }
     479             : 
     480       27101 :     if ( aStatus.DoRestoreFont() )
     481           0 :         GetRefDevice()->SetFont( aOldFont );
     482       27101 :     bIsFormatting = false;
     483       27101 :     bFormatted = true;
     484             : 
     485       27101 :     if ( bMapChanged )
     486           0 :         GetRefDevice()->Pop();
     487             : 
     488       27101 :     CallStatusHdl();    // If Modified...
     489             : 
     490       27101 :     LeaveBlockNotifications();
     491             : }
     492             : 
     493       34159 : sal_Bool ImpEditEngine::ImpCheckRefMapMode()
     494             : {
     495       34159 :     sal_Bool bChange = sal_False;
     496             : 
     497       34159 :     if ( aStatus.DoFormat100() )
     498             :     {
     499       34109 :         MapMode aMapMode( GetRefDevice()->GetMapMode() );
     500       34109 :         if ( aMapMode.GetScaleX().GetNumerator() != aMapMode.GetScaleX().GetDenominator() )
     501           0 :             bChange = sal_True;
     502       34109 :         else if ( aMapMode.GetScaleY().GetNumerator() != aMapMode.GetScaleY().GetDenominator() )
     503           0 :             bChange = sal_True;
     504             : 
     505       34109 :         if ( bChange )
     506             :         {
     507           0 :             Fraction Scale1( 1, 1 );
     508           0 :             aMapMode.SetScaleX( Scale1 );
     509           0 :             aMapMode.SetScaleY( Scale1 );
     510           0 :             GetRefDevice()->Push();
     511           0 :             GetRefDevice()->SetMapMode( aMapMode );
     512       34109 :         }
     513             :     }
     514             : 
     515       34159 :     return bChange;
     516             : }
     517             : 
     518         218 : void ImpEditEngine::CheckAutoPageSize()
     519             : {
     520         218 :     Size aPrevPaperSize( GetPaperSize() );
     521         218 :     if ( GetStatus().AutoPageWidth() )
     522         218 :         aPaperSize.Width() = (long) !IsVertical() ? CalcTextWidth( sal_True ) : GetTextHeight();
     523         218 :     if ( GetStatus().AutoPageHeight() )
     524         218 :         aPaperSize.Height() = (long) !IsVertical() ? GetTextHeight() : CalcTextWidth( sal_True );
     525             : 
     526         218 :     SetValidPaperSize( aPaperSize );    // consider Min, Max
     527             : 
     528         218 :     if ( aPaperSize != aPrevPaperSize )
     529             :     {
     530         353 :         if ( ( !IsVertical() && ( aPaperSize.Width() != aPrevPaperSize.Width() ) )
     531         161 :              || ( IsVertical() && ( aPaperSize.Height() != aPrevPaperSize.Height() ) ) )
     532             :         {
     533             :             // If ahead is centered / right or tabs ...
     534          31 :             aStatus.GetStatusWord() |= !IsVertical() ? EE_STAT_TEXTWIDTHCHANGED : EE_STAT_TEXTHEIGHTCHANGED;
     535          62 :             for ( sal_uInt16 nPara = 0; nPara < GetParaPortions().Count(); nPara++ )
     536             :             {
     537             :                 // Only paragraphs which are not aligned to the left need to be
     538             :                 // reformatted, the height can not be changed here anymore.
     539          31 :                 ParaPortion* pParaPortion = GetParaPortions()[nPara];
     540          31 :                 ContentNode* pNode = pParaPortion->GetNode();
     541          31 :                 SvxAdjust eJustification = GetJustification( nPara );
     542          31 :                 if ( eJustification != SVX_ADJUST_LEFT )
     543             :                 {
     544           1 :                     pParaPortion->MarkSelectionInvalid( 0, pNode->Len() );
     545           1 :                     CreateLines( nPara, 0 );  // 0: For AutoPageSize no TextRange!
     546             :                 }
     547             :             }
     548             :         }
     549             : 
     550         192 :         Size aInvSize = aPaperSize;
     551         192 :         if ( aPaperSize.Width() < aPrevPaperSize.Width() )
     552           0 :             aInvSize.Width() = aPrevPaperSize.Width();
     553         192 :         if ( aPaperSize.Height() < aPrevPaperSize.Height() )
     554          62 :             aInvSize.Height() = aPrevPaperSize.Height();
     555             : 
     556         192 :         Size aSz( aInvSize );
     557         192 :         if ( IsVertical() )
     558             :         {
     559           0 :             aSz.Width() = aInvSize.Height();
     560           0 :             aSz.Height() = aInvSize.Width();
     561             :         }
     562         192 :         aInvalidRec = Rectangle( Point(), aSz );
     563             : 
     564             : 
     565         192 :         for (size_t nView = 0; nView < aEditViews.size(); ++nView)
     566             :         {
     567           0 :             EditView* pView = aEditViews[nView];
     568           0 :             pView->pImpEditView->RecalcOutputArea();
     569             :         }
     570             :     }
     571         218 : }
     572             : 
     573       13612 : static sal_Int32 ImplCalculateFontIndependentLineSpacing( const sal_Int32 nFontHeight )
     574             : {
     575       13612 :     return ( nFontHeight * 12 ) / 10;   // + 20%
     576             : }
     577             : 
     578       25091 : sal_Bool ImpEditEngine::CreateLines( sal_uInt16 nPara, sal_uInt32 nStartPosY )
     579             : {
     580       25091 :     ParaPortion* pParaPortion = GetParaPortions()[nPara];
     581             : 
     582             :     // sal_Bool: Changes in the height of paragraph Yes / No - sal_True/sal_False
     583             :     DBG_ASSERT( pParaPortion->GetNode(), "Portion without Node in CreateLines" );
     584             :     DBG_ASSERT( pParaPortion->IsVisible(), "Invisible paragraphs not formatted!" );
     585             :     DBG_ASSERT( pParaPortion->IsInvalid(), "CreateLines: Portion not invalid!" );
     586             : 
     587       25091 :     sal_Bool bProcessingEmptyLine = ( pParaPortion->GetNode()->Len() == 0 );
     588       25091 :     sal_Bool bEmptyNodeWithPolygon = ( pParaPortion->GetNode()->Len() == 0 ) && GetTextRanger();
     589             : 
     590             :     // ---------------------------------------------------------------
     591             :     // Fast special treatment for empty paragraphs ...
     592             :     // ---------------------------------------------------------------
     593       25091 :     if ( ( pParaPortion->GetNode()->Len() == 0 ) && !GetTextRanger() )
     594             :     {
     595             :         // fast special treatment ...
     596       18033 :         if ( pParaPortion->GetTextPortions().Count() )
     597        5548 :             pParaPortion->GetTextPortions().Reset();
     598       18033 :         if ( pParaPortion->GetLines().Count() )
     599        5548 :             pParaPortion->GetLines().Reset();
     600       18033 :         CreateAndInsertEmptyLine( pParaPortion, nStartPosY );
     601       18033 :         return FinishCreateLines( pParaPortion );
     602             :     }
     603             : 
     604             :     // ---------------------------------------------------------------
     605             :     // Initialization ......
     606             :     // ---------------------------------------------------------------
     607             : 
     608             :     // Always format for 100%:
     609        7058 :     sal_Bool bMapChanged = ImpCheckRefMapMode();
     610             : 
     611        7058 :     if ( pParaPortion->GetLines().Count() == 0 )
     612             :     {
     613        6840 :         EditLine* pL = new EditLine;
     614        6840 :         pParaPortion->GetLines().Append(pL);
     615             :     }
     616             : 
     617             :     // ---------------------------------------------------------------
     618             :     // Get Paragraph attributes  ......
     619             :     // ---------------------------------------------------------------
     620        7058 :     ContentNode* const pNode = pParaPortion->GetNode();
     621             : 
     622        7058 :     sal_Bool bRightToLeftPara = IsRightToLeft( nPara );
     623             : 
     624        7058 :     SvxAdjust eJustification = GetJustification( nPara );
     625        7058 :     sal_Bool bHyphenatePara = ((const SfxBoolItem&)pNode->GetContentAttribs().GetItem( EE_PARA_HYPHENATE )).GetValue();
     626        7058 :     sal_Int32 nSpaceBefore      = 0;
     627        7058 :     sal_Int32 nMinLabelWidth    = 0;
     628        7058 :     sal_Int32 nSpaceBeforeAndMinLabelWidth = GetSpaceBeforeAndMinLabelWidth( pNode, &nSpaceBefore, &nMinLabelWidth );
     629        7058 :     const SvxLRSpaceItem& rLRItem = GetLRSpaceItem( pNode );
     630        7058 :     const SvxLineSpacingItem& rLSItem = (const SvxLineSpacingItem&) pNode->GetContentAttribs().GetItem( EE_PARA_SBL );
     631        7058 :     const sal_Bool bScriptSpace = ((const SvxScriptSpaceItem&) pNode->GetContentAttribs().GetItem( EE_PARA_ASIANCJKSPACING )).GetValue();
     632             : 
     633        7058 :     const short nInvalidDiff = pParaPortion->GetInvalidDiff();
     634        7058 :     const sal_uInt16 nInvalidStart = pParaPortion->GetInvalidPosStart();
     635        7058 :     const sal_uInt16 nInvalidEnd =  nInvalidStart + Abs( nInvalidDiff );
     636             : 
     637        7058 :     sal_Bool bQuickFormat = sal_False;
     638        7058 :     if ( !bEmptyNodeWithPolygon && !HasScriptType( nPara, i18n::ScriptType::COMPLEX ) )
     639             :     {
     640        7100 :         if ( ( pParaPortion->IsSimpleInvalid() ) && ( nInvalidDiff > 0 ) &&
     641          42 :              ( pNode->GetString().Search( CH_FEATURE, nInvalidStart ) > nInvalidEnd ) )
     642             :         {
     643          42 :             bQuickFormat = sal_True;
     644             :         }
     645        7016 :         else if ( ( pParaPortion->IsSimpleInvalid() ) && ( nInvalidDiff < 0 ) )
     646             :         {
     647             :             // check if delete over the portion boundaries was done ...
     648           3 :             sal_uInt16 nStart = nInvalidStart;  // DOUBLE !!!!!!!!!!!!!!!
     649           3 :             sal_uInt16 nEnd = nStart - nInvalidDiff;  // negative
     650           3 :             bQuickFormat = sal_True;
     651           3 :             sal_uInt16 nPos = 0;
     652           3 :             sal_uInt16 nPortions = pParaPortion->GetTextPortions().Count();
     653           8 :             for ( sal_uInt16 nTP = 0; nTP < nPortions; nTP++ )
     654             :             {
     655             :                 // There must be no start / end in the deleted area.
     656           5 :                 TextPortion* const pTP = pParaPortion->GetTextPortions()[ nTP ];
     657           5 :                 nPos = nPos + pTP->GetLen();
     658           5 :                 if ( ( nPos > nStart ) && ( nPos < nEnd ) )
     659             :                 {
     660           0 :                     bQuickFormat = sal_False;
     661           0 :                     break;
     662             :                 }
     663             :             }
     664             :         }
     665             :     }
     666             : 
     667             :     // SW disables TEXT_LAYOUT_COMPLEX_DISABLED, so maybe I have to enable it...
     668             : 
     669             :     // Saving both layout mode and language (since I'm potentially changing both)
     670        7058 :     GetRefDevice()->Push( PUSH_TEXTLAYOUTMODE|PUSH_TEXTLANGUAGE );
     671             : 
     672        7058 :     ImplInitLayoutMode( GetRefDevice(), nPara, 0xFFFF );
     673             : 
     674        7058 :     sal_uInt16 nRealInvalidStart = nInvalidStart;
     675             : 
     676        7058 :     if ( bEmptyNodeWithPolygon )
     677             :     {
     678           0 :         TextPortion* pDummyPortion = new TextPortion( 0 );
     679           0 :         pParaPortion->GetTextPortions().Reset();
     680           0 :         pParaPortion->GetTextPortions().Append(pDummyPortion);
     681             :     }
     682        7058 :     else if ( bQuickFormat )
     683             :     {
     684             :         // faster Method:
     685          45 :         RecalcTextPortion( pParaPortion, nInvalidStart, nInvalidDiff );
     686             :     }
     687             :     else    // nRealInvalidStart can be before InvalidStart, since Portions were deleted....
     688             :     {
     689        7013 :         CreateTextPortions( pParaPortion, nRealInvalidStart );
     690             :     }
     691             : 
     692             : 
     693             :     // ---------------------------------------------------------------
     694             :     // Search for line with InvalidPos, start one line before
     695             :     // Flag the line => do not remove it !
     696             :     // ---------------------------------------------------------------
     697             : 
     698        7058 :     sal_uInt16 nLine = pParaPortion->GetLines().Count()-1;
     699       14058 :     for ( sal_uInt16 nL = 0; nL <= nLine; nL++ )
     700             :     {
     701        7058 :         EditLine* pLine = pParaPortion->GetLines()[nL];
     702        7058 :         if ( pLine->GetEnd() > nRealInvalidStart )  // not nInvalidStart!
     703             :         {
     704          58 :             nLine = nL;
     705          58 :             break;
     706             :         }
     707        7000 :         pLine->SetValid();
     708             :     }
     709             :     // Begin one line before...
     710             :     // If it is typed at the end, the line in front cannot change.
     711        7058 :     if ( nLine && ( !pParaPortion->IsSimpleInvalid() || ( nInvalidEnd < pNode->Len() ) || ( nInvalidDiff <= 0 ) ) )
     712           0 :         nLine--;
     713             : 
     714        7058 :     EditLine* pLine = pParaPortion->GetLines()[nLine];
     715             : 
     716        7058 :     static Rectangle aZeroArea = Rectangle( Point(), Point() );
     717        7058 :     Rectangle aBulletArea( aZeroArea );
     718        7058 :     if ( !nLine )
     719             :     {
     720        7058 :         aBulletArea = GetEditEnginePtr()->GetBulletArea( GetParaPortions().GetPos( pParaPortion ) );
     721        7058 :         if ( aBulletArea.Right() > 0 )
     722         425 :             pParaPortion->SetBulletX( (sal_uInt16) GetXValue( aBulletArea.Right() ) );
     723             :         else
     724        6633 :             pParaPortion->SetBulletX( 0 ); // if Bullet is set incorrectly
     725             :     }
     726             : 
     727             :     // ---------------------------------------------------------------
     728             :     // Reformat all lines from here ...
     729             :     // ---------------------------------------------------------------
     730        7058 :     sal_uInt16 nDelFromLine = 0xFFFF;
     731        7058 :     sal_Bool bLineBreak = sal_False;
     732             : 
     733        7058 :     sal_uInt16 nIndex = pLine->GetStart();
     734        7058 :     EditLine aSaveLine( *pLine );
     735        7058 :     SvxFont aTmpFont( pNode->GetCharAttribs().GetDefFont() );
     736             : 
     737        7058 :     sal_Bool bCalcCharPositions = sal_True;
     738        7058 :     sal_Int32* pBuf = new sal_Int32[ pNode->Len() ];
     739             : 
     740        7058 :     sal_Bool bSameLineAgain = sal_False;    // For TextRanger, if the height changes.
     741        7058 :     TabInfo aCurrentTab;
     742             : 
     743        7058 :     sal_Bool bForceOneRun = bEmptyNodeWithPolygon;
     744        7058 :     sal_Bool bCompressedChars = sal_False;
     745             : 
     746       24683 :     while ( ( nIndex < pNode->Len() ) || bForceOneRun )
     747             :     {
     748       10571 :         bForceOneRun = sal_False;
     749             : 
     750       10571 :         sal_Bool bEOL = sal_False;
     751       10571 :         sal_Bool bEOC = sal_False;
     752       10571 :         sal_uInt16 nPortionStart = 0;
     753       10571 :         sal_uInt16 nPortionEnd = 0;
     754             : 
     755       10571 :         long nStartX = GetXValue( rLRItem.GetTxtLeft() + nSpaceBeforeAndMinLabelWidth );
     756       10571 :         if ( nIndex == 0 )
     757             :         {
     758        7058 :             long nFI = GetXValue( rLRItem.GetTxtFirstLineOfst() );
     759        7058 :             nStartX += nFI;
     760             : 
     761        7058 :             if ( !nLine && ( pParaPortion->GetBulletX() > nStartX ) )
     762             :             {
     763          29 :                     nStartX = pParaPortion->GetBulletX();
     764             :             }
     765             :         }
     766             : 
     767             :         long nMaxLineWidth;
     768       10571 :         if ( !IsVertical() )
     769       10571 :             nMaxLineWidth = aStatus.AutoPageWidth() ? aMaxAutoPaperSize.Width() : aPaperSize.Width();
     770             :         else
     771           0 :             nMaxLineWidth = aStatus.AutoPageHeight() ? aMaxAutoPaperSize.Height() : aPaperSize.Height();
     772             : 
     773       10571 :         nMaxLineWidth -= GetXValue( rLRItem.GetRight() );
     774       10571 :         nMaxLineWidth -= nStartX;
     775             : 
     776             :         // If PaperSize == long_max, one cannot take away any negative
     777             :         // first line indent. (Overflow)
     778       10571 :         if ( ( nMaxLineWidth < 0 ) && ( nStartX < 0 ) )
     779           0 :             nMaxLineWidth = ( !IsVertical() ? aPaperSize.Width() : aPaperSize.Height() ) - GetXValue( rLRItem.GetRight() );
     780             : 
     781             :         // If still less than 0, it may be just the right edge.
     782       10571 :         if ( nMaxLineWidth <= 0 )
     783        1395 :             nMaxLineWidth = 1;
     784             : 
     785             :         // Problem:
     786             :         // Since formatting starts a line _before_ the invalid position,
     787             :      // the positions unfortunately have to be redefined ...
     788             :         // Solution:
     789             :         // The line before can only become longer, not smaller
     790             :         // => ...
     791       10571 :         if ( bCalcCharPositions )
     792       10571 :             pLine->GetCharPosArray().clear();
     793             : 
     794       10571 :         sal_uInt16 nTmpPos = nIndex;
     795       10571 :         sal_uInt16 nTmpPortion = pLine->GetStartPortion();
     796       10571 :         long nTmpWidth = 0;
     797       10571 :         long nXWidth = nMaxLineWidth;
     798       10571 :         if ( nXWidth <= nTmpWidth ) // while has to be looped once
     799           0 :             nXWidth = nTmpWidth+1;
     800             : 
     801       10571 :         LongDqPtr pTextRanges = 0;
     802       10571 :         long nTextExtraYOffset = 0;
     803       10571 :         long nTextXOffset = 0;
     804       10571 :         long nTextLineHeight = 0;
     805       10571 :         if ( GetTextRanger() )
     806             :         {
     807           0 :             GetTextRanger()->SetVertical( IsVertical() );
     808             : 
     809           0 :             long nTextY = nStartPosY + GetEditCursor( pParaPortion, pLine->GetStart() ).Top();
     810           0 :             if ( !bSameLineAgain )
     811             :             {
     812           0 :                 SeekCursor( pNode, nTmpPos+1, aTmpFont );
     813           0 :                 aTmpFont.SetPhysFont( GetRefDevice() );
     814           0 :                 ImplInitDigitMode( GetRefDevice(), 0, 0, 0, aTmpFont.GetLanguage() );
     815             : 
     816           0 :                 if ( IsFixedCellHeight() )
     817           0 :                     nTextLineHeight = ImplCalculateFontIndependentLineSpacing( aTmpFont.GetHeight() );
     818             :                 else
     819           0 :                     nTextLineHeight = aTmpFont.GetPhysTxtSize( GetRefDevice(), String() ).Height();
     820             :                 // Metrics can be greater
     821           0 :                 FormatterFontMetric aTempFormatterMetrics;
     822           0 :                 RecalcFormatterFontMetrics( aTempFormatterMetrics, aTmpFont );
     823           0 :                 sal_uInt16 nLineHeight = aTempFormatterMetrics.GetHeight();
     824           0 :                 if ( nLineHeight > nTextLineHeight )
     825           0 :                     nTextLineHeight = nLineHeight;
     826             :             }
     827             :             else
     828           0 :                 nTextLineHeight = pLine->GetHeight();
     829             : 
     830           0 :             nXWidth = 0;
     831           0 :             while ( !nXWidth )
     832             :             {
     833           0 :                 long nYOff = nTextY + nTextExtraYOffset;
     834           0 :                 long nYDiff = nTextLineHeight;
     835           0 :                 if ( IsVertical() )
     836             :                 {
     837           0 :                     long nMaxPolygonX = GetTextRanger()->GetBoundRect().Right();
     838           0 :                     nYOff = nMaxPolygonX-nYOff;
     839           0 :                     nYDiff = -nTextLineHeight;
     840             :                 }
     841           0 :                 pTextRanges = GetTextRanger()->GetTextRanges( Range( nYOff, nYOff + nYDiff ) );
     842             :                 DBG_ASSERT( pTextRanges, "GetTextRanges?!" );
     843           0 :                 long nMaxRangeWidth = 0;
     844             :                 // Use the widest range ...
     845             :                 // The widest range could be a bit confusing, so normally it
     846             :                 // is the first one. Best with gaps.
     847           0 :                 if ( pTextRanges->size() )
     848             :                 {
     849           0 :                     sal_uInt16 n = 0;
     850           0 :                     long nA = pTextRanges->at(n++);
     851           0 :                     long nB = pTextRanges->at(n++);
     852             :                     DBG_ASSERT( nA <= nB, "TextRange distorted?" );
     853           0 :                     long nW = nB - nA;
     854           0 :                     if ( nW > nMaxRangeWidth )
     855             :                     {
     856           0 :                         nMaxRangeWidth = nW;
     857           0 :                         nTextXOffset = nA;
     858             :                     }
     859             :                 }
     860           0 :                 nXWidth = nMaxRangeWidth;
     861           0 :                 if ( nXWidth )
     862           0 :                     nMaxLineWidth = nXWidth - nStartX - GetXValue( rLRItem.GetRight() );
     863             :                 else
     864             :                 {
     865             :                     // Try further down in the polygon.
     866             :                     // Below the polygon use the Paper Width.
     867           0 :                     nTextExtraYOffset += Max( (long)(nTextLineHeight / 10), (long)1 );
     868           0 :                     if ( ( nTextY + nTextExtraYOffset  ) > GetTextRanger()->GetBoundRect().Bottom() )
     869             :                     {
     870           0 :                         nXWidth = !IsVertical() ? GetPaperSize().Width() : GetPaperSize().Height();
     871           0 :                         if ( !nXWidth ) // AutoPaperSize
     872           0 :                             nXWidth = 0x7FFFFFFF;
     873             :                     }
     874             :                 }
     875             :             }
     876             :         }
     877             : 
     878             :         // search for Portion that no longer fits in line ....
     879       10571 :         TextPortion* pPortion = 0;
     880       10571 :         sal_Bool bBrokenLine = sal_False;
     881       10571 :         bLineBreak = sal_False;
     882       10571 :         const EditCharAttrib* pNextFeature = pNode->GetCharAttribs().FindFeature( pLine->GetStart() );
     883       32568 :         while ( ( nTmpWidth < nXWidth ) && !bEOL && ( nTmpPortion < pParaPortion->GetTextPortions().Count() ) )
     884             :         {
     885       11426 :             nPortionStart = nTmpPos;
     886       11426 :             pPortion = pParaPortion->GetTextPortions()[nTmpPortion];
     887       11426 :             if ( pPortion->GetKind() == PORTIONKIND_HYPHENATOR )
     888             :             {
     889             :                 // Throw away a Portion, if necessary correct the one before,
     890             :                 // if the Hyph portion has swallowed a character ...
     891           0 :                 sal_uInt16 nTmpLen = pPortion->GetLen();
     892           0 :                 pParaPortion->GetTextPortions().Remove( nTmpPortion );
     893           0 :                 if (nTmpPortion && nTmpLen)
     894             :                 {
     895           0 :                     nTmpPortion--;
     896           0 :                     TextPortion* pPrev = pParaPortion->GetTextPortions()[nTmpPortion];
     897             :                     DBG_ASSERT( pPrev->GetKind() == PORTIONKIND_TEXT, "Portion?!" );
     898           0 :                     nTmpWidth -= pPrev->GetSize().Width();
     899           0 :                     nTmpPos = nTmpPos - pPrev->GetLen();
     900           0 :                     pPrev->SetLen(pPrev->GetLen() + nTmpLen);
     901           0 :                     pPrev->GetSize().Width() = (-1);
     902             :                 }
     903             : 
     904             :                 DBG_ASSERT( nTmpPortion < pParaPortion->GetTextPortions().Count(), "No more Portions left!" );
     905           0 :                 pPortion = pParaPortion->GetTextPortions()[nTmpPortion];
     906             :             }
     907             :             DBG_ASSERT( pPortion->GetKind() != PORTIONKIND_HYPHENATOR, "CreateLines: Hyphenator-Portion!" );
     908             :             DBG_ASSERT( pPortion->GetLen() || bProcessingEmptyLine, "Empty Portion in CreateLines ?!" );
     909             :             (void)bProcessingEmptyLine;
     910       11426 :             if ( pNextFeature && ( pNextFeature->GetStart() == nTmpPos ) )
     911             :             {
     912         595 :                 sal_uInt16 nWhich = pNextFeature->GetItem()->Which();
     913         595 :                 switch ( nWhich )
     914             :                 {
     915             :                     case EE_FEATURE_TAB:
     916             :                     {
     917          18 :                         long nOldTmpWidth = nTmpWidth;
     918             : 
     919             :                         // Search for Tab-Pos...
     920          18 :                         long nCurPos = nTmpWidth+nStartX;
     921             :                         // consider scaling
     922          18 :                         if ( aStatus.DoStretch() && ( nStretchX != 100 ) )
     923           0 :                             nCurPos = nCurPos*100/std::max(static_cast<sal_Int32>(nStretchX), static_cast<sal_Int32>(1));
     924             : 
     925          18 :                         short nAllSpaceBeforeText = static_cast< short >(rLRItem.GetTxtLeft()/* + rLRItem.GetTxtLeft()*/ + nSpaceBeforeAndMinLabelWidth);
     926          18 :                         aCurrentTab.aTabStop = pNode->GetContentAttribs().FindTabStop( nCurPos - nAllSpaceBeforeText /*rLRItem.GetTxtLeft()*/, aEditDoc.GetDefTab() );
     927          18 :                         aCurrentTab.nTabPos = GetXValue( (long) ( aCurrentTab.aTabStop.GetTabPos() + nAllSpaceBeforeText /*rLRItem.GetTxtLeft()*/ ) );
     928          18 :                         aCurrentTab.bValid = sal_False;
     929             : 
     930             :                         // Switch direction in R2L para...
     931          18 :                         if ( bRightToLeftPara )
     932             :                         {
     933           0 :                             if ( aCurrentTab.aTabStop.GetAdjustment() == SVX_TAB_ADJUST_RIGHT )
     934           0 :                                 aCurrentTab.aTabStop.GetAdjustment() = SVX_TAB_ADJUST_LEFT;
     935           0 :                             else if ( aCurrentTab.aTabStop.GetAdjustment() == SVX_TAB_ADJUST_LEFT )
     936           0 :                                 aCurrentTab.aTabStop.GetAdjustment() = SVX_TAB_ADJUST_RIGHT;
     937             :                         }
     938             : 
     939          54 :                         if ( ( aCurrentTab.aTabStop.GetAdjustment() == SVX_TAB_ADJUST_RIGHT ) ||
     940          18 :                              ( aCurrentTab.aTabStop.GetAdjustment() == SVX_TAB_ADJUST_CENTER ) ||
     941          18 :                              ( aCurrentTab.aTabStop.GetAdjustment() == SVX_TAB_ADJUST_DECIMAL ) )
     942             :                         {
     943             :                             // For LEFT / DEFAULT this tab is not considered.
     944           0 :                             aCurrentTab.bValid = sal_True;
     945           0 :                             aCurrentTab.nStartPosX = nTmpWidth;
     946           0 :                             aCurrentTab.nCharPos = nTmpPos;
     947           0 :                             aCurrentTab.nTabPortion = nTmpPortion;
     948             :                         }
     949             : 
     950          18 :                         pPortion->GetKind() = PORTIONKIND_TAB;
     951          18 :                         pPortion->SetExtraValue( aCurrentTab.aTabStop.GetFill() );
     952          18 :                         pPortion->GetSize().Width() = aCurrentTab.nTabPos - (nTmpWidth+nStartX);
     953             : 
     954             :                         // Height needed...
     955          18 :                         SeekCursor( pNode, nTmpPos+1, aTmpFont );
     956          18 :                         pPortion->GetSize().Height() = aTmpFont.QuickGetTextSize( GetRefDevice(), String(), 0, 0, NULL ).Height();
     957             : 
     958             :                         DBG_ASSERT( pPortion->GetSize().Width() >= 0, "Tab incorrectly calculated!" );
     959             : 
     960          18 :                         nTmpWidth = aCurrentTab.nTabPos-nStartX;
     961             : 
     962             :                         // If this is the first token on the line,
     963             :                         // and nTmpWidth > aPaperSize.Width, => infinite loop!
     964          18 :                         if ( ( nTmpWidth >= nXWidth ) && ( nTmpPortion == pLine->GetStartPortion() ) )
     965             :                         {
     966             :                             // What now?
     967             :                             // make the tab fitting
     968           0 :                             pPortion->GetSize().Width() = nXWidth-nOldTmpWidth;
     969           0 :                             nTmpWidth = nXWidth-1;
     970           0 :                             bEOL = sal_True;
     971           0 :                             bBrokenLine = sal_True;
     972             :                         }
     973          18 :                         EditLine::CharPosArrayType& rArray = pLine->GetCharPosArray();
     974          18 :                         size_t nPos = nTmpPos - pLine->GetStart();
     975          18 :                         rArray.insert(rArray.begin()+nPos, pPortion->GetSize().Width());
     976          18 :                         bCompressedChars = sal_False;
     977             :                     }
     978          18 :                     break;
     979             :                     case EE_FEATURE_LINEBR:
     980             :                     {
     981             :                         DBG_ASSERT( pPortion, "?!" );
     982           3 :                         pPortion->GetSize().Width() = 0;
     983           3 :                         bEOL = sal_True;
     984           3 :                         bLineBreak = sal_True;
     985           3 :                         pPortion->GetKind() = PORTIONKIND_LINEBREAK;
     986           3 :                         bCompressedChars = sal_False;
     987           3 :                         EditLine::CharPosArrayType& rArray = pLine->GetCharPosArray();
     988           3 :                         size_t nPos = nTmpPos - pLine->GetStart();
     989           3 :                         rArray.insert(rArray.begin()+nPos, pPortion->GetSize().Width());
     990             :                     }
     991           3 :                     break;
     992             :                     case EE_FEATURE_FIELD:
     993             :                     {
     994         574 :                         SeekCursor( pNode, nTmpPos+1, aTmpFont );
     995         574 :                         sal_Unicode cChar = 0;  // later: NBS?
     996         574 :                         aTmpFont.SetPhysFont( GetRefDevice() );
     997         574 :                         ImplInitDigitMode( GetRefDevice(), 0, 0, 0, aTmpFont.GetLanguage() );
     998             : 
     999         574 :                         rtl::OUString aFieldValue = cChar ? rtl::OUString(cChar) : ((EditCharAttribField*)pNextFeature)->GetFieldValue();
    1000         574 :                         if ( bCalcCharPositions || !pPortion->HasValidSize() )
    1001             :                         {
    1002         574 :                             pPortion->GetSize() = aTmpFont.QuickGetTextSize( GetRefDevice(), aFieldValue, 0, aFieldValue.getLength(), 0 );
    1003             :                             // So no scrolling for oversized fields
    1004         574 :                             if ( pPortion->GetSize().Width() > nXWidth )
    1005             :                             {
    1006           0 :                                 sal_Int32 nWidthOrg         = pPortion->GetSize().Width();
    1007           0 :                                 sal_Int32 nChars            = aFieldValue.getLength();
    1008           0 :                                 sal_Int32 nApproxWC         = nXWidth / ( nWidthOrg / nChars );
    1009           0 :                                 ExtraPortionInfo *pExtraInfo= pPortion->GetExtraInfos();
    1010           0 :                                 if( !nApproxWC ) nApproxWC++;
    1011           0 :                                 if( pExtraInfo == NULL )
    1012             :                                 {
    1013           0 :                                     pExtraInfo = new ExtraPortionInfo();
    1014           0 :                                     pExtraInfo->nOrgWidth = nXWidth;
    1015           0 :                                     pPortion->SetExtraInfos( pExtraInfo );
    1016             :                                 }
    1017             :                                 else
    1018             :                                 {
    1019           0 :                                     pExtraInfo->lineBreaksList.clear();
    1020             :                                 }
    1021             : 
    1022           0 :                                 pPortion->GetSize().Width() = nXWidth;
    1023             : 
    1024           0 :                                 while( nChars > 0 )
    1025             :                                 {
    1026           0 :                                     pExtraInfo->lineBreaksList.push_back( aFieldValue.getLength() - nChars );
    1027           0 :                                     nChars -= nApproxWC;
    1028             :                                 }
    1029             :                             }
    1030             :                         }
    1031         574 :                         nTmpWidth += pPortion->GetSize().Width();
    1032         574 :                         EditLine::CharPosArrayType& rArray = pLine->GetCharPosArray();
    1033         574 :                         size_t nPos = nTmpPos - pLine->GetStart();
    1034         574 :                         rArray.insert(rArray.begin()+nPos, pPortion->GetSize().Width());
    1035         574 :                         pPortion->GetKind() = cChar ? PORTIONKIND_TEXT : PORTIONKIND_FIELD;
    1036             :                         // If this is the first token on the line,
    1037             :                         // and nTmpWidth > aPaperSize.Width, => infinite loop!
    1038         574 :                         if ( ( nTmpWidth >= nXWidth ) && ( nTmpPortion == pLine->GetStartPortion() ) )
    1039             :                         {
    1040           0 :                             nTmpWidth = nXWidth-1;
    1041           0 :                             bEOL = sal_True;
    1042           0 :                             bBrokenLine = sal_True;
    1043             :                         }
    1044             :                         // Compression in Fields????
    1045             :                         // I think this could be a little bit difficult and is not very usefull
    1046         574 :                         bCompressedChars = sal_False;
    1047             :                     }
    1048         574 :                     break;
    1049             :                     default:    OSL_FAIL( "What feature?" );
    1050             :                 }
    1051         595 :                 pNextFeature = pNode->GetCharAttribs().FindFeature( pNextFeature->GetStart() + 1  );
    1052             :             }
    1053             :             else
    1054             :             {
    1055             :                 DBG_ASSERT( pPortion->GetLen() || bProcessingEmptyLine, "Empty Portion - Extra Space?!" );
    1056             :                 (void)bProcessingEmptyLine;
    1057       10831 :                 SeekCursor( pNode, nTmpPos+1, aTmpFont );
    1058       10831 :                 aTmpFont.SetPhysFont( GetRefDevice() );
    1059       10831 :                 ImplInitDigitMode( GetRefDevice(), 0, 0, 0, aTmpFont.GetLanguage() );
    1060             : 
    1061       10831 :                 if ( bCalcCharPositions || !pPortion->HasValidSize() )
    1062             :                 {
    1063       10831 :                     pPortion->GetSize() = aTmpFont.QuickGetTextSize( GetRefDevice(), pParaPortion->GetNode()->GetString(), nTmpPos, pPortion->GetLen(), pBuf );
    1064             : 
    1065             :                     // #i9050# Do Kerning also behind portions...
    1066       10831 :                     if ( ( aTmpFont.GetFixKerning() > 0 ) && ( ( nTmpPos + pPortion->GetLen() ) < pNode->Len() ) )
    1067           0 :                         pPortion->GetSize().Width() += aTmpFont.GetFixKerning();
    1068       10831 :                     if ( IsFixedCellHeight() )
    1069        3664 :                         pPortion->GetSize().Height() = ImplCalculateFontIndependentLineSpacing( aTmpFont.GetHeight() );
    1070             :                 }
    1071       10831 :                 if ( bCalcCharPositions )
    1072             :                 {
    1073       10831 :                     sal_uInt16 nLen = pPortion->GetLen();
    1074             :                     // The array is  generally flattened at the beginning
    1075             :                     // => Always simply quick inserts.
    1076       10831 :                     size_t nPos = nTmpPos - pLine->GetStart();
    1077       10831 :                     EditLine::CharPosArrayType& rArray = pLine->GetCharPosArray();
    1078       10831 :                     rArray.insert(rArray.begin()+nPos, pBuf, pBuf+nLen);
    1079             :                 }
    1080             : 
    1081             :                 // And now check for Compression:
    1082       10831 :                 if ( pPortion->GetLen() && GetAsianCompressionMode() )
    1083             :                 {
    1084           0 :                     EditLine::CharPosArrayType& rArray = pLine->GetCharPosArray();
    1085           0 :                     sal_Int32* pDXArray = &rArray[0] + nTmpPos - pLine->GetStart();
    1086             :                     bCompressedChars |= ImplCalcAsianCompression(
    1087           0 :                         pNode, pPortion, nTmpPos, pDXArray, 10000, false);
    1088             :                 }
    1089             : 
    1090       10831 :                 nTmpWidth += pPortion->GetSize().Width();
    1091             : 
    1092       10831 :                 pPortion->SetRightToLeft( GetRightToLeft( nPara, nTmpPos+1 ) );
    1093             : 
    1094       10831 :                 sal_uInt16 _nPortionEnd = nTmpPos + pPortion->GetLen();
    1095       10831 :                 if( bScriptSpace && ( _nPortionEnd < pNode->Len() ) && ( nTmpWidth < nXWidth ) && IsScriptChange( EditPaM( pNode, _nPortionEnd ) ) )
    1096             :                 {
    1097          72 :                     sal_Bool bAllow = sal_False;
    1098          72 :                     sal_uInt16 nScriptTypeLeft = GetScriptType( EditPaM( pNode, _nPortionEnd ) );
    1099          72 :                     sal_uInt16 nScriptTypeRight = GetScriptType( EditPaM( pNode, _nPortionEnd+1 ) );
    1100          72 :                     if ( ( nScriptTypeLeft == i18n::ScriptType::ASIAN ) || ( nScriptTypeRight == i18n::ScriptType::ASIAN ) )
    1101           0 :                         bAllow = sal_True;
    1102             : 
    1103             :                     // No spacing within L2R/R2L nesting
    1104          72 :                     if ( bAllow )
    1105             :                     {
    1106           0 :                         long nExtraSpace = pPortion->GetSize().Height()/5;
    1107           0 :                         nExtraSpace = GetXValue( nExtraSpace );
    1108           0 :                         pPortion->GetSize().Width() += nExtraSpace;
    1109           0 :                         nTmpWidth += nExtraSpace;
    1110             :                     }
    1111             :                 }
    1112             :             }
    1113             : 
    1114       11426 :             if ( aCurrentTab.bValid && ( nTmpPortion != aCurrentTab.nTabPortion ) )
    1115             :             {
    1116           0 :                 long nWidthAfterTab = 0;
    1117           0 :                 for ( sal_uInt16 n = aCurrentTab.nTabPortion+1; n <= nTmpPortion; n++  )
    1118             :                 {
    1119           0 :                     const TextPortion* pTP = pParaPortion->GetTextPortions()[n];
    1120           0 :                     nWidthAfterTab += pTP->GetSize().Width();
    1121             :                 }
    1122           0 :                 long nW = nWidthAfterTab;   // Length before tab position
    1123           0 :                 if ( aCurrentTab.aTabStop.GetAdjustment() == SVX_TAB_ADJUST_RIGHT )
    1124             :                 {
    1125             :                 }
    1126           0 :                 else if ( aCurrentTab.aTabStop.GetAdjustment() == SVX_TAB_ADJUST_CENTER )
    1127             :                 {
    1128           0 :                     nW = nWidthAfterTab/2;
    1129             :                 }
    1130           0 :                 else if ( aCurrentTab.aTabStop.GetAdjustment() == SVX_TAB_ADJUST_DECIMAL )
    1131             :                 {
    1132             :                     String aText = GetSelected( EditSelection(  EditPaM( pParaPortion->GetNode(), nTmpPos ),
    1133           0 :                                                                 EditPaM( pParaPortion->GetNode(), nTmpPos + pPortion->GetLen() ) ) );
    1134           0 :                     sal_uInt16 nDecPos = aText.Search( aCurrentTab.aTabStop.GetDecimal() );
    1135           0 :                     if ( nDecPos != STRING_NOTFOUND )
    1136             :                     {
    1137           0 :                         nW -= pParaPortion->GetTextPortions()[nTmpPortion]->GetSize().Width();
    1138           0 :                         nW += aTmpFont.QuickGetTextSize( GetRefDevice(), pParaPortion->GetNode()->GetString(), nTmpPos, nDecPos, NULL ).Width();
    1139           0 :                         aCurrentTab.bValid = sal_False;
    1140           0 :                     }
    1141             :                 }
    1142             :                 else
    1143             :                 {
    1144             :                     OSL_FAIL( "CreateLines: Tab not handled!" );
    1145             :                 }
    1146           0 :                 long nMaxW = aCurrentTab.nTabPos - aCurrentTab.nStartPosX - nStartX;
    1147           0 :                 if ( nW >= nMaxW )
    1148             :                 {
    1149           0 :                     nW = nMaxW;
    1150           0 :                     aCurrentTab.bValid = sal_False;
    1151             :                 }
    1152           0 :                 TextPortion* const pTabPortion = pParaPortion->GetTextPortions()[aCurrentTab.nTabPortion];
    1153           0 :                 pTabPortion->GetSize().Width() = aCurrentTab.nTabPos - aCurrentTab.nStartPosX - nW - nStartX;
    1154           0 :                 nTmpWidth = aCurrentTab.nStartPosX + pTabPortion->GetSize().Width() + nWidthAfterTab;
    1155             :             }
    1156             : 
    1157       11426 :             nTmpPos = nTmpPos + pPortion->GetLen();
    1158       11426 :             nPortionEnd = nTmpPos;
    1159       11426 :             nTmpPortion++;
    1160       11426 :             if ( aStatus.OneCharPerLine() )
    1161           0 :                 bEOL = sal_True;
    1162             :         }
    1163             : 
    1164             :         DBG_ASSERT( pPortion, "no portion!?" );
    1165             : 
    1166       10571 :         aCurrentTab.bValid = sal_False;
    1167             : 
    1168             :         // this was possibly a portion too far:
    1169       10571 :         sal_Bool bFixedEnd = sal_False;
    1170       10571 :         if ( aStatus.OneCharPerLine() )
    1171             :         {
    1172             :             // State before Portion (apart from nTmpWidth):
    1173           0 :             nPortionEnd = nTmpPos;
    1174           0 :             nTmpPos -= pPortion ? pPortion->GetLen() : 0;
    1175           0 :             nPortionStart = nTmpPos;
    1176           0 :             nTmpPortion--;
    1177             : 
    1178           0 :             bEOL = sal_True;
    1179           0 :             bEOC = sal_False;
    1180             : 
    1181             :             // And now just one character:
    1182           0 :             nTmpPos++;
    1183           0 :             nTmpPortion++;
    1184           0 :             nPortionEnd = nTmpPortion;
    1185             :             // one Non-Feature-Portion has to be wrapped
    1186           0 :             if ( pPortion->GetLen() > 1 )
    1187             :             {
    1188             :                 DBG_ASSERT( pPortion && (pPortion->GetKind() == PORTIONKIND_TEXT), "Len>1, but no TextPortion?" );
    1189           0 :                 nTmpWidth -= pPortion ? pPortion->GetSize().Width() : 0;
    1190           0 :                 sal_uInt16 nP = SplitTextPortion( pParaPortion, nTmpPos, pLine );
    1191           0 :                 const TextPortion* p = pParaPortion->GetTextPortions()[nP];
    1192             :                 DBG_ASSERT( p, "Portion ?!" );
    1193           0 :                 nTmpWidth += p->GetSize().Width();
    1194             :             }
    1195             :         }
    1196       10571 :         else if ( nTmpWidth >= nXWidth )
    1197             :         {
    1198        4778 :             nPortionEnd = nTmpPos;
    1199        4778 :             nTmpPos -= pPortion ? pPortion->GetLen() : 0;
    1200        4778 :             nPortionStart = nTmpPos;
    1201        4778 :             nTmpPortion--;
    1202        4778 :             bEOL = sal_False;
    1203        4778 :             bEOC = sal_False;
    1204        4778 :             if( pPortion ) switch ( pPortion->GetKind() )
    1205             :             {
    1206             :                 case PORTIONKIND_TEXT:
    1207             :                 {
    1208        4778 :                     nTmpWidth -= pPortion->GetSize().Width();
    1209             :                 }
    1210        4778 :                 break;
    1211             :                 case PORTIONKIND_FIELD:
    1212             :                 case PORTIONKIND_TAB:
    1213             :                 {
    1214           0 :                     nTmpWidth -= pPortion->GetSize().Width();
    1215           0 :                     bEOL = sal_True;
    1216           0 :                     bFixedEnd = sal_True;
    1217             :                 }
    1218           0 :                 break;
    1219             :                 default:
    1220             :                 {
    1221             :                     //  A feature is not wrapped:
    1222             :                     DBG_ASSERT( ( pPortion->GetKind() == PORTIONKIND_LINEBREAK ), "What Feature ?" );
    1223           0 :                     bEOL = sal_True;
    1224           0 :                     bFixedEnd = sal_True;
    1225             :                 }
    1226             :             }
    1227             :         }
    1228             :         else
    1229             :         {
    1230        5793 :             bEOL = sal_True;
    1231        5793 :             bEOC = sal_True;
    1232        5793 :             pLine->SetEnd( nPortionEnd );
    1233             :             DBG_ASSERT( pParaPortion->GetTextPortions().Count(), "No TextPortions?" );
    1234        5793 :             pLine->SetEndPortion( (sal_uInt16)pParaPortion->GetTextPortions().Count() - 1 );
    1235             :         }
    1236             : 
    1237       10571 :         if ( aStatus.OneCharPerLine() )
    1238             :         {
    1239           0 :             pLine->SetEnd( nPortionEnd );
    1240           0 :             pLine->SetEndPortion( nTmpPortion-1 );
    1241             :         }
    1242       10571 :         else if ( bFixedEnd )
    1243             :         {
    1244           0 :             pLine->SetEnd( nPortionStart );
    1245           0 :             pLine->SetEndPortion( nTmpPortion-1 );
    1246             :         }
    1247       10571 :         else if ( bLineBreak || bBrokenLine )
    1248             :         {
    1249           3 :             pLine->SetEnd( nPortionStart+1 );
    1250           3 :             pLine->SetEndPortion( nTmpPortion-1 );
    1251           3 :             bEOC = sal_False; // was set above, maybe change the sequence of the if's?
    1252             :         }
    1253       10568 :         else if ( !bEOL )
    1254             :         {
    1255             :             DBG_ASSERT( pPortion && ((nPortionEnd-nPortionStart) == pPortion->GetLen()), "However, another portion?!" );
    1256        4778 :             long nRemainingWidth = nMaxLineWidth - nTmpWidth;
    1257        4778 :             sal_Bool bCanHyphenate = ( aTmpFont.GetCharSet() != RTL_TEXTENCODING_SYMBOL );
    1258        4778 :             if ( bCompressedChars && pPortion && ( pPortion->GetLen() > 1 ) && pPortion->GetExtraInfos() && pPortion->GetExtraInfos()->bCompressed )
    1259             :             {
    1260             :                 // I need the manipulated DXArray for determining the break postion...
    1261           0 :                 sal_Int32* pDXArray = NULL;
    1262           0 :                 if (!pLine->GetCharPosArray().empty())
    1263           0 :                     pDXArray = &pLine->GetCharPosArray()[0] + (nPortionStart - pLine->GetStart());
    1264             :                 ImplCalcAsianCompression(
    1265           0 :                     pNode, pPortion, nPortionStart, pDXArray, 10000, true);
    1266             :             }
    1267        4778 :             if( pPortion )
    1268             :                 ImpBreakLine( pParaPortion, pLine, pPortion, nPortionStart,
    1269        4778 :                                                 nRemainingWidth, bCanHyphenate && bHyphenatePara );
    1270             :         }
    1271             : 
    1272             :         // ------------------------------------------------------------------
    1273             :         // Line finished => adjust
    1274             :         // ------------------------------------------------------------------
    1275             : 
    1276             :         // CalcTextSize should be replaced by a continuous registering!
    1277       10571 :         Size aTextSize = pLine->CalcTextSize( *pParaPortion );
    1278             : 
    1279       10571 :         if ( aTextSize.Height() == 0 )
    1280             :         {
    1281           0 :             SeekCursor( pNode, pLine->GetStart()+1, aTmpFont );
    1282           0 :             aTmpFont.SetPhysFont( pRefDev );
    1283           0 :             ImplInitDigitMode( pRefDev, 0, 0, 0, aTmpFont.GetLanguage() );
    1284             : 
    1285           0 :             if ( IsFixedCellHeight() )
    1286           0 :                 aTextSize.Height() = ImplCalculateFontIndependentLineSpacing( aTmpFont.GetHeight() );
    1287             :             else
    1288           0 :                 aTextSize.Height() = aTmpFont.GetPhysTxtSize( pRefDev, String() ).Height();
    1289           0 :             pLine->SetHeight( (sal_uInt16)aTextSize.Height() );
    1290             :         }
    1291             : 
    1292             :         // The font metrics can not be calculated continuously, if the font is
    1293             :         // set anyway, because a large font only after wrapping suddenly ends
    1294             :         // up in the next line => Font metrics too big.
    1295       10571 :         FormatterFontMetric aFormatterMetrics;
    1296       10571 :         sal_uInt16 nTPos = pLine->GetStart();
    1297       21994 :         for ( sal_uInt16 nP = pLine->GetStartPortion(); nP <= pLine->GetEndPortion(); nP++ )
    1298             :         {
    1299       11423 :             const TextPortion* pTP = pParaPortion->GetTextPortions()[nP];
    1300             :             // problem with hard font height attribute, when everthing but the line break has this attribute
    1301       11423 :             if ( pTP->GetKind() != PORTIONKIND_LINEBREAK )
    1302             :             {
    1303       11420 :                 SeekCursor( pNode, nTPos+1, aTmpFont );
    1304       11420 :                 aTmpFont.SetPhysFont( GetRefDevice() );
    1305       11420 :                 ImplInitDigitMode( GetRefDevice(), 0, 0, 0, aTmpFont.GetLanguage() );
    1306       11420 :                 RecalcFormatterFontMetrics( aFormatterMetrics, aTmpFont );
    1307             :             }
    1308       11423 :             nTPos = nTPos + pTP->GetLen();
    1309             :         }
    1310       10571 :         sal_uInt16 nLineHeight = aFormatterMetrics.GetHeight();
    1311       10571 :         if ( nLineHeight > pLine->GetHeight() )
    1312         306 :             pLine->SetHeight( nLineHeight );
    1313       10571 :         pLine->SetMaxAscent( aFormatterMetrics.nMaxAscent );
    1314             : 
    1315       10571 :         bSameLineAgain = sal_False;
    1316       10571 :         if ( GetTextRanger() && ( pLine->GetHeight() > nTextLineHeight ) )
    1317             :         {
    1318             :             // put down with the other size!
    1319           0 :             bSameLineAgain = sal_True;
    1320             :         }
    1321             : 
    1322             : 
    1323       10571 :         if ( !bSameLineAgain && !aStatus.IsOutliner() )
    1324             :         {
    1325       10571 :             if ( rLSItem.GetLineSpaceRule() == SVX_LINE_SPACE_MIN )
    1326             :             {
    1327           0 :                 sal_uInt16 nMinHeight = GetYValue( rLSItem.GetLineHeight() );
    1328           0 :                 sal_uInt16 nTxtHeight = pLine->GetHeight();
    1329           0 :                 if ( nTxtHeight < nMinHeight )
    1330             :                 {
    1331             :                     // The Ascent has to be adjusted for the difference:
    1332           0 :                     long nDiff = nMinHeight - nTxtHeight;
    1333           0 :                     pLine->SetMaxAscent( (sal_uInt16)(pLine->GetMaxAscent() + nDiff) );
    1334           0 :                     pLine->SetHeight( nMinHeight, nTxtHeight );
    1335             :                 }
    1336             :             }
    1337       10571 :             else if ( rLSItem.GetLineSpaceRule() == SVX_LINE_SPACE_FIX )
    1338             :             {
    1339           0 :                 sal_uInt16 nFixHeight = GetYValue( rLSItem.GetLineHeight() );
    1340           0 :                 sal_uInt16 nTxtHeight = pLine->GetHeight();
    1341           0 :                 pLine->SetMaxAscent( (sal_uInt16)(pLine->GetMaxAscent() + ( nFixHeight - nTxtHeight ) ) );
    1342           0 :                 pLine->SetHeight( nFixHeight, nTxtHeight );
    1343             :             }
    1344       10571 :             else if ( rLSItem.GetInterLineSpaceRule() == SVX_INTER_LINE_SPACE_PROP )
    1345             :             {
    1346        3467 :                 if ( nPara || IsFixedCellHeight() || pLine->GetStartPortion() ) // Not the very first line
    1347             :                 {
    1348             :                     // There are documents with PropLineSpace 0, why?
    1349             :                     // (cmc: re above question :-) such documents can be seen by importing a .ppt
    1350        3427 :                     if ( rLSItem.GetPropLineSpace() && ( rLSItem.GetPropLineSpace() != 100 ) )
    1351             :                     {
    1352        3169 :                         sal_uInt16 nTxtHeight = pLine->GetHeight();
    1353        3169 :                         sal_Int32 nH = nTxtHeight;
    1354        3169 :                         nH *= rLSItem.GetPropLineSpace();
    1355        3169 :                         nH /= 100;
    1356             :                         // The Ascent has to be adjusted for the difference:
    1357        3169 :                         long nDiff = pLine->GetHeight() - nH;
    1358        3169 :                         if ( nDiff > pLine->GetMaxAscent() )
    1359           0 :                             nDiff = pLine->GetMaxAscent();
    1360        3169 :                         pLine->SetMaxAscent( (sal_uInt16)(pLine->GetMaxAscent() - nDiff) );
    1361        3169 :                         pLine->SetHeight( (sal_uInt16)nH, nTxtHeight );
    1362             :                     }
    1363             :                 }
    1364             :             }
    1365             :         }
    1366             : 
    1367       20930 :         if ( ( !IsVertical() && aStatus.AutoPageWidth() ) ||
    1368       10359 :              ( IsVertical() && aStatus.AutoPageHeight() ) )
    1369             :         {
    1370             :             // If the row fits within the current paper width, then this width
    1371             :             // has to be used for the Alignment. If it does not fit or if it
    1372             :             // will change the paper width, it will be formatted again for
    1373             :             // Justification! = LEFT anyway.
    1374         424 :             long nMaxLineWidthFix = ( !IsVertical() ? aPaperSize.Width() : aPaperSize.Height() )
    1375         424 :                                         - GetXValue( rLRItem.GetRight() ) - nStartX;
    1376         212 :             if ( aTextSize.Width() < nMaxLineWidthFix )
    1377         134 :                 nMaxLineWidth = nMaxLineWidthFix;
    1378             :         }
    1379             : 
    1380       10571 :         if ( bCompressedChars )
    1381             :         {
    1382           0 :             long nRemainingWidth = nMaxLineWidth - aTextSize.Width();
    1383           0 :             if ( nRemainingWidth > 0 )
    1384             :             {
    1385           0 :                 ImplExpandCompressedPortions( pLine, pParaPortion, nRemainingWidth );
    1386           0 :                 aTextSize = pLine->CalcTextSize( *pParaPortion );
    1387             :             }
    1388             :         }
    1389             : 
    1390       10571 :         if ( pLine->IsHangingPunctuation() )
    1391             :         {
    1392             :             // Width from HangingPunctuation was set to 0 in ImpBreakLine,
    1393             :             // check for rel width now, maybe create compression...
    1394           0 :             long n = nMaxLineWidth - aTextSize.Width();
    1395           0 :             TextPortion* const pTP = pParaPortion->GetTextPortions()[pLine->GetEndPortion()];
    1396           0 :             sal_uInt16 nPosInArray = pLine->GetEnd()-1-pLine->GetStart();
    1397           0 :             long nNewValue = ( nPosInArray ? pLine->GetCharPosArray()[ nPosInArray-1 ] : 0 ) + n;
    1398           0 :             pLine->GetCharPosArray()[ nPosInArray ] = nNewValue;
    1399           0 :             pTP->GetSize().Width() += n;
    1400             :         }
    1401             : 
    1402       10571 :         pLine->SetTextWidth( aTextSize.Width() );
    1403       10571 :         switch ( eJustification )
    1404             :         {
    1405             :             case SVX_ADJUST_CENTER:
    1406             :             {
    1407        3297 :                 long n = ( nMaxLineWidth - aTextSize.Width() ) / 2;
    1408        3297 :                 n += nStartX;  // Indentation is kept.
    1409        3297 :                 pLine->SetStartPosX( n );
    1410             :             }
    1411        3297 :             break;
    1412             :             case SVX_ADJUST_RIGHT:
    1413             :             {
    1414             :                 // For automatically wrapped lines, which has a blank at the end
    1415             :                 // the blank must not be displayed!
    1416          38 :                 long n = nMaxLineWidth - aTextSize.Width();
    1417          38 :                 n += nStartX;  // Indentation is kept.
    1418          38 :                 pLine->SetStartPosX( n );
    1419             :             }
    1420          38 :             break;
    1421             :             case SVX_ADJUST_BLOCK:
    1422             :             {
    1423           5 :                 bool bDistLastLine = (GetJustifyMethod(nPara) == SVX_JUSTIFY_METHOD_DISTRIBUTE);
    1424           5 :                 long nRemainingSpace = nMaxLineWidth - aTextSize.Width();
    1425           5 :                 pLine->SetStartPosX( nStartX );
    1426           5 :                 if ( nRemainingSpace > 0 && (!bEOC || bDistLastLine) )
    1427           1 :                     ImpAdjustBlocks( pParaPortion, pLine, nRemainingSpace );
    1428             :             }
    1429           5 :             break;
    1430             :             default:
    1431             :             {
    1432        7231 :                 pLine->SetStartPosX( nStartX ); // FI, LI
    1433             :             }
    1434        7231 :             break;
    1435             :         }
    1436             : 
    1437             :         // -----------------------------------------------------------------
    1438             :         // Check whether the line must be re-issued ...
    1439             :         // -----------------------------------------------------------------
    1440       10571 :         pLine->SetInvalid();
    1441             : 
    1442             :         // If a portion was wrapped there may be far too many positions in
    1443             :         // CharPosArray:
    1444       10571 :         if ( bCalcCharPositions )
    1445             :         {
    1446       10571 :             EditLine::CharPosArrayType& rArray = pLine->GetCharPosArray();
    1447       10571 :             size_t nLen = pLine->GetLen();
    1448       10571 :             if (rArray.size() > nLen)
    1449        3468 :                 rArray.erase(rArray.begin()+nLen, rArray.end());
    1450             :         }
    1451             : 
    1452       10571 :         if ( GetTextRanger() )
    1453             :         {
    1454           0 :             if ( nTextXOffset )
    1455           0 :                 pLine->SetStartPosX( pLine->GetStartPosX() + nTextXOffset );
    1456           0 :             if ( nTextExtraYOffset )
    1457             :             {
    1458           0 :                 pLine->SetHeight( (sal_uInt16) ( pLine->GetHeight() + nTextExtraYOffset ), 0, pLine->GetHeight() );
    1459           0 :                 pLine->SetMaxAscent( (sal_uInt16) ( pLine->GetMaxAscent() + nTextExtraYOffset ) );
    1460             :             }
    1461             :         }
    1462             : 
    1463             :         // for <0 think over !
    1464       10571 :         if ( pParaPortion->IsSimpleInvalid() )
    1465             :         {
    1466             :             // Change through simple Text changes ...
    1467             :             // Do mot cancel formatting since Portions possibly have to be split
    1468             :             // again! If at some point cancelable, then validate the following
    1469             :             // line! But if applicable, mark as valid, so there is less output...
    1470          49 :             if ( pLine->GetEnd() < nInvalidStart )
    1471             :             {
    1472           0 :                 if ( *pLine == aSaveLine )
    1473             :                 {
    1474           0 :                     pLine->SetValid();
    1475             :                 }
    1476             :             }
    1477             :             else
    1478             :             {
    1479          49 :                 sal_uInt16 nStart = pLine->GetStart();
    1480          49 :                 sal_uInt16 nEnd = pLine->GetEnd();
    1481             : 
    1482          49 :                 if ( nStart > nInvalidEnd )
    1483             :                 {
    1484           0 :                     if ( ( ( nStart-nInvalidDiff ) == aSaveLine.GetStart() ) &&
    1485           0 :                             ( ( nEnd-nInvalidDiff ) == aSaveLine.GetEnd() ) )
    1486             :                     {
    1487           0 :                         pLine->SetValid();
    1488           0 :                         if ( bCalcCharPositions && bQuickFormat )
    1489             :                         {
    1490           0 :                             bCalcCharPositions = sal_False;
    1491           0 :                             bLineBreak = sal_False;
    1492           0 :                             pParaPortion->CorrectValuesBehindLastFormattedLine( nLine );
    1493             :                             break;
    1494             :                         }
    1495             :                     }
    1496             :                 }
    1497          49 :                 else if ( bCalcCharPositions && bQuickFormat && ( nEnd > nInvalidEnd) )
    1498             :                 {
    1499             :                     // If the invalid line ends so that the next begins on the
    1500             :                     // 'same' passage as before, i.e. not wrapped differently,
    1501             :                     //  then the text width does not have to be determined anew:
    1502           4 :                     if ( nEnd == ( aSaveLine.GetEnd() + nInvalidDiff ) )
    1503             :                     {
    1504           4 :                         bCalcCharPositions = sal_False;
    1505           4 :                         bLineBreak = sal_False;
    1506           4 :                         pParaPortion->CorrectValuesBehindLastFormattedLine( nLine );
    1507             :                         break;
    1508             :                     }
    1509             :                 }
    1510             :             }
    1511             :         }
    1512             : 
    1513       10567 :         if ( !bSameLineAgain )
    1514             :         {
    1515       10567 :             nIndex = pLine->GetEnd();   // next line start = last line end
    1516             :                                         // as nEnd points to the last charecter!
    1517             : 
    1518       10567 :             sal_uInt16 nEndPortion = pLine->GetEndPortion();
    1519             : 
    1520             :             // Next line or maybe a new line....
    1521       10567 :             pLine = 0;
    1522       10567 :             if ( nLine < pParaPortion->GetLines().Count()-1 )
    1523           2 :                 pLine = pParaPortion->GetLines()[++nLine];
    1524       10567 :             if ( pLine && ( nIndex >= pNode->Len() ) )
    1525             :             {
    1526           0 :                 nDelFromLine = nLine;
    1527             :                 break;
    1528             :             }
    1529       10567 :             if ( !pLine )
    1530             :             {
    1531       10565 :                 if ( nIndex < pNode->Len() )
    1532             :                 {
    1533        3511 :                     pLine = new EditLine;
    1534        3511 :                     pParaPortion->GetLines().Insert(++nLine, pLine);
    1535             :                 }
    1536        7054 :                 else if ( nIndex && bLineBreak && GetTextRanger() )
    1537             :                 {
    1538             :                     // normaly CreateAndInsertEmptyLine would be called, but I want to use
    1539             :                     // CreateLines, so I need Polygon code only here...
    1540           0 :                     TextPortion* pDummyPortion = new TextPortion( 0 );
    1541           0 :                     pParaPortion->GetTextPortions().Append(pDummyPortion);
    1542           0 :                     pLine = new EditLine;
    1543           0 :                     pParaPortion->GetLines().Insert(++nLine, pLine);
    1544           0 :                     bForceOneRun = sal_True;
    1545           0 :                     bProcessingEmptyLine = sal_True;
    1546             :                 }
    1547             :             }
    1548       10567 :             if ( pLine )
    1549             :             {
    1550        3513 :                 aSaveLine = *pLine;
    1551        3513 :                 pLine->SetStart( nIndex );
    1552        3513 :                 pLine->SetEnd( nIndex );
    1553        3513 :                 pLine->SetStartPortion( nEndPortion+1 );
    1554        3513 :                 pLine->SetEndPortion( nEndPortion+1 );
    1555             :             }
    1556             :         }
    1557             :     }   // while ( Index < Len )
    1558             : 
    1559        7058 :     if ( nDelFromLine != 0xFFFF )
    1560           0 :         pParaPortion->GetLines().DeleteFromLine( nDelFromLine );
    1561             : 
    1562             :     DBG_ASSERT( pParaPortion->GetLines().Count(), "No line after CreateLines!" );
    1563             : 
    1564        7058 :     if ( bLineBreak == sal_True )
    1565           3 :         CreateAndInsertEmptyLine( pParaPortion, nStartPosY );
    1566             : 
    1567        7058 :     delete[] pBuf;
    1568             : 
    1569        7058 :     sal_Bool bHeightChanged = FinishCreateLines( pParaPortion );
    1570             : 
    1571        7058 :     if ( bMapChanged )
    1572           0 :         GetRefDevice()->Pop();
    1573             : 
    1574        7058 :     GetRefDevice()->Pop();
    1575             : 
    1576        7058 :     return bHeightChanged;
    1577             : }
    1578             : 
    1579       18036 : void ImpEditEngine::CreateAndInsertEmptyLine( ParaPortion* pParaPortion, sal_uInt32 )
    1580             : {
    1581             :     DBG_ASSERT( !GetTextRanger(), "Don't use CreateAndInsertEmptyLine with a polygon!" );
    1582             : 
    1583       18036 :     EditLine* pTmpLine = new EditLine;
    1584       18036 :     pTmpLine->SetStart( pParaPortion->GetNode()->Len() );
    1585       18036 :     pTmpLine->SetEnd( pParaPortion->GetNode()->Len() );
    1586       18036 :     pParaPortion->GetLines().Append(pTmpLine);
    1587             : 
    1588       18036 :     sal_Bool bLineBreak = pParaPortion->GetNode()->Len() ? sal_True : sal_False;
    1589       18036 :     sal_Int32 nSpaceBefore = 0;
    1590       18036 :     sal_Int32 nSpaceBeforeAndMinLabelWidth = GetSpaceBeforeAndMinLabelWidth( pParaPortion->GetNode(), &nSpaceBefore );
    1591       18036 :     const SvxLRSpaceItem& rLRItem = GetLRSpaceItem( pParaPortion->GetNode() );
    1592       18036 :     const SvxLineSpacingItem& rLSItem = (const SvxLineSpacingItem&)pParaPortion->GetNode()->GetContentAttribs().GetItem( EE_PARA_SBL );
    1593       18036 :     short nStartX = GetXValue( (short)(rLRItem.GetTxtLeft() + rLRItem.GetTxtFirstLineOfst() + nSpaceBefore));
    1594             : 
    1595       18036 :     Rectangle aBulletArea = Rectangle( Point(), Point() );
    1596       18036 :     if ( bLineBreak == sal_True )
    1597             :     {
    1598           3 :         nStartX = (short)GetXValue( rLRItem.GetTxtLeft() + rLRItem.GetTxtFirstLineOfst() + nSpaceBeforeAndMinLabelWidth );
    1599             :     }
    1600             :     else
    1601             :     {
    1602       18033 :         aBulletArea = GetEditEnginePtr()->GetBulletArea( GetParaPortions().GetPos( pParaPortion ) );
    1603       18033 :         if ( aBulletArea.Right() > 0 )
    1604           8 :             pParaPortion->SetBulletX( (sal_uInt16) GetXValue( aBulletArea.Right() ) );
    1605             :         else
    1606       18025 :             pParaPortion->SetBulletX( 0 ); // If Bullet set incorrectly.
    1607       18033 :         if ( pParaPortion->GetBulletX() > nStartX )
    1608             :         {
    1609           8 :             nStartX = (short)GetXValue( rLRItem.GetTxtLeft() + rLRItem.GetTxtFirstLineOfst() + nSpaceBeforeAndMinLabelWidth );
    1610           8 :             if ( pParaPortion->GetBulletX() > nStartX )
    1611           0 :                 nStartX = pParaPortion->GetBulletX();
    1612             :         }
    1613             :     }
    1614             : 
    1615       18036 :     SvxFont aTmpFont;
    1616       18036 :     SeekCursor( pParaPortion->GetNode(), bLineBreak ? pParaPortion->GetNode()->Len() : 0, aTmpFont );
    1617       18036 :     aTmpFont.SetPhysFont( pRefDev );
    1618             : 
    1619       18036 :     TextPortion* pDummyPortion = new TextPortion( 0 );
    1620       18036 :     pDummyPortion->GetSize() = aTmpFont.GetPhysTxtSize( pRefDev, String() );
    1621       18036 :     if ( IsFixedCellHeight() )
    1622        3104 :         pDummyPortion->GetSize().Height() = ImplCalculateFontIndependentLineSpacing( aTmpFont.GetHeight() );
    1623       18036 :     pParaPortion->GetTextPortions().Append(pDummyPortion);
    1624       18036 :     FormatterFontMetric aFormatterMetrics;
    1625       18036 :     RecalcFormatterFontMetrics( aFormatterMetrics, aTmpFont );
    1626       18036 :     pTmpLine->SetMaxAscent( aFormatterMetrics.nMaxAscent );
    1627       18036 :     pTmpLine->SetHeight( (sal_uInt16) pDummyPortion->GetSize().Height() );
    1628       18036 :     sal_uInt16 nLineHeight = aFormatterMetrics.GetHeight();
    1629       18036 :     if ( nLineHeight > pTmpLine->GetHeight() )
    1630          73 :         pTmpLine->SetHeight( nLineHeight );
    1631             : 
    1632       18036 :     if ( !aStatus.IsOutliner() )
    1633             :     {
    1634       18036 :         sal_uInt16 nPara = GetParaPortions().GetPos( pParaPortion );
    1635       18036 :         SvxAdjust eJustification = GetJustification( nPara );
    1636       18036 :         long nMaxLineWidth = !IsVertical() ? aPaperSize.Width() : aPaperSize.Height();
    1637       18036 :         nMaxLineWidth -= GetXValue( rLRItem.GetRight() );
    1638       18036 :         long nTextXOffset = 0;
    1639       18036 :         if ( nMaxLineWidth < 0 )
    1640           0 :             nMaxLineWidth = 1;
    1641       18036 :         if ( eJustification ==  SVX_ADJUST_CENTER )
    1642         208 :             nStartX = sal::static_int_cast< short >(nMaxLineWidth / 2);
    1643       17828 :         else if ( eJustification ==  SVX_ADJUST_RIGHT )
    1644           2 :             nStartX = sal::static_int_cast< short >(nMaxLineWidth);
    1645             : 
    1646       18036 :         nStartX = sal::static_int_cast< short >(nStartX + nTextXOffset);
    1647             :     }
    1648             : 
    1649       18036 :     pTmpLine->SetStartPosX( nStartX );
    1650             : 
    1651       18036 :     if ( !aStatus.IsOutliner() )
    1652             :     {
    1653       18036 :         if ( rLSItem.GetLineSpaceRule() == SVX_LINE_SPACE_MIN )
    1654             :         {
    1655           0 :             sal_uInt16 nMinHeight = rLSItem.GetLineHeight();
    1656           0 :             sal_uInt16 nTxtHeight = pTmpLine->GetHeight();
    1657           0 :             if ( nTxtHeight < nMinHeight )
    1658             :             {
    1659             :                 // The Ascent has to be adjusted for the difference:
    1660           0 :                 long nDiff = nMinHeight - nTxtHeight;
    1661           0 :                 pTmpLine->SetMaxAscent( (sal_uInt16)(pTmpLine->GetMaxAscent() + nDiff) );
    1662           0 :                 pTmpLine->SetHeight( nMinHeight, nTxtHeight );
    1663             :             }
    1664             :         }
    1665       18036 :         else if ( rLSItem.GetLineSpaceRule() == SVX_LINE_SPACE_FIX )
    1666             :         {
    1667           0 :             sal_uInt16 nFixHeight = rLSItem.GetLineHeight();
    1668           0 :             sal_uInt16 nTxtHeight = pTmpLine->GetHeight();
    1669             : 
    1670           0 :             pTmpLine->SetMaxAscent( (sal_uInt16)(pTmpLine->GetMaxAscent() + ( nFixHeight - nTxtHeight ) ) );
    1671           0 :             pTmpLine->SetHeight( nFixHeight, nTxtHeight );
    1672             :         }
    1673       18036 :         else if ( rLSItem.GetInterLineSpaceRule() == SVX_INTER_LINE_SPACE_PROP )
    1674             :         {
    1675         287 :             sal_uInt16 nPara = GetParaPortions().GetPos( pParaPortion );
    1676         287 :             if ( nPara || IsFixedCellHeight() || pTmpLine->GetStartPortion() ) // Not the very first line
    1677             :             {
    1678             :                 // There are documents with PropLineSpace 0, why?
    1679             :                 // (cmc: re above question :-) such documents can be seen by importing a .ppt
    1680         228 :                 if ( rLSItem.GetPropLineSpace() && ( rLSItem.GetPropLineSpace() != 100 ) )
    1681             :                 {
    1682         218 :                     sal_uInt16 nTxtHeight = pTmpLine->GetHeight();
    1683         218 :                     sal_Int32 nH = nTxtHeight;
    1684         218 :                     nH *= rLSItem.GetPropLineSpace();
    1685         218 :                     nH /= 100;
    1686             :                     // The Ascent has to be adjusted for the difference:
    1687         218 :                     long nDiff = pTmpLine->GetHeight() - nH;
    1688         218 :                     if ( nDiff > pTmpLine->GetMaxAscent() )
    1689           0 :                         nDiff = pTmpLine->GetMaxAscent();
    1690         218 :                     pTmpLine->SetMaxAscent( (sal_uInt16)(pTmpLine->GetMaxAscent() - nDiff) );
    1691         218 :                     pTmpLine->SetHeight( (sal_uInt16)nH, nTxtHeight );
    1692             :                 }
    1693             :             }
    1694             :         }
    1695             :     }
    1696             : 
    1697       18036 :     if ( !bLineBreak )
    1698             :     {
    1699       18033 :         long nMinHeight = aBulletArea.GetHeight();
    1700       18033 :         if ( nMinHeight > (long)pTmpLine->GetHeight() )
    1701             :         {
    1702           0 :             long nDiff = nMinHeight - (long)pTmpLine->GetHeight();
    1703             :             // distribute nDiff upwards and downwards
    1704           0 :             pTmpLine->SetMaxAscent( (sal_uInt16)(pTmpLine->GetMaxAscent() + nDiff/2) );
    1705           0 :             pTmpLine->SetHeight( (sal_uInt16)nMinHeight );
    1706             :         }
    1707             :     }
    1708             :     else
    1709             :     {
    1710             :         // -2: The new one is already inserted.
    1711             : #ifdef DBG_UTIL
    1712             :         EditLine* pLastLine = pParaPortion->GetLines()[pParaPortion->GetLines().Count()-2];
    1713             :         DBG_ASSERT( pLastLine, "soft wrap no line?!" );
    1714             :         DBG_ASSERT( pLastLine->GetEnd() == pParaPortion->GetNode()->Len(), "different anyway?" );
    1715             : #endif
    1716           3 :         sal_uInt16 nPos = (sal_uInt16) pParaPortion->GetTextPortions().Count() - 1 ;
    1717           3 :         pTmpLine->SetStartPortion( nPos );
    1718           3 :         pTmpLine->SetEndPortion( nPos );
    1719       18036 :     }
    1720       18036 : }
    1721             : 
    1722       25091 : sal_Bool ImpEditEngine::FinishCreateLines( ParaPortion* pParaPortion )
    1723             : {
    1724             : //  CalcCharPositions( pParaPortion );
    1725       25091 :     pParaPortion->SetValid();
    1726       25091 :     long nOldHeight = pParaPortion->GetHeight();
    1727       25091 :     CalcHeight( pParaPortion );
    1728             : 
    1729             :     DBG_ASSERT( pParaPortion->GetTextPortions().Count(), "FinishCreateLines: No Text-Portion?" );
    1730       25091 :     sal_Bool bRet = ( pParaPortion->GetHeight() != nOldHeight );
    1731       25091 :     return bRet;
    1732             : }
    1733             : 
    1734        4778 : void ImpEditEngine::ImpBreakLine( ParaPortion* pParaPortion, EditLine* pLine, TextPortion* pPortion, sal_uInt16 nPortionStart, long nRemainingWidth, sal_Bool bCanHyphenate )
    1735             : {
    1736        4778 :     ContentNode* const pNode = pParaPortion->GetNode();
    1737             : 
    1738        4778 :     sal_uInt16 nBreakInLine = nPortionStart - pLine->GetStart();
    1739        4778 :     sal_uInt16 nMax = nBreakInLine + pPortion->GetLen();
    1740       11464 :     while ( ( nBreakInLine < nMax ) && ( pLine->GetCharPosArray()[nBreakInLine] < nRemainingWidth ) )
    1741        1908 :         nBreakInLine++;
    1742             : 
    1743        4778 :     sal_uInt16 nMaxBreakPos = nBreakInLine + pLine->GetStart();
    1744        4778 :        sal_uInt16 nBreakPos = 0xFFFF;
    1745             : 
    1746        4778 :     sal_Bool bCompressBlank = sal_False;
    1747        4778 :     sal_Bool bHyphenated = sal_False;
    1748        4778 :     sal_Bool bHangingPunctuation = sal_False;
    1749        4778 :     sal_Unicode cAlternateReplChar = 0;
    1750        4778 :     sal_Unicode cAlternateExtraChar = 0;
    1751             : 
    1752        4778 :     if ( ( nMaxBreakPos < ( nMax + pLine->GetStart() ) ) && ( pNode->GetChar( nMaxBreakPos ) == ' ' ) )
    1753             :     {
    1754             :         // Break behind the blank, blank will be compressed...
    1755         507 :         nBreakPos = nMaxBreakPos + 1;
    1756         507 :         bCompressBlank = sal_True;
    1757             :     }
    1758             :     else
    1759             :     {
    1760        4271 :         sal_uInt16 nMinBreakPos = pLine->GetStart();
    1761        4271 :         const CharAttribList::AttribsType& rAttrs = pNode->GetCharAttribs().GetAttribs();
    1762       24470 :         for (size_t nAttr = rAttrs.size(); nAttr; )
    1763             :         {
    1764       15928 :             const EditCharAttrib& rAttr = rAttrs[--nAttr];
    1765       15928 :             if (rAttr.IsFeature() && rAttr.GetEnd() > nMinBreakPos && rAttr.GetEnd() <= nMaxBreakPos)
    1766             :             {
    1767           0 :                 nMinBreakPos = rAttr.GetEnd();
    1768           0 :                 break;
    1769             :             }
    1770             :         }
    1771             : 
    1772        4271 :         lang::Locale aLocale = GetLocale( EditPaM( pNode, nMaxBreakPos ) );
    1773             : 
    1774        4271 :         Reference < i18n::XBreakIterator > _xBI( ImplGetBreakIterator() );
    1775        4271 :         OUString aText = pNode->GetString();
    1776        4271 :         Reference< XHyphenator > xHyph;
    1777        4271 :         if ( bCanHyphenate )
    1778        2788 :             xHyph = GetHyphenator();
    1779        4271 :         i18n::LineBreakHyphenationOptions aHyphOptions( xHyph, Sequence< PropertyValue >(), 1 );
    1780        4271 :         i18n::LineBreakUserOptions aUserOptions;
    1781             : 
    1782        4271 :         const i18n::ForbiddenCharacters* pForbidden = GetForbiddenCharsTable()->GetForbiddenCharacters( LanguageTag( aLocale ).getLanguageType(), sal_True );
    1783        4271 :         aUserOptions.forbiddenBeginCharacters = pForbidden->beginLine;
    1784        4271 :         aUserOptions.forbiddenEndCharacters = pForbidden->endLine;
    1785        4271 :         aUserOptions.applyForbiddenRules = ((const SfxBoolItem&)pNode->GetContentAttribs().GetItem( EE_PARA_FORBIDDENRULES )).GetValue();
    1786        4271 :         aUserOptions.allowPunctuationOutsideMargin = ((const SfxBoolItem&)pNode->GetContentAttribs().GetItem( EE_PARA_HANGINGPUNCTUATION )).GetValue();
    1787        4271 :         aUserOptions.allowHyphenateEnglish = sal_False;
    1788             : 
    1789        4271 :         i18n::LineBreakResults aLBR = _xBI->getLineBreak(
    1790        4271 :             pNode->GetString(), nMaxBreakPos, aLocale, nMinBreakPos, aHyphOptions, aUserOptions );
    1791        4271 :         nBreakPos = (sal_uInt16)aLBR.breakIndex;
    1792             : 
    1793             :         // BUG in I18N - under special condition (break behind field, #87327#) breakIndex is < nMinBreakPos
    1794        4271 :         if ( nBreakPos < nMinBreakPos )
    1795             :         {
    1796        2515 :             nBreakPos = nMinBreakPos;
    1797             :         }
    1798        1756 :         else if ( ( nBreakPos > nMaxBreakPos ) && !aUserOptions.allowPunctuationOutsideMargin )
    1799             :         {
    1800             :             OSL_FAIL( "I18N: XBreakIterator::getLineBreak returns position > Max" );
    1801           0 :             nBreakPos = nMaxBreakPos;
    1802             :         }
    1803             : 
    1804             :         // nBreakPos can never be outside the portion, even not with hangig punctuation
    1805        4271 :         if ( nBreakPos > nMaxBreakPos )
    1806           0 :             nBreakPos = nMaxBreakPos;
    1807             : 
    1808             :         // BUG in I18N - the japanese dot is in the next line!
    1809             :         // !!!  Test!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    1810        4271 :         if ( (nBreakPos + ( aUserOptions.allowPunctuationOutsideMargin ? 0 : 1 ) ) <= nMaxBreakPos )
    1811             :         {
    1812          34 :             sal_Unicode cFirstInNextLine = ( (nBreakPos+1) < pNode->Len() ) ? pNode->GetChar( nBreakPos ) : 0;
    1813          34 :             if ( cFirstInNextLine == 12290 )
    1814           0 :                 nBreakPos++;
    1815             :         }
    1816             : 
    1817        4271 :         bHangingPunctuation = ( nBreakPos > nMaxBreakPos ) ? sal_True : sal_False;
    1818        4271 :         pLine->SetHangingPunctuation( bHangingPunctuation );
    1819             : 
    1820             :         // Whether a separator or not, push the word after the separator through
    1821             :         // hyphenation ... NMaxBreakPos is the last character that fits into
    1822             :         // the line, nBreakPos is the beginning of the word.
    1823             :         // There is a problem if the Doc is so narrow that a word is broken
    1824             :         // into more than two lines ...
    1825        4271 :         if ( !bHangingPunctuation && bCanHyphenate && GetHyphenator().is() )
    1826             :         {
    1827        2788 :             i18n::Boundary aBoundary = _xBI->getWordBoundary(
    1828        2788 :                 pNode->GetString(), nBreakPos, GetLocale( EditPaM( pNode, nBreakPos ) ), ::com::sun::star::i18n::WordType::DICTIONARY_WORD, true);
    1829        2788 :             sal_uInt16 nWordStart = nBreakPos;
    1830        2788 :             sal_uInt16 nWordEnd = (sal_uInt16) aBoundary.endPos;
    1831             :             DBG_ASSERT( nWordEnd > nWordStart, "ImpBreakLine: Start >= End?" );
    1832             : 
    1833        2788 :             sal_uInt16 nWordLen = nWordEnd - nWordStart;
    1834        2788 :             if ( ( nWordEnd >= nMaxBreakPos ) && ( nWordLen > 3 ) )
    1835             :             {
    1836             :                 // May happen, because getLineBreak may differ from getWordBoudary with DICTIONARY_WORD
    1837         369 :                 String aWord(pNode->GetString(), nWordStart, nWordLen);
    1838         369 :                 sal_uInt16 nMinTrail = nWordEnd-nMaxBreakPos+1; //+1: Before the dickey letter
    1839         369 :                 Reference< XHyphenatedWord > xHyphWord;
    1840         369 :                 if (xHyphenator.is())
    1841         369 :                     xHyphWord = xHyphenator->hyphenate( aWord, aLocale, aWord.Len() - nMinTrail, Sequence< PropertyValue >() );
    1842         369 :                 if (xHyphWord.is())
    1843             :                 {
    1844           0 :                     sal_Bool bAlternate = xHyphWord->isAlternativeSpelling();
    1845           0 :                     sal_uInt16 _nWordLen = 1 + xHyphWord->getHyphenPos();
    1846             : 
    1847           0 :                     if ( ( _nWordLen >= 2 ) && ( (nWordStart+_nWordLen) >= (pLine->GetStart() + 2 ) ) )
    1848             :                     {
    1849           0 :                         if ( !bAlternate )
    1850             :                         {
    1851           0 :                             bHyphenated = sal_True;
    1852           0 :                             nBreakPos = nWordStart + _nWordLen;
    1853             :                         }
    1854             :                         else
    1855             :                         {
    1856           0 :                             String aAlt( xHyphWord->getHyphenatedWord() );
    1857             : 
    1858             :                             // We expect the two cases, which might exist now:
    1859             :                             // 1) packen becomes pak-ken
    1860             :                             // 2) Schiffahrt becomes Schiff-fahrt
    1861             :                             // In case 1, a character has to be replaced
    1862             :                             // in case 2 a character is added.
    1863             :                             // The identification is complicated by long
    1864             :                             // compound words because the Hyphenator separates
    1865             :                             // all position of the word.
    1866             :                             // "Schiffahrtsbrennesseln" -> "Schifffahrtsbrennnesseln"
    1867             :                  // We can thus actually not directly connect the index of the
    1868             :                             // AlternativeWord to aWord. The whole issue will be simplified
    1869             :                             // by a function in the  Hyphenator as soon as AMA builds this in...
    1870           0 :                             sal_uInt16 nAltStart = _nWordLen - 1;
    1871           0 :                             sal_uInt16 nTxtStart = nAltStart - (aAlt.Len() - aWord.Len());
    1872           0 :                             sal_uInt16 nTxtEnd = nTxtStart;
    1873           0 :                             sal_uInt16 nAltEnd = nAltStart;
    1874             : 
    1875             :                             // The regions between the nStart and nEnd is the
    1876             :                             // difference between alternative and original string.
    1877           0 :                             while( nTxtEnd < aWord.Len() && nAltEnd < aAlt.Len() &&
    1878           0 :                                    aWord.GetChar(nTxtEnd) != aAlt.GetChar(nAltEnd) )
    1879             :                             {
    1880           0 :                                 ++nTxtEnd;
    1881           0 :                                 ++nAltEnd;
    1882             :                             }
    1883             : 
    1884             :                             // If a character is added, then we notice it now:
    1885           0 :                             if( nAltEnd > nTxtEnd && nAltStart == nAltEnd &&
    1886           0 :                                 aWord.GetChar( nTxtEnd ) == aAlt.GetChar(nAltEnd) )
    1887             :                             {
    1888           0 :                                 ++nAltEnd;
    1889           0 :                                 ++nTxtStart;
    1890           0 :                                 ++nTxtEnd;
    1891             :                             }
    1892             : 
    1893             :                             DBG_ASSERT( ( nAltEnd - nAltStart ) == 1, "Alternate: Wrong assumption!" );
    1894             : 
    1895           0 :                             if ( nTxtEnd > nTxtStart )
    1896           0 :                                 cAlternateReplChar = aAlt.GetChar( nAltStart );
    1897             :                             else
    1898           0 :                                 cAlternateExtraChar = aAlt.GetChar( nAltStart );
    1899             : 
    1900           0 :                             bHyphenated = sal_True;
    1901           0 :                             nBreakPos = nWordStart + nTxtStart;
    1902           0 :                             if ( cAlternateReplChar )
    1903           0 :                                 nBreakPos++;
    1904             :                         }
    1905             :                     }
    1906         369 :                 }
    1907             :             }
    1908             :         }
    1909             : 
    1910        4271 :         if ( nBreakPos <= pLine->GetStart() )
    1911             :         {
    1912             :             // No separator in line => Chop!
    1913        4238 :             nBreakPos = nMaxBreakPos;
    1914             :             // I18N nextCharacters !
    1915        4238 :             if ( nBreakPos <= pLine->GetStart() )
    1916        4236 :                 nBreakPos = pLine->GetStart() + 1;  // Otherwise infinite loop!
    1917        4271 :         }
    1918             :     }
    1919             : 
    1920             :     // the dickey portion is the end portion
    1921        4778 :     pLine->SetEnd( nBreakPos );
    1922             : 
    1923        4778 :     sal_uInt16 nEndPortion = SplitTextPortion( pParaPortion, nBreakPos, pLine );
    1924             : 
    1925        4778 :     if ( !bCompressBlank && !bHangingPunctuation )
    1926             :     {
    1927             :         // When justification is not SVX_ADJUST_LEFT, it's important to compress
    1928             :         // the trailing space even if there is enough room for the space...
    1929             :         // Don't check for SVX_ADJUST_LEFT, doesn't matter to compress in this case too...
    1930             :         DBG_ASSERT( nBreakPos > pLine->GetStart(), "ImpBreakLines - BreakPos not expected!" );
    1931        4271 :         if ( pNode->GetChar( nBreakPos-1 ) == ' ' )
    1932          33 :             bCompressBlank = sal_True;
    1933             :     }
    1934             : 
    1935        4778 :     if ( bCompressBlank || bHangingPunctuation )
    1936             :     {
    1937         540 :         TextPortion* const pTP = pParaPortion->GetTextPortions()[nEndPortion];
    1938             :         DBG_ASSERT( pTP->GetKind() == PORTIONKIND_TEXT, "BlankRubber: No TextPortion!" );
    1939             :         DBG_ASSERT( nBreakPos > pLine->GetStart(), "SplitTextPortion at the beginning of the line?" );
    1940         540 :         sal_uInt16 nPosInArray = nBreakPos - 1 - pLine->GetStart();
    1941         540 :         pTP->GetSize().Width() = ( nPosInArray && ( pTP->GetLen() > 1 ) ) ? pLine->GetCharPosArray()[ nPosInArray-1 ] : 0;
    1942         540 :         pLine->GetCharPosArray()[ nPosInArray ] = pTP->GetSize().Width();
    1943             :     }
    1944        4238 :     else if ( bHyphenated )
    1945             :     {
    1946             :         // A portion for inserting the separator ...
    1947           0 :         TextPortion* pHyphPortion = new TextPortion( 0 );
    1948           0 :         pHyphPortion->GetKind() = PORTIONKIND_HYPHENATOR;
    1949           0 :         String aHyphText(rtl::OUString(CH_HYPH));
    1950           0 :         if ( cAlternateReplChar )
    1951             :         {
    1952           0 :             TextPortion* pPrev = pParaPortion->GetTextPortions()[nEndPortion];
    1953             :             DBG_ASSERT( pPrev && pPrev->GetLen(), "Hyphenate: Prev portion?!" );
    1954           0 :             pPrev->SetLen( pPrev->GetLen() - 1 );
    1955           0 :             pHyphPortion->SetLen( 1 );
    1956           0 :             pHyphPortion->SetExtraValue( cAlternateReplChar );
    1957             :             // Correct width of the portion above:
    1958           0 :             pPrev->GetSize().Width() =
    1959           0 :                 pLine->GetCharPosArray()[ nBreakPos-1 - pLine->GetStart() - 1 ];
    1960             :         }
    1961           0 :         else if ( cAlternateExtraChar )
    1962             :         {
    1963           0 :             pHyphPortion->SetExtraValue( cAlternateExtraChar );
    1964           0 :             aHyphText.Insert( rtl::OUString(cAlternateExtraChar), 0 );
    1965             :         }
    1966             : 
    1967             :         // Determine the width of the Hyph-Portion:
    1968           0 :         SvxFont aFont;
    1969           0 :         SeekCursor( pParaPortion->GetNode(), nBreakPos, aFont );
    1970           0 :         aFont.SetPhysFont( GetRefDevice() );
    1971           0 :         pHyphPortion->GetSize().Height() = GetRefDevice()->GetTextHeight();
    1972           0 :         pHyphPortion->GetSize().Width() = GetRefDevice()->GetTextWidth( aHyphText );
    1973             : 
    1974           0 :         pParaPortion->GetTextPortions().Insert(++nEndPortion, pHyphPortion);
    1975             :     }
    1976        4778 :     pLine->SetEndPortion( nEndPortion );
    1977        4778 : }
    1978             : 
    1979           1 : void ImpEditEngine::ImpAdjustBlocks( ParaPortion* pParaPortion, EditLine* pLine, long nRemainingSpace )
    1980             : {
    1981             :     DBG_ASSERT( nRemainingSpace > 0, "AdjustBlocks: Somewhat too little..." );
    1982             :     DBG_ASSERT( pLine, "AdjustBlocks: Line ?!" );
    1983           1 :     if ( ( nRemainingSpace < 0 ) || pLine->IsEmpty() )
    1984             :         return ;
    1985             : 
    1986           1 :     const sal_uInt16 nFirstChar = pLine->GetStart();
    1987           1 :     const sal_uInt16 nLastChar = pLine->GetEnd() -1;    // Last points behind
    1988           1 :     ContentNode* pNode = pParaPortion->GetNode();
    1989             : 
    1990             :     DBG_ASSERT( nLastChar < pNode->Len(), "AdjustBlocks: Out of range!" );
    1991             : 
    1992             :     // Search blanks or Kashidas...
    1993           1 :     std::vector<sal_uInt16> aPositions;
    1994           1 :     sal_uInt16 nLastScript = i18n::ScriptType::LATIN;
    1995           2 :     for ( sal_uInt16 nChar = nFirstChar; nChar <= nLastChar; nChar++ )
    1996             :     {
    1997           1 :         EditPaM aPaM( pNode, nChar+1 );
    1998           1 :         LanguageType eLang = GetLanguage(aPaM);
    1999           1 :         sal_uInt16 nScript = GetScriptType(aPaM);
    2000           1 :         if ( MsLangId::getPrimaryLanguage( eLang) == LANGUAGE_ARABIC_PRIMARY_ONLY )
    2001             :             // Arabic script is handled later.
    2002           0 :             continue;
    2003             : 
    2004           1 :         if ( pNode->GetChar(nChar) == ' ' )
    2005             :         {
    2006             :             // Normal latin script.
    2007           1 :             aPositions.push_back( nChar );
    2008             :         }
    2009           0 :         else if (nChar > nFirstChar)
    2010             :         {
    2011           0 :             if (nLastScript == i18n::ScriptType::ASIAN)
    2012             :             {
    2013             :                 // Set break position between this and the last character if
    2014             :                 // the last character is asian script.
    2015           0 :                 aPositions.push_back( nChar-1 );
    2016             :             }
    2017           0 :             else if (nScript == i18n::ScriptType::ASIAN)
    2018             :             {
    2019             :                 // Set break position between a latin script and asian script.
    2020           0 :                 aPositions.push_back( nChar-1 );
    2021             :             }
    2022             :         }
    2023             : 
    2024           1 :         nLastScript = nScript;
    2025             :     }
    2026             : 
    2027             :     // Kashidas ?
    2028           1 :     ImpFindKashidas( pNode, nFirstChar, nLastChar, aPositions );
    2029             : 
    2030           1 :     if ( aPositions.empty() )
    2031             :         return;
    2032             : 
    2033             :     // If the last character is a blank, it is rejected!
    2034             :     // The width must be distributed to the blockers in front...
    2035             :     // But not if it is the only one.
    2036           2 :     if ( ( pNode->GetChar( nLastChar ) == ' ' ) && ( aPositions.size() > 1 ) &&
    2037           1 :          ( MsLangId::getPrimaryLanguage( GetLanguage( EditPaM( pNode, nLastChar ) ) ) != LANGUAGE_ARABIC_PRIMARY_ONLY ) )
    2038             :     {
    2039           0 :         aPositions.pop_back();
    2040             :         sal_uInt16 nPortionStart, nPortion;
    2041           0 :         nPortion = pParaPortion->GetTextPortions().FindPortion( nLastChar+1, nPortionStart );
    2042           0 :         TextPortion* pLastPortion = pParaPortion->GetTextPortions()[ nPortion ];
    2043           0 :         long nRealWidth = pLine->GetCharPosArray()[nLastChar-nFirstChar];
    2044           0 :         long nBlankWidth = nRealWidth;
    2045           0 :         if ( nLastChar > nPortionStart )
    2046           0 :             nBlankWidth -= pLine->GetCharPosArray()[nLastChar-nFirstChar-1];
    2047             :         // Possibly the blank has already been deducted in ImpBreakLine:
    2048           0 :         if ( nRealWidth == pLastPortion->GetSize().Width() )
    2049             :         {
    2050             :             // For the last character the portion must stop behind the blank
    2051             :             // => Simplify correction:
    2052             :             DBG_ASSERT( ( nPortionStart + pLastPortion->GetLen() ) == ( nLastChar+1 ), "Blank actually not at the end of the portion!?");
    2053           0 :             pLastPortion->GetSize().Width() -= nBlankWidth;
    2054           0 :             nRemainingSpace += nBlankWidth;
    2055             :         }
    2056           0 :         pLine->GetCharPosArray()[nLastChar-nFirstChar] -= nBlankWidth;
    2057             :     }
    2058             : 
    2059           1 :     size_t nGaps = aPositions.size();
    2060           1 :     const long nMore4Everyone = nRemainingSpace / nGaps;
    2061           1 :     long nSomeExtraSpace = nRemainingSpace - nMore4Everyone*nGaps;
    2062             : 
    2063             :     DBG_ASSERT( nSomeExtraSpace < (long)nGaps, "AdjustBlocks: ExtraSpace too large" );
    2064             :     DBG_ASSERT( nSomeExtraSpace >= 0, "AdjustBlocks: ExtraSpace < 0 " );
    2065             : 
    2066             :     // Correct the positions in the Array and the portion widths:
    2067             :     // Last character won't be considered ...
    2068           2 :     for ( std::vector<sal_uInt16>::const_iterator it(aPositions.begin()); it != aPositions.end(); ++it )
    2069             :     {
    2070           1 :         sal_uInt16 nChar = *it;
    2071           1 :         if ( nChar < nLastChar )
    2072             :         {
    2073             :             sal_uInt16 nPortionStart, nPortion;
    2074           0 :             nPortion = pParaPortion->GetTextPortions().FindPortion( nChar, nPortionStart, true );
    2075           0 :             TextPortion* pLastPortion = pParaPortion->GetTextPortions()[ nPortion ];
    2076             : 
    2077             :             // The width of the portion:
    2078           0 :             pLastPortion->GetSize().Width() += nMore4Everyone;
    2079           0 :             if ( nSomeExtraSpace )
    2080           0 :                 pLastPortion->GetSize().Width()++;
    2081             : 
    2082             :             // Correct positions in array
    2083             :             // Even for kashidas just change positions, VCL will then draw the kashida automaticly
    2084           0 :             sal_uInt16 nPortionEnd = nPortionStart + pLastPortion->GetLen();
    2085           0 :             for ( sal_uInt16 _n = nChar; _n < nPortionEnd; _n++ )
    2086             :             {
    2087           0 :                 pLine->GetCharPosArray()[_n-nFirstChar] += nMore4Everyone;
    2088           0 :                 if ( nSomeExtraSpace )
    2089           0 :                     pLine->GetCharPosArray()[_n-nFirstChar]++;
    2090             :             }
    2091             : 
    2092           0 :             if ( nSomeExtraSpace )
    2093           0 :                 nSomeExtraSpace--;
    2094             :         }
    2095             :     }
    2096             : 
    2097             :     // Now the text width contains the extra width...
    2098           1 :     pLine->SetTextWidth( pLine->GetTextWidth() + nRemainingSpace );
    2099             : }
    2100             : 
    2101           1 : void ImpEditEngine::ImpFindKashidas( ContentNode* pNode, sal_uInt16 nStart, sal_uInt16 nEnd, std::vector<sal_uInt16>& rArray )
    2102             : {
    2103             :     // the search has to be performed on a per word base
    2104             : 
    2105           1 :     EditSelection aWordSel( EditPaM( pNode, nStart ) );
    2106           1 :     aWordSel = SelectWord( aWordSel, ::com::sun::star::i18n::WordType::DICTIONARY_WORD );
    2107           1 :     if ( aWordSel.Min().GetIndex() < nStart )
    2108           0 :        aWordSel.Min().GetIndex() = nStart;
    2109             : 
    2110           2 :     while ( ( aWordSel.Min().GetNode() == pNode ) && ( aWordSel.Min().GetIndex() < nEnd ) )
    2111             :     {
    2112           0 :         sal_uInt16 nSavPos = aWordSel.Max().GetIndex();
    2113           0 :         if ( aWordSel.Max().GetIndex() > nEnd )
    2114           0 :            aWordSel.Max().GetIndex() = nEnd;
    2115             : 
    2116           0 :         String aWord = GetSelected( aWordSel );
    2117             : 
    2118             :         // restore selection for proper iteration at the end of the function
    2119           0 :         aWordSel.Max().GetIndex() = nSavPos;
    2120             : 
    2121           0 :         xub_StrLen nIdx = 0;
    2122           0 :         xub_StrLen nKashidaPos = STRING_LEN;
    2123             :         sal_Unicode cCh;
    2124           0 :         sal_Unicode cPrevCh = 0;
    2125             : 
    2126           0 :         while ( nIdx < aWord.Len() )
    2127             :         {
    2128           0 :             cCh = aWord.GetChar( nIdx );
    2129             : 
    2130             :             // 1. Priority:
    2131             :             // after user inserted kashida
    2132           0 :             if ( 0x640 == cCh )
    2133             :             {
    2134           0 :                 nKashidaPos = aWordSel.Min().GetIndex() + nIdx;
    2135           0 :                 break;
    2136             :             }
    2137             : 
    2138             :             // 2. Priority:
    2139             :             // after a Seen or Sad
    2140           0 :             if ( nIdx + 1 < aWord.Len() &&
    2141             :                  ( 0x633 == cCh || 0x635 == cCh ) )
    2142             :             {
    2143           0 :                 nKashidaPos = aWordSel.Min().GetIndex() + nIdx;
    2144           0 :                 break;
    2145             :             }
    2146             : 
    2147             :             // 3. Priority:
    2148             :             // before final form of Teh Marbuta, Hah, Dal
    2149             :             // 4. Priority:
    2150             :             // before final form of Alef, Lam or Kaf
    2151           0 :             if ( nIdx && nIdx + 1 == aWord.Len() &&
    2152             :                  ( 0x629 == cCh || 0x62D == cCh || 0x62F == cCh ||
    2153             :                    0x627 == cCh || 0x644 == cCh || 0x643 == cCh ) )
    2154             :             {
    2155             :                 DBG_ASSERT( 0 != cPrevCh, "No previous character" );
    2156             : 
    2157             :                 // check if character is connectable to previous character,
    2158           0 :                 if ( lcl_ConnectToPrev( cCh, cPrevCh ) )
    2159             :                 {
    2160           0 :                     nKashidaPos = aWordSel.Min().GetIndex() + nIdx - 1;
    2161           0 :                     break;
    2162             :                 }
    2163             :             }
    2164             : 
    2165             :             // 5. Priority:
    2166             :             // before media Bah
    2167           0 :             if ( nIdx && nIdx + 1 < aWord.Len() && 0x628 == cCh )
    2168             :             {
    2169             :                 DBG_ASSERT( 0 != cPrevCh, "No previous character" );
    2170             : 
    2171             :                 // check if next character is Reh, Yeh or Alef Maksura
    2172           0 :                 sal_Unicode cNextCh = aWord.GetChar( nIdx + 1 );
    2173             : 
    2174           0 :                 if ( 0x631 == cNextCh || 0x64A == cNextCh ||
    2175             :                      0x649 == cNextCh )
    2176             :                 {
    2177             :                     // check if character is connectable to previous character,
    2178           0 :                     if ( lcl_ConnectToPrev( cCh, cPrevCh ) )
    2179           0 :                         nKashidaPos = aWordSel.Min().GetIndex() + nIdx - 1;
    2180             :                 }
    2181             :             }
    2182             : 
    2183             :             // 6. Priority:
    2184             :             // other connecting possibilities
    2185           0 :             if ( nIdx && nIdx + 1 == aWord.Len() &&
    2186             :                  0x60C <= cCh && 0x6FE >= cCh )
    2187             :             {
    2188             :                 DBG_ASSERT( 0 != cPrevCh, "No previous character" );
    2189             : 
    2190             :                 // check if character is connectable to previous character,
    2191           0 :                 if ( lcl_ConnectToPrev( cCh, cPrevCh ) )
    2192             :                 {
    2193             :                     // only choose this position if we did not find
    2194             :                     // a better one:
    2195           0 :                     if ( STRING_LEN == nKashidaPos )
    2196           0 :                         nKashidaPos = aWordSel.Min().GetIndex() + nIdx - 1;
    2197           0 :                     break;
    2198             :                 }
    2199             :             }
    2200             : 
    2201             :             // Do not consider Fathatan, Dammatan, Kasratan, Fatha,
    2202             :             // Damma, Kasra, Shadda and Sukun when checking if
    2203             :             // a character can be connected to previous character.
    2204           0 :             if ( cCh < 0x64B || cCh > 0x652 )
    2205           0 :                 cPrevCh = cCh;
    2206             : 
    2207           0 :             ++nIdx;
    2208             :         } // end of current word
    2209             : 
    2210           0 :         if ( STRING_LEN != nKashidaPos )
    2211           0 :             rArray.push_back( nKashidaPos );
    2212             : 
    2213           0 :         aWordSel = WordRight( aWordSel.Max(), ::com::sun::star::i18n::WordType::DICTIONARY_WORD );
    2214           0 :         aWordSel = SelectWord( aWordSel, ::com::sun::star::i18n::WordType::DICTIONARY_WORD );
    2215           0 :     }
    2216           1 : }
    2217             : 
    2218        4778 : sal_uInt16 ImpEditEngine::SplitTextPortion( ParaPortion* pPortion, sal_uInt16 nPos, EditLine* pCurLine )
    2219             : {
    2220             :     DBG_ASSERT( pPortion, "SplitTextPortion: Which ?" );
    2221             : 
    2222             :     // The portion at nPos is split, if there is not a transition at nPos anyway
    2223        4778 :     if ( nPos == 0 )
    2224           0 :         return 0;
    2225             : 
    2226             :     sal_uInt16 nSplitPortion;
    2227        4778 :     sal_uInt16 nTmpPos = 0;
    2228        4778 :     TextPortion* pTextPortion = NULL;
    2229        4778 :     sal_uInt16 nPortions = pPortion->GetTextPortions().Count();
    2230       15725 :     for ( nSplitPortion = 0; nSplitPortion < nPortions; nSplitPortion++ )
    2231             :     {
    2232       15725 :         TextPortion* pTP = pPortion->GetTextPortions()[nSplitPortion];
    2233       15725 :         nTmpPos = nTmpPos + pTP->GetLen();
    2234       15725 :         if ( nTmpPos >= nPos )
    2235             :         {
    2236        4778 :             if ( nTmpPos == nPos )  // then nothing needs to be split
    2237             :             {
    2238        1312 :                 return nSplitPortion;
    2239             :             }
    2240        3466 :             pTextPortion = pTP;
    2241        3466 :             break;
    2242             :         }
    2243             :     }
    2244             : 
    2245             :     DBG_ASSERT( pTextPortion, "Position outside the area!" );
    2246             :     DBG_ASSERT( pTextPortion->GetKind() == PORTIONKIND_TEXT, "SplitTextPortion: No TextPortion!" );
    2247             : 
    2248        3466 :     sal_uInt16 nOverlapp = nTmpPos - nPos;
    2249        3466 :     pTextPortion->GetLen() = pTextPortion->GetLen() - nOverlapp;
    2250        3466 :     TextPortion* pNewPortion = new TextPortion( nOverlapp );
    2251        3466 :     pPortion->GetTextPortions().Insert(nSplitPortion+1, pNewPortion);
    2252             :     // Set sizes
    2253        3466 :     if ( pCurLine )
    2254             :     {
    2255             :         // No new GetTextSize, instead use values from the Array:
    2256             :         DBG_ASSERT( nPos > pCurLine->GetStart(), "SplitTextPortion at the beginning of the line?" );
    2257        3466 :         pTextPortion->GetSize().Width() = pCurLine->GetCharPosArray()[ nPos-pCurLine->GetStart()-1 ];
    2258             : 
    2259        3466 :         if ( pTextPortion->GetExtraInfos() && pTextPortion->GetExtraInfos()->bCompressed )
    2260             :         {
    2261             :             // We need the original size from the portion
    2262           0 :             sal_uInt16 nTxtPortionStart = pPortion->GetTextPortions().GetStartPos( nSplitPortion );
    2263           0 :                SvxFont aTmpFont( pPortion->GetNode()->GetCharAttribs().GetDefFont() );
    2264           0 :             SeekCursor( pPortion->GetNode(), nTxtPortionStart+1, aTmpFont );
    2265           0 :             aTmpFont.SetPhysFont( GetRefDevice() );
    2266           0 :             GetRefDevice()->Push( PUSH_TEXTLANGUAGE );
    2267           0 :             ImplInitDigitMode( GetRefDevice(), 0, 0, 0, aTmpFont.GetLanguage() );
    2268           0 :             Size aSz = aTmpFont.QuickGetTextSize( GetRefDevice(), pPortion->GetNode()->GetString(), nTxtPortionStart, pTextPortion->GetLen(), NULL );
    2269           0 :             GetRefDevice()->Pop();
    2270           0 :             pTextPortion->GetExtraInfos()->nOrgWidth = aSz.Width();
    2271             :         }
    2272             :     }
    2273             :     else
    2274           0 :         pTextPortion->GetSize().Width() = (-1);
    2275             : 
    2276        3466 :     return nSplitPortion;
    2277             : }
    2278             : 
    2279        7013 : void ImpEditEngine::CreateTextPortions( ParaPortion* pParaPortion, sal_uInt16& rStart )
    2280             : {
    2281        7013 :     sal_uInt16 nStartPos = rStart;
    2282        7013 :     ContentNode* pNode = pParaPortion->GetNode();
    2283             :     DBG_ASSERT( pNode->Len(), "CreateTextPortions should not be used for empty paragraphs!" );
    2284             : 
    2285        7013 :     ::std::set< sal_uInt32 > aPositions;
    2286        7013 :     aPositions.insert( 0 );
    2287             : 
    2288        7013 :     sal_uInt16 nAttr = 0;
    2289        7013 :     EditCharAttrib* pAttrib = GetAttrib( pNode->GetCharAttribs().GetAttribs(), nAttr );
    2290       40075 :     while ( pAttrib )
    2291             :     {
    2292             :         // Insert Start and End into the Array...
    2293             :         // The Insert method does not allow for duplicate values....
    2294       26049 :         aPositions.insert( pAttrib->GetStart() );
    2295       26049 :         aPositions.insert( pAttrib->GetEnd() );
    2296       26049 :         nAttr++;
    2297       26049 :         pAttrib = GetAttrib( pNode->GetCharAttribs().GetAttribs(), nAttr );
    2298             :     }
    2299        7013 :     aPositions.insert( pNode->Len() );
    2300             : 
    2301        7013 :     if ( pParaPortion->aScriptInfos.empty() )
    2302           0 :         ((ImpEditEngine*)this)->InitScriptTypes( GetParaPortions().GetPos( pParaPortion ) );
    2303             : 
    2304        7013 :     const ScriptTypePosInfos& rTypes = pParaPortion->aScriptInfos;
    2305       14178 :     for ( size_t nT = 0; nT < rTypes.size(); nT++ )
    2306        7165 :         aPositions.insert( rTypes[nT].nStartPos );
    2307             : 
    2308        7013 :     const WritingDirectionInfos& rWritingDirections = pParaPortion->aWritingDirectionInfos;
    2309       14026 :     for ( size_t nD = 0; nD < rWritingDirections.size(); nD++ )
    2310        7013 :         aPositions.insert( rWritingDirections[nD].nStartPos );
    2311             : 
    2312        7013 :     if ( mpIMEInfos && mpIMEInfos->nLen && mpIMEInfos->pAttribs && ( mpIMEInfos->aPos.GetNode() == pNode ) )
    2313             :     {
    2314           0 :         sal_uInt16 nLastAttr = 0xFFFF;
    2315           0 :         for( sal_uInt16 n = 0; n < mpIMEInfos->nLen; n++ )
    2316             :         {
    2317           0 :             if ( mpIMEInfos->pAttribs[n] != nLastAttr )
    2318             :             {
    2319           0 :                 aPositions.insert( mpIMEInfos->aPos.GetIndex() + n );
    2320           0 :                 nLastAttr = mpIMEInfos->pAttribs[n];
    2321             :             }
    2322             :         }
    2323           0 :         aPositions.insert( mpIMEInfos->aPos.GetIndex() + mpIMEInfos->nLen );
    2324             :     }
    2325             : 
    2326             :     // From ... Delete:
    2327             :     // Unfortunately, the number of text portions does not have to match
    2328             :     // aPositions.Count(), since there might be line breaks...
    2329        7013 :     sal_uInt16 nPortionStart = 0;
    2330        7013 :     sal_uInt16 nInvPortion = 0;
    2331             :     sal_uInt16 nP;
    2332        7013 :     for ( nP = 0; nP < pParaPortion->GetTextPortions().Count(); nP++ )
    2333             :     {
    2334         173 :         const TextPortion* pTmpPortion = pParaPortion->GetTextPortions()[nP];
    2335         173 :         nPortionStart = nPortionStart + pTmpPortion->GetLen();
    2336         173 :         if ( nPortionStart >= nStartPos )
    2337             :         {
    2338         173 :             nPortionStart = nPortionStart - pTmpPortion->GetLen();
    2339         173 :             rStart = nPortionStart;
    2340         173 :             nInvPortion = nP;
    2341         173 :             break;
    2342             :         }
    2343             :     }
    2344             :     DBG_ASSERT( nP < pParaPortion->GetTextPortions().Count() || !pParaPortion->GetTextPortions().Count(), "Nothing to delete: CreateTextPortions" );
    2345        7013 :     if ( nInvPortion && ( nPortionStart+pParaPortion->GetTextPortions()[nInvPortion]->GetLen() > nStartPos ) )
    2346             :     {
    2347             :         // prefer one in front ...
    2348             :         // But only if it was in the middle of the portion of, otherwise it
    2349             :         // might be the only one in the row in front!
    2350           0 :         nInvPortion--;
    2351           0 :         nPortionStart = nPortionStart - pParaPortion->GetTextPortions()[nInvPortion]->GetLen();
    2352             :     }
    2353        7013 :     pParaPortion->GetTextPortions().DeleteFromPortion( nInvPortion );
    2354             : 
    2355             :     // A portion may also have been formed by a line break:
    2356        7013 :     aPositions.insert( nPortionStart );
    2357             : 
    2358        7013 :     ::std::set< sal_uInt32 >::iterator nInvPos = aPositions.find(  nPortionStart );
    2359             :     DBG_ASSERT( (nInvPos != aPositions.end()), "InvPos ?!" );
    2360             : 
    2361        7013 :     ::std::set< sal_uInt32 >::iterator i = nInvPos;
    2362        7013 :     ++i;
    2363       21933 :     while ( i != aPositions.end() )
    2364             :     {
    2365        7907 :         TextPortion* pNew = new TextPortion( static_cast<sal_uInt16>(*i++) - static_cast<sal_uInt16>(*nInvPos++) );
    2366        7907 :         pParaPortion->GetTextPortions().Append(pNew);
    2367             :     }
    2368             : 
    2369        7013 :     DBG_ASSERT( pParaPortion->GetTextPortions().Count(), "No Portions?!" );
    2370             : #if OSL_DEBUG_LEVEL > 2
    2371             :     OSL_ENSURE( pParaPortion->DbgCheckTextPortions(), "Portion is broken?" );
    2372             : #endif
    2373        7013 : }
    2374             : 
    2375          45 : void ImpEditEngine::RecalcTextPortion( ParaPortion* pParaPortion, sal_uInt16 nStartPos, short nNewChars )
    2376             : {
    2377             :     DBG_ASSERT( pParaPortion->GetTextPortions().Count(), "No Portions!" );
    2378             :     DBG_ASSERT( nNewChars, "RecalcTextPortion with Diff == 0" );
    2379             : 
    2380          45 :     ContentNode* const pNode = pParaPortion->GetNode();
    2381          45 :     if ( nNewChars > 0 )
    2382             :     {
    2383             :         // If an Attribute begins/ends at nStartPos, then a new portion starts
    2384             :         // otherwise the portion is extended at nStartPos.
    2385          42 :         if ( pNode->GetCharAttribs().HasBoundingAttrib( nStartPos ) || IsScriptChange( EditPaM( pNode, nStartPos ) ) )
    2386             :         {
    2387          40 :             sal_uInt16 nNewPortionPos = 0;
    2388          40 :             if ( nStartPos )
    2389           0 :                 nNewPortionPos = SplitTextPortion( pParaPortion, nStartPos ) + 1;
    2390             : 
    2391             :             // A blank portion may be here, if the paragraph was empty,
    2392             :             // or if a line was created by a hard line break.
    2393          80 :             if ( ( nNewPortionPos < pParaPortion->GetTextPortions().Count() ) &&
    2394          40 :                     !pParaPortion->GetTextPortions()[nNewPortionPos]->GetLen() )
    2395             :             {
    2396             :                 DBG_ASSERT( pParaPortion->GetTextPortions()[nNewPortionPos]->GetKind() == PORTIONKIND_TEXT, "the empty portion was no TextPortion!" );
    2397             :                 sal_uInt16 & r =
    2398          39 :                     pParaPortion->GetTextPortions()[nNewPortionPos]->GetLen();
    2399          39 :                 r = r + nNewChars;
    2400             :             }
    2401             :             else
    2402             :             {
    2403           1 :                 TextPortion* pNewPortion = new TextPortion( nNewChars );
    2404           1 :                 pParaPortion->GetTextPortions().Insert(nNewPortionPos, pNewPortion);
    2405             :             }
    2406             :         }
    2407             :         else
    2408             :         {
    2409             :             sal_uInt16 nPortionStart;
    2410           2 :             const sal_uInt16 nTP = pParaPortion->GetTextPortions().
    2411           4 :                 FindPortion( nStartPos, nPortionStart );
    2412           2 :             TextPortion* const pTP = pParaPortion->GetTextPortions()[ nTP ];
    2413             :             DBG_ASSERT( pTP, "RecalcTextPortion: Portion not found"  );
    2414           2 :             pTP->GetLen() = pTP->GetLen() + nNewChars;
    2415           2 :             pTP->GetSize().Width() = (-1);
    2416             :         }
    2417             :     }
    2418             :     else
    2419             :     {
    2420             :         // Shrink or remove portion if necessary.
    2421             :         // Before calling this method it must be ensured that no portions were
    2422             :         // in the deleted area!
    2423             : 
    2424             :         // There must be no portions extending into the area or portions starting in
    2425             :         // the area, so it must be:
    2426             :         //    nStartPos <= nPos <= nStartPos - nNewChars(neg.)
    2427           3 :         sal_uInt16 nPortion = 0;
    2428           3 :         sal_uInt16 nPos = 0;
    2429           3 :         sal_uInt16 nEnd = nStartPos-nNewChars;
    2430           3 :         sal_uInt16 nPortions = pParaPortion->GetTextPortions().Count();
    2431           3 :         TextPortion* pTP = 0;
    2432           5 :         for ( nPortion = 0; nPortion < nPortions; nPortion++ )
    2433             :         {
    2434           5 :             pTP = pParaPortion->GetTextPortions()[ nPortion ];
    2435           5 :             if ( ( nPos+pTP->GetLen() ) > nStartPos )
    2436             :             {
    2437             :                 DBG_ASSERT( nPos <= nStartPos, "Wrong Start!" );
    2438             :                 DBG_ASSERT( nPos+pTP->GetLen() >= nEnd, "Wrong End!" );
    2439           3 :                 break;
    2440             :             }
    2441           2 :             nPos = nPos + pTP->GetLen();
    2442             :         }
    2443             :         DBG_ASSERT( pTP, "RecalcTextPortion: Portion not found" );
    2444           3 :         if ( ( nPos == nStartPos ) && ( (nPos+pTP->GetLen()) == nEnd ) )
    2445             :         {
    2446             :             // Remove portion;
    2447           0 :             sal_uInt8 nType = pTP->GetKind();
    2448           0 :             pParaPortion->GetTextPortions().Remove( nPortion );
    2449           0 :             if ( nType == PORTIONKIND_LINEBREAK )
    2450             :             {
    2451           0 :                 TextPortion* pNext = pParaPortion->GetTextPortions()[ nPortion ];
    2452           0 :                 if ( pNext && !pNext->GetLen() )
    2453             :                 {
    2454             :                     // Remove dummy portion
    2455           0 :                     pParaPortion->GetTextPortions().Remove( nPortion );
    2456             :                 }
    2457             :             }
    2458             :         }
    2459             :         else
    2460             :         {
    2461             :             DBG_ASSERT( pTP->GetLen() > (-nNewChars), "Portion too small to shrink! ");
    2462           3 :             pTP->GetLen() = pTP->GetLen() + nNewChars;
    2463             :         }
    2464             : 
    2465           3 :         sal_uInt16 nPortionCount = pParaPortion->GetTextPortions().Count();
    2466             :         assert( nPortionCount );
    2467           3 :         if (nPortionCount)
    2468             :         {
    2469             :             // No HYPHENATOR portion is allowed to get stuck right at the end...
    2470           3 :             sal_uInt16 nLastPortion = nPortionCount - 1;
    2471           3 :             pTP = pParaPortion->GetTextPortions()[nLastPortion];
    2472           3 :             if ( pTP->GetKind() == PORTIONKIND_HYPHENATOR )
    2473             :             {
    2474             :                 // Discard portion; if possible, correct the ones before,
    2475             :                 // if the Hyphenator portion has swallowed one character...
    2476           0 :                 if ( nLastPortion && pTP->GetLen() )
    2477             :                 {
    2478           0 :                     TextPortion* pPrev = pParaPortion->GetTextPortions()[nLastPortion - 1];
    2479             :                     DBG_ASSERT( pPrev->GetKind() == PORTIONKIND_TEXT, "Portion?!" );
    2480           0 :                     pPrev->SetLen( pPrev->GetLen() + pTP->GetLen() );
    2481           0 :                     pPrev->GetSize().Width() = (-1);
    2482             :                 }
    2483           0 :                 pParaPortion->GetTextPortions().Remove( nLastPortion );
    2484             :             }
    2485             :         }
    2486             :     }
    2487             : #if OSL_DEBUG_LEVEL > 2
    2488             :     OSL_ENSURE( pParaPortion->DbgCheckTextPortions(), "Portions are broken?" );
    2489             : #endif
    2490          45 : }
    2491             : 
    2492       25161 : void ImpEditEngine::SetTextRanger( TextRanger* pRanger )
    2493             : {
    2494       25161 :     if ( pTextRanger != pRanger )
    2495             :     {
    2496           0 :         delete pTextRanger;
    2497           0 :         pTextRanger = pRanger;
    2498             : 
    2499           0 :         for ( sal_uInt16 nPara = 0; nPara < GetParaPortions().Count(); nPara++ )
    2500             :         {
    2501           0 :             ParaPortion* pParaPortion = GetParaPortions()[nPara];
    2502           0 :             pParaPortion->MarkSelectionInvalid( 0, pParaPortion->GetNode()->Len() );
    2503           0 :             pParaPortion->GetLines().Reset();
    2504             :         }
    2505             : 
    2506           0 :         FormatFullDoc();
    2507           0 :         UpdateViews( GetActiveView() );
    2508           0 :         if ( GetUpdateMode() && GetActiveView() )
    2509           0 :             pActiveView->ShowCursor(false, false);
    2510             :     }
    2511       25161 : }
    2512             : 
    2513       14548 : void ImpEditEngine::SetVertical( sal_Bool bVertical )
    2514             : {
    2515       14548 :     if ( IsVertical() != bVertical )
    2516             :     {
    2517           0 :         GetEditDoc().SetVertical( bVertical );
    2518           0 :         sal_Bool bUseCharAttribs = ( aStatus.GetControlWord() & EE_CNTRL_USECHARATTRIBS ) ? sal_True : sal_False;
    2519           0 :         GetEditDoc().CreateDefFont( bUseCharAttribs );
    2520           0 :         if ( IsFormatted() )
    2521             :         {
    2522           0 :             FormatFullDoc();
    2523           0 :             UpdateViews( GetActiveView() );
    2524             :         }
    2525             :     }
    2526       14548 : }
    2527             : 
    2528        4204 : void ImpEditEngine::SetFixedCellHeight( sal_Bool bUseFixedCellHeight )
    2529             : {
    2530        4204 :     if ( IsFixedCellHeight() != bUseFixedCellHeight )
    2531             :     {
    2532           5 :         GetEditDoc().SetFixedCellHeight( bUseFixedCellHeight );
    2533           5 :         if ( IsFormatted() )
    2534             :         {
    2535           5 :             FormatFullDoc();
    2536           5 :             UpdateViews( GetActiveView() );
    2537             :         }
    2538             :     }
    2539        4204 : }
    2540             : 
    2541       41237 : void ImpEditEngine::SeekCursor( ContentNode* pNode, sal_uInt16 nPos, SvxFont& rFont, OutputDevice* pOut, sal_uInt16 nIgnoreWhich )
    2542             : {
    2543             :     // It was planned, SeekCursor( nStartPos, nEndPos, ... ), so that it would
    2544             :     // only be searched anew at the StartPosition.
    2545             :     // Problem: There would be two lists to consider/handle:
    2546             :     // OrderedByStart,OrderedByEnd.
    2547             : 
    2548       41237 :     if ( nPos > pNode->Len() )
    2549          87 :         nPos = pNode->Len();
    2550             : 
    2551       41237 :     rFont = pNode->GetCharAttribs().GetDefFont();
    2552             : 
    2553       41237 :     short nScriptType = GetScriptType( EditPaM( pNode, nPos ) );
    2554       41237 :     if ( ( nScriptType == i18n::ScriptType::ASIAN ) || ( nScriptType == i18n::ScriptType::COMPLEX ) )
    2555             :     {
    2556          14 :         const SvxFontItem& rFontItem = (const SvxFontItem&)pNode->GetContentAttribs().GetItem( GetScriptItemId( EE_CHAR_FONTINFO, nScriptType ) );
    2557          14 :         rFont.SetName( rFontItem.GetFamilyName() );
    2558          14 :         rFont.SetFamily( rFontItem.GetFamily() );
    2559          14 :         rFont.SetPitch( rFontItem.GetPitch() );
    2560          14 :         rFont.SetCharSet( rFontItem.GetCharSet() );
    2561          14 :         Size aSz( rFont.GetSize() );
    2562          14 :         aSz.Height() = ((const SvxFontHeightItem&)pNode->GetContentAttribs().GetItem( GetScriptItemId( EE_CHAR_FONTHEIGHT, nScriptType ) ) ).GetHeight();
    2563          14 :         rFont.SetSize( aSz );
    2564          14 :         rFont.SetWeight( ((const SvxWeightItem&)pNode->GetContentAttribs().GetItem( GetScriptItemId( EE_CHAR_WEIGHT, nScriptType ))).GetWeight() );
    2565          14 :         rFont.SetItalic( ((const SvxPostureItem&)pNode->GetContentAttribs().GetItem( GetScriptItemId( EE_CHAR_ITALIC, nScriptType ))).GetPosture() );
    2566          14 :         rFont.SetLanguage( ((const SvxLanguageItem&)pNode->GetContentAttribs().GetItem( GetScriptItemId( EE_CHAR_LANGUAGE, nScriptType ))).GetLanguage() );
    2567             :     }
    2568             : 
    2569       41237 :     sal_uInt16 nRelWidth = ((const SvxCharScaleWidthItem&)pNode->GetContentAttribs().GetItem( EE_CHAR_FONTWIDTH)).GetValue();
    2570             : 
    2571       41237 :     if ( pOut )
    2572             :     {
    2573         245 :         const SvxUnderlineItem& rTextLineColor = (const SvxUnderlineItem&)pNode->GetContentAttribs().GetItem( EE_CHAR_UNDERLINE );
    2574         245 :         if ( rTextLineColor.GetColor() != COL_TRANSPARENT )
    2575           0 :             pOut->SetTextLineColor( rTextLineColor.GetColor() );
    2576             :         else
    2577         245 :             pOut->SetTextLineColor();
    2578             :     }
    2579             : 
    2580       41237 :     if ( pOut )
    2581             :     {
    2582         245 :         const SvxOverlineItem& rOverlineColor = (const SvxOverlineItem&)pNode->GetContentAttribs().GetItem( EE_CHAR_OVERLINE );
    2583         245 :         if ( rOverlineColor.GetColor() != COL_TRANSPARENT )
    2584           0 :             pOut->SetOverlineColor( rOverlineColor.GetColor() );
    2585             :         else
    2586         245 :             pOut->SetOverlineColor();
    2587             :     }
    2588             : 
    2589       41237 :     const SvxLanguageItem* pCJKLanguageItem = NULL;
    2590             : 
    2591       41237 :     if ( aStatus.UseCharAttribs() )
    2592             :     {
    2593       41237 :         CharAttribList::AttribsType& rAttribs = pNode->GetCharAttribs().GetAttribs();
    2594       41237 :         size_t nAttr = 0;
    2595       41237 :         EditCharAttrib* pAttrib = GetAttrib(rAttribs, nAttr);
    2596      174784 :         while ( pAttrib && ( pAttrib->GetStart() <= nPos ) )
    2597             :         {
    2598             :             // when seeking, ignore attributes which start there! Empty attributes
    2599             :             // are considered (used) as these are just set. But do not use empty
    2600             :             // attributes: When just set and empty => no effect on font
    2601             :             // In a blank paragraph, set characters take effect immediately.
    2602      280075 :             if ( ( pAttrib->Which() != nIgnoreWhich ) &&
    2603      179993 :                  ( ( ( pAttrib->GetStart() < nPos ) && ( pAttrib->GetEnd() >= nPos ) )
    2604        7772 :                      || ( !pNode->Len() ) ) )
    2605             :             {
    2606             :                 DBG_ASSERT( ( pAttrib->Which() >= EE_CHAR_START ) && ( pAttrib->Which() <= EE_FEATURE_END ), "Invalid Attribute in Seek() " );
    2607       88662 :                 if ( IsScriptItemValid( pAttrib->Which(), nScriptType ) )
    2608             :                 {
    2609       39524 :                     pAttrib->SetFont( rFont, pOut );
    2610             :                     // #i1550# hard color attrib should win over text color from field
    2611       39524 :                     if ( pAttrib->Which() == EE_FEATURE_FIELD )
    2612             :                     {
    2613        1192 :                         EditCharAttrib* pColorAttr = pNode->GetCharAttribs().FindAttrib( EE_CHAR_COLOR, nPos );
    2614        1192 :                         if ( pColorAttr )
    2615         192 :                             pColorAttr->SetFont( rFont, pOut );
    2616             :                     }
    2617             :                 }
    2618       88662 :                 if ( pAttrib->Which() == EE_CHAR_FONTWIDTH )
    2619          80 :                     nRelWidth = ((const SvxCharScaleWidthItem*)pAttrib->GetItem())->GetValue();
    2620       88662 :                 if ( pAttrib->Which() == EE_CHAR_LANGUAGE_CJK )
    2621        7394 :                     pCJKLanguageItem = (const SvxLanguageItem*) pAttrib->GetItem();
    2622             :             }
    2623       92310 :             pAttrib = GetAttrib( rAttribs, ++nAttr );
    2624             :         }
    2625             :     }
    2626             : 
    2627       41237 :     if ( !pCJKLanguageItem )
    2628       33843 :         pCJKLanguageItem = (const SvxLanguageItem*) &pNode->GetContentAttribs().GetItem( EE_CHAR_LANGUAGE_CJK );
    2629             : 
    2630       41237 :     rFont.SetCJKContextLanguage( pCJKLanguageItem->GetLanguage() );
    2631             : 
    2632       41237 :     if ( rFont.GetKerning() && IsKernAsianPunctuation() && ( nScriptType == i18n::ScriptType::ASIAN ) )
    2633           0 :         rFont.SetKerning( rFont.GetKerning() | KERNING_ASIAN );
    2634             : 
    2635       41237 :     if ( aStatus.DoNotUseColors() )
    2636             :     {
    2637           0 :         rFont.SetColor( /* rColorItem.GetValue() */ COL_BLACK );
    2638             :     }
    2639             : 
    2640       41237 :     if ( aStatus.DoStretch() || ( nRelWidth != 100 ) )
    2641             :     {
    2642             :         // For the current Output device, because otherwise if RefDev=Printer its looks
    2643             :         // ugly on the screen!
    2644          44 :         OutputDevice* pDev = pOut ? pOut : GetRefDevice();
    2645          44 :         rFont.SetPhysFont( pDev );
    2646          44 :         Size aRealSz( rFont.GetSize().Width(), rFont.GetSize().Height() );
    2647          44 :         if ( aStatus.DoStretch() )
    2648             :         {
    2649          44 :             if ( nStretchY != 100 )
    2650             :             {
    2651           0 :                 aRealSz.Height() *= nStretchY;
    2652           0 :                 aRealSz.Height() /= 100;
    2653             :             }
    2654          44 :             if ( nStretchX != 100 )
    2655             :             {
    2656           0 :                 if ( nStretchX == nStretchY &&
    2657             :                      nRelWidth == 100 )
    2658             :                 {
    2659           0 :                     aRealSz.Width() = 0;
    2660             :                 }
    2661             :                 else
    2662             :                 {
    2663           0 :                     aRealSz.Width() *= nStretchX;
    2664           0 :                     aRealSz.Width() /= 100;
    2665             : 
    2666             :                     // Also the Kerning: (long due to handle Interim results)
    2667           0 :                     long nKerning = rFont.GetFixKerning();
    2668             : /*
    2669             :   The consideration was: If negative kerning, but StretchX = 200
    2670             :   => Do not double the kerning, thus pull the letters closer together
    2671             :   ---------------------------
    2672             :   Kern  StretchX    =>Kern
    2673             :   ---------------------------
    2674             :   >0        <100        < (Proportional)
    2675             :   <0        <100        < (Proportional)
    2676             :   >0        >100        > (Proportional)
    2677             :   <0        >100        < (The amount, thus disproportional)
    2678             : */
    2679           0 :                     if ( ( nKerning < 0  ) && ( nStretchX > 100 ) )
    2680             :                     {
    2681             :                         // disproportional
    2682           0 :                         nKerning *= 100;
    2683           0 :                         nKerning /= nStretchX;
    2684             :                     }
    2685           0 :                     else if ( nKerning )
    2686             :                     {
    2687             :                         // Proportional
    2688           0 :                         nKerning *= nStretchX;
    2689           0 :                         nKerning /= 100;
    2690             :                     }
    2691           0 :                     rFont.SetFixKerning( (short)nKerning );
    2692             :                 }
    2693             :             }
    2694             :         }
    2695          44 :         if ( nRelWidth != 100 )
    2696             :         {
    2697           0 :             aRealSz.Width() *= nRelWidth;
    2698           0 :             aRealSz.Width() /= 100;
    2699             :         }
    2700          44 :         rFont.SetSize( aRealSz );
    2701             :         // Font is not restored ...
    2702             :     }
    2703             : 
    2704       41237 :     if ( ( ( rFont.GetColor() == COL_AUTO ) || ( IsForceAutoColor() ) ) && pOut )
    2705             :     {
    2706             :         // #i75566# Do not use AutoColor when printing OR Pdf export
    2707         137 :         const bool bPrinting(OUTDEV_PRINTER == pOut->GetOutDevType());
    2708         137 :         const bool bPDFExporting(0 != pOut->GetPDFWriter());
    2709             : 
    2710         137 :         if ( IsAutoColorEnabled() && !bPrinting && !bPDFExporting)
    2711             :         {
    2712             :             // Never use WindowTextColor on the printer
    2713         137 :             rFont.SetColor( GetAutoColor() );
    2714             :         }
    2715             :         else
    2716             :         {
    2717           0 :             if ( ( GetBackgroundColor() != COL_AUTO ) && GetBackgroundColor().IsDark() )
    2718           0 :                 rFont.SetColor( COL_WHITE );
    2719             :             else
    2720           0 :                 rFont.SetColor( COL_BLACK );
    2721             :         }
    2722             :     }
    2723             : 
    2724       41237 :     if ( mpIMEInfos && mpIMEInfos->pAttribs && ( mpIMEInfos->aPos.GetNode() == pNode ) &&
    2725           0 :         ( nPos > mpIMEInfos->aPos.GetIndex() ) && ( nPos <= ( mpIMEInfos->aPos.GetIndex() + mpIMEInfos->nLen ) ) )
    2726             :     {
    2727           0 :         sal_uInt16 nAttr = mpIMEInfos->pAttribs[ nPos - mpIMEInfos->aPos.GetIndex() - 1 ];
    2728           0 :         if ( nAttr & EXTTEXTINPUT_ATTR_UNDERLINE )
    2729           0 :             rFont.SetUnderline( UNDERLINE_SINGLE );
    2730           0 :         else if ( nAttr & EXTTEXTINPUT_ATTR_BOLDUNDERLINE )
    2731           0 :             rFont.SetUnderline( UNDERLINE_BOLD );
    2732           0 :         else if ( nAttr & EXTTEXTINPUT_ATTR_DOTTEDUNDERLINE )
    2733           0 :             rFont.SetUnderline( UNDERLINE_DOTTED );
    2734           0 :         else if ( nAttr & EXTTEXTINPUT_ATTR_DASHDOTUNDERLINE )
    2735           0 :             rFont.SetUnderline( UNDERLINE_DOTTED );
    2736           0 :         else if ( nAttr & EXTTEXTINPUT_ATTR_REDTEXT )
    2737           0 :             rFont.SetColor( Color( COL_RED ) );
    2738           0 :         else if ( nAttr & EXTTEXTINPUT_ATTR_HALFTONETEXT )
    2739           0 :             rFont.SetColor( Color( COL_LIGHTGRAY ) );
    2740           0 :         if ( nAttr & EXTTEXTINPUT_ATTR_HIGHLIGHT )
    2741             :         {
    2742           0 :             const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
    2743           0 :             rFont.SetColor( rStyleSettings.GetHighlightTextColor() );
    2744           0 :             rFont.SetFillColor( rStyleSettings.GetHighlightColor() );
    2745           0 :             rFont.SetTransparent( sal_False );
    2746             :         }
    2747           0 :         else if ( nAttr & EXTTEXTINPUT_ATTR_GRAYWAVELINE )
    2748             :         {
    2749           0 :             rFont.SetUnderline( UNDERLINE_WAVE );
    2750           0 :             if( pOut )
    2751           0 :                 pOut->SetTextLineColor( Color( COL_LIGHTGRAY ) );
    2752             :         }
    2753             :     }
    2754       41237 : }
    2755             : 
    2756       29456 : void ImpEditEngine::RecalcFormatterFontMetrics( FormatterFontMetric& rCurMetrics, SvxFont& rFont )
    2757             : {
    2758             :     // for line height at high / low first without Propr!
    2759       29456 :     sal_uInt16 nPropr = rFont.GetPropr();
    2760             :     DBG_ASSERT( ( nPropr == 100 ) || rFont.GetEscapement(), "Propr without Escape?!" );
    2761       29456 :     if ( nPropr != 100 )
    2762             :     {
    2763         111 :         rFont.SetPropr( 100 );
    2764         111 :         rFont.SetPhysFont( pRefDev );
    2765             :     }
    2766             :     sal_uInt16 nAscent, nDescent;
    2767             : 
    2768       29456 :     FontMetric aMetric( pRefDev->GetFontMetric() );
    2769       29456 :     nAscent = (sal_uInt16)aMetric.GetAscent();
    2770       29456 :     if ( IsAddExtLeading() )
    2771             :         nAscent = sal::static_int_cast< sal_uInt16 >(
    2772         264 :             nAscent + aMetric.GetExtLeading() );
    2773       29456 :     nDescent = (sal_uInt16)aMetric.GetDescent();
    2774             : 
    2775       29456 :     if ( IsFixedCellHeight() )
    2776             :     {
    2777        6844 :         nAscent = sal::static_int_cast< sal_uInt16 >( rFont.GetHeight() );
    2778        6844 :         nDescent= sal::static_int_cast< sal_uInt16 >( ImplCalculateFontIndependentLineSpacing( rFont.GetHeight() ) - nAscent );
    2779             :     }
    2780             :     else
    2781             :     {
    2782       22612 :         sal_uInt16 nIntLeading = ( aMetric.GetIntLeading() > 0 ) ? (sal_uInt16)aMetric.GetIntLeading() : 0;
    2783             :         // Fonts without leading cause problems
    2784       22612 :         if ( ( nIntLeading == 0 ) && ( pRefDev->GetOutDevType() == OUTDEV_PRINTER ) )
    2785             :         {
    2786             :             // Lets see what Leading one gets on the screen
    2787           0 :             VirtualDevice* pVDev = GetVirtualDevice( pRefDev->GetMapMode(), pRefDev->GetDrawMode() );
    2788           0 :             rFont.SetPhysFont( pVDev );
    2789           0 :             aMetric = pVDev->GetFontMetric();
    2790             : 
    2791             :             // This is so that the Leading does not count itself out again,
    2792             :             // if the whole line has the font, nTmpLeading.
    2793           0 :             nAscent = (sal_uInt16)aMetric.GetAscent();
    2794           0 :             nDescent = (sal_uInt16)aMetric.GetDescent();
    2795             :         }
    2796             :     }
    2797       29456 :     if ( nAscent > rCurMetrics.nMaxAscent )
    2798       28610 :         rCurMetrics.nMaxAscent = nAscent;
    2799       29456 :     if ( nDescent > rCurMetrics.nMaxDescent )
    2800       28610 :         rCurMetrics.nMaxDescent= nDescent;
    2801             :     // Special treatment of high/low:
    2802       29456 :     if ( rFont.GetEscapement() )
    2803             :     {
    2804             :         // Now in consideration of Escape/Propr
    2805             :         // possibly enlarge Ascent or Descent
    2806         111 :         short nDiff = (short)(rFont.GetSize().Height()*rFont.GetEscapement()/100L);
    2807         111 :         if ( rFont.GetEscapement() > 0 )
    2808             :         {
    2809           0 :             nAscent = (sal_uInt16) (((long)nAscent)*nPropr/100 + nDiff);
    2810           0 :             if ( nAscent > rCurMetrics.nMaxAscent )
    2811           0 :                 rCurMetrics.nMaxAscent = nAscent;
    2812             :         }
    2813             :         else    // has to be < 0
    2814             :         {
    2815         111 :             nDescent = (sal_uInt16) (((long)nDescent)*nPropr/100 - nDiff);
    2816         111 :             if ( nDescent > rCurMetrics.nMaxDescent )
    2817         110 :                 rCurMetrics.nMaxDescent= nDescent;
    2818             :         }
    2819       29456 :     }
    2820       29456 : }
    2821             : 
    2822         140 : void ImpEditEngine::Paint( OutputDevice* pOutDev, Rectangle aClipRec, Point aStartPos, sal_Bool bStripOnly, short nOrientation )
    2823             : {
    2824         140 :     if ( !GetUpdateMode() && !bStripOnly )
    2825             :         return;
    2826             : 
    2827         140 :     if ( !IsFormatted() )
    2828           0 :         FormatDoc();
    2829             : 
    2830         140 :     long nFirstVisXPos = - pOutDev->GetMapMode().GetOrigin().X();
    2831         140 :     long nFirstVisYPos = - pOutDev->GetMapMode().GetOrigin().Y();
    2832             : 
    2833         140 :     const EditLine* pLine = NULL;
    2834         140 :     Point aTmpPos;
    2835         140 :     Point aRedLineTmpPos;
    2836             :     DBG_ASSERT( GetParaPortions().Count(), "No ParaPortion?!" );
    2837         140 :     SvxFont aTmpFont( GetParaPortions()[0]->GetNode()->GetCharAttribs().GetDefFont() );
    2838         140 :     Font aOldFont( pOutDev->GetFont() );
    2839         140 :     vcl::PDFExtOutDevData* pPDFExtOutDevData = PTR_CAST( vcl::PDFExtOutDevData, pOutDev->GetExtOutDevData() );
    2840             : 
    2841             :     // In the case of rotated text is aStartPos considered TopLeft because
    2842             :     // other information is missing, and since the whole object is shown anyway
    2843             :     // un-scrolled.
    2844             :     // The rectangle is infinite.
    2845         140 :     Point aOrigin( aStartPos );
    2846         140 :     double nCos = 0.0, nSin = 0.0;
    2847         140 :     if ( nOrientation )
    2848             :     {
    2849           0 :         double nRealOrientation = nOrientation*F_PI1800;
    2850           0 :         nCos = cos( nRealOrientation );
    2851           0 :         nSin = sin( nRealOrientation );
    2852             :     }
    2853             : 
    2854             :     // #110496# Added some more optional metafile comments. This
    2855             :     // change: factored out some duplicated code.
    2856         140 :     GDIMetaFile* pMtf = pOutDev->GetConnectMetaFile();
    2857         140 :     const bool bMetafileValid( pMtf != NULL );
    2858             : 
    2859         140 :     long nVertLineSpacing = CalcVertLineSpacing(aStartPos);
    2860             : 
    2861             :     // --------------------------------------------------
    2862             :     // Over all the paragraphs ...
    2863             :     // --------------------------------------------------
    2864         273 :     for ( sal_uInt16 n = 0; n < GetParaPortions().Count(); n++ )
    2865             :     {
    2866         164 :         const ParaPortion* pPortion = GetParaPortions()[n];
    2867             :         DBG_ASSERT( pPortion, "NULL-Pointer in TokenList in Paint" );
    2868             :         // if when typing idle formatting,  asynchronous Paint.
    2869             :         // Invisible Portions may be invalid.
    2870         164 :         if ( pPortion->IsVisible() && pPortion->IsInvalid() )
    2871             :             return;
    2872             : 
    2873         164 :         if ( pPDFExtOutDevData )
    2874           0 :             pPDFExtOutDevData->BeginStructureElement( vcl::PDFWriter::Paragraph );
    2875             : 
    2876         164 :         long nParaHeight = pPortion->GetHeight();
    2877         656 :         if ( pPortion->IsVisible() && (
    2878         492 :                 ( !IsVertical() && ( ( aStartPos.Y() + nParaHeight ) > aClipRec.Top() ) ) ||
    2879           0 :                 ( IsVertical() && ( ( aStartPos.X() - nParaHeight ) < aClipRec.Right() ) ) ) )
    2880             : 
    2881             :         {
    2882             :             // --------------------------------------------------
    2883             :             // Over the lines of the paragraph ...
    2884             :             // --------------------------------------------------
    2885         164 :             sal_uInt16 nLines = pPortion->GetLines().Count();
    2886         164 :             sal_uInt16 nLastLine = nLines-1;
    2887             : 
    2888         164 :             if ( !IsVertical() )
    2889         164 :                 aStartPos.Y() += pPortion->GetFirstLineOffset();
    2890             :             else
    2891           0 :                 aStartPos.X() -= pPortion->GetFirstLineOffset();
    2892             : 
    2893         164 :             Point aParaStart( aStartPos );
    2894             : 
    2895         164 :             const SvxLineSpacingItem& rLSItem = ((const SvxLineSpacingItem&)pPortion->GetNode()->GetContentAttribs().GetItem( EE_PARA_SBL ));
    2896         164 :             sal_uInt16 nSBL = ( rLSItem.GetInterLineSpaceRule() == SVX_INTER_LINE_SPACE_FIX )
    2897         164 :                                 ? GetYValue( rLSItem.GetInterLineSpace() ) : 0;
    2898         376 :             for ( sal_uInt16 nLine = 0; nLine < nLines; nLine++ )
    2899             :             {
    2900         243 :                 pLine = pPortion->GetLines()[nLine];
    2901             :                 DBG_ASSERT( pLine, "NULL-Pointer in the line iterator in UpdateViews" );
    2902         243 :                 aTmpPos = aStartPos;
    2903         243 :                 if ( !IsVertical() )
    2904             :                 {
    2905         243 :                     aTmpPos.X() += pLine->GetStartPosX();
    2906         243 :                     aTmpPos.Y() += pLine->GetMaxAscent();
    2907         243 :                     aStartPos.Y() += pLine->GetHeight();
    2908         243 :                     if (nLine != nLastLine)
    2909          79 :                         aStartPos.Y() += nVertLineSpacing;
    2910             :                 }
    2911             :                 else
    2912             :                 {
    2913           0 :                     aTmpPos.Y() += pLine->GetStartPosX();
    2914           0 :                     aTmpPos.X() -= pLine->GetMaxAscent();
    2915           0 :                     aStartPos.X() -= pLine->GetHeight();
    2916           0 :                     if (nLine != nLastLine)
    2917           0 :                         aStartPos.X() -= nVertLineSpacing;
    2918             :                 }
    2919             : 
    2920         243 :                 if ( ( !IsVertical() && ( aStartPos.Y() > aClipRec.Top() ) )
    2921           0 :                     || ( IsVertical() && aStartPos.X() < aClipRec.Right() ) )
    2922             :                 {
    2923         243 :                     bool bPaintBullet (false);
    2924             : 
    2925             :                     // Why not just also call when stripping portions? This will give the correct values
    2926             :                     // and needs no position corrections in OutlinerEditEng::DrawingText which tries to call
    2927             :                     // PaintBullet correctly; exactly what GetEditEnginePtr()->PaintingFirstLine
    2928             :                     // does, too. No change for not-layouting (painting).
    2929         243 :                     if(0 == nLine) // && !bStripOnly)
    2930             :                     {
    2931         164 :                         GetEditEnginePtr()->PaintingFirstLine( n, aParaStart, aTmpPos.Y(), aOrigin, nOrientation, pOutDev );
    2932             : 
    2933             :                         // Remember whether a bullet was painted.
    2934             :                         const SfxBoolItem& rBulletState = static_cast<const SfxBoolItem&>(
    2935         164 :                             pEditEngine->GetParaAttrib(n, EE_PARA_BULLETSTATE));
    2936         164 :                         bPaintBullet = rBulletState.GetValue() ? true : false;
    2937             :                     }
    2938             : 
    2939             :                     // --------------------------------------------------
    2940             :                     // Over the Portions of the line ...
    2941             :                     // --------------------------------------------------
    2942         243 :                     sal_uInt16 nIndex = pLine->GetStart();
    2943         243 :                     bool bParsingFields = false;
    2944         243 :                     ::std::vector< sal_Int32 >::iterator itSubLines;
    2945             : 
    2946             :                     // #i108052# When stripping a callback for empty paragraphs is needed. This
    2947             :                     // was somehow lost/removed/killed by making the TextPortions with empty
    2948             :                     // paragraph to type PORTIONKIND_TAB instead of PORTIONKIND_TEXT. Adding here
    2949             : 
    2950             :                                         // since I could not find out who and why this has
    2951             :                                         // changed.
    2952             :                     // #i118881#: Do not include the empty paragraph
    2953             :                     // after a bullet.  Otherwise the wrong paragraph
    2954             :                     // indices will eventually find their way into
    2955             :                     // metafiles and break the association between
    2956             :                     // paragraphs and Impress animations.
    2957         243 :                                         if(!bPaintBullet && bStripOnly && pLine->GetStartPortion() == pLine->GetEndPortion())
    2958             :                     {
    2959          80 :                         const Color aOverlineColor(pOutDev->GetOverlineColor());
    2960          80 :                         const Color aTextLineColor(pOutDev->GetTextLineColor());
    2961             : 
    2962          80 :                         GetEditEnginePtr()->DrawingText(
    2963             :                             aTmpPos, String(), 0, 0, 0,
    2964             :                             aTmpFont, n, nIndex, 0,
    2965             :                             0,
    2966             :                             0,
    2967             :                             false, true, false, // support for EOL/EOP TEXT comments
    2968             :                             0,
    2969             :                             aOverlineColor,
    2970          80 :                             aTextLineColor);
    2971             :                     }
    2972             : 
    2973         488 :                     for ( sal_uInt16 y = pLine->GetStartPortion(); y <= pLine->GetEndPortion(); y++ )
    2974             :                     {
    2975             :                         DBG_ASSERT( pPortion->GetTextPortions().Count(), "Line without Textportion in Paint!" );
    2976         250 :                         const TextPortion* pTextPortion = pPortion->GetTextPortions()[y];
    2977             :                         DBG_ASSERT( pTextPortion, "NULL-Pointer in Portion iterator in UpdateViews" );
    2978             : 
    2979         250 :                         long nPortionXOffset = GetPortionXOffset( pPortion, pLine, y );
    2980         250 :                         if ( !IsVertical() )
    2981             :                         {
    2982         250 :                             aTmpPos.X() = aStartPos.X() + nPortionXOffset;
    2983         250 :                             if ( aTmpPos.X() > aClipRec.Right() )
    2984           5 :                                 break;  // No further output in line necessary
    2985             :                         }
    2986             :                         else
    2987             :                         {
    2988           0 :                             aTmpPos.Y() = aStartPos.Y() + nPortionXOffset;
    2989           0 :                             if ( aTmpPos.Y() > aClipRec.Bottom() )
    2990           0 :                                 break;  // No further output in line necessary
    2991             :                         }
    2992             : 
    2993         245 :                         switch ( pTextPortion->GetKind() )
    2994             :                         {
    2995             :                             case PORTIONKIND_TEXT:
    2996             :                             case PORTIONKIND_FIELD:
    2997             :                             case PORTIONKIND_HYPHENATOR:
    2998             :                             {
    2999         245 :                                 SeekCursor( pPortion->GetNode(), nIndex+1, aTmpFont, pOutDev );
    3000             : 
    3001         245 :                                 sal_Bool bDrawFrame = sal_False;
    3002             : 
    3003         490 :                                 if ( ( pTextPortion->GetKind() == PORTIONKIND_FIELD ) && !aTmpFont.IsTransparent() &&
    3004         245 :                                      ( GetBackgroundColor() != COL_AUTO ) && GetBackgroundColor().IsDark() &&
    3005           0 :                                      ( IsAutoColorEnabled() && ( pOutDev->GetOutDevType() != OUTDEV_PRINTER ) ) )
    3006             :                                 {
    3007           0 :                                     aTmpFont.SetTransparent( sal_True );
    3008           0 :                                     pOutDev->SetFillColor();
    3009           0 :                                     pOutDev->SetLineColor( GetAutoColor() );
    3010           0 :                                     bDrawFrame = sal_True;
    3011             :                                 }
    3012             : 
    3013             : #if OSL_DEBUG_LEVEL > 2
    3014             :                                 if ( pTextPortion->GetKind() == PORTIONKIND_HYPHENATOR )
    3015             :                                 {
    3016             :                                     aTmpFont.SetFillColor( COL_LIGHTGRAY );
    3017             :                                     aTmpFont.SetTransparent( sal_False );
    3018             :                                 }
    3019             :                                 if ( pTextPortion->GetRightToLeft()  )
    3020             :                                 {
    3021             :                                     aTmpFont.SetFillColor( COL_LIGHTGRAY );
    3022             :                                     aTmpFont.SetTransparent( sal_False );
    3023             :                                 }
    3024             :                                 else if ( GetScriptType( EditPaM( pPortion->GetNode(), nIndex+1 ) ) == i18n::ScriptType::COMPLEX )
    3025             :                                 {
    3026             :                                     aTmpFont.SetFillColor( COL_LIGHTCYAN );
    3027             :                                     aTmpFont.SetTransparent( sal_False );
    3028             :                                 }
    3029             : #endif
    3030         245 :                                 aTmpFont.SetPhysFont( pOutDev );
    3031             : 
    3032             :                                 // #114278# Saving both layout mode and language (since I'm
    3033             :                                 // potentially changing both)
    3034         245 :                                 pOutDev->Push( PUSH_TEXTLAYOUTMODE|PUSH_TEXTLANGUAGE );
    3035         245 :                                 ImplInitLayoutMode( pOutDev, n, nIndex );
    3036         245 :                                 ImplInitDigitMode( pOutDev, 0, 0, 0, aTmpFont.GetLanguage() );
    3037             : 
    3038         245 :                                 XubString aText;
    3039         245 :                                 sal_uInt16 nTextStart = 0;
    3040         245 :                                 sal_uInt16 nTextLen = 0;
    3041         245 :                                 const sal_Int32* pDXArray = 0;
    3042         245 :                                 sal_Int32* pTmpDXArray = 0;
    3043             : 
    3044         245 :                                 if ( pTextPortion->GetKind() == PORTIONKIND_TEXT )
    3045             :                                 {
    3046         201 :                                     aText = pPortion->GetNode()->GetString();
    3047         201 :                                     nTextStart = nIndex;
    3048         201 :                                     nTextLen = pTextPortion->GetLen();
    3049         201 :                                     if (!pLine->GetCharPosArray().empty())
    3050         186 :                                         pDXArray = &pLine->GetCharPosArray()[0]+( nIndex-pLine->GetStart() );
    3051             : 
    3052             :                                     // Paint control characters (#i55716#)
    3053         201 :                                     if ( aStatus.MarkFields() )
    3054             :                                     {
    3055             :                                         xub_StrLen nTmpIdx;
    3056          16 :                                         const xub_StrLen nTmpEnd = nTextStart + pTextPortion->GetLen();
    3057             : 
    3058         128 :                                         for ( nTmpIdx = nTextStart; nTmpIdx <= nTmpEnd ; ++nTmpIdx )
    3059             :                                         {
    3060         112 :                                             const sal_Unicode cChar = ( nTmpIdx != aText.Len() && ( nTmpIdx != nTextStart || 0 == nTextStart ) ) ?
    3061          96 :                                                                         aText.GetChar( nTmpIdx ) :
    3062         208 :                                                                         0;
    3063             : 
    3064         112 :                                             if ( 0x200B == cChar || 0x2060 == cChar )
    3065             :                                             {
    3066           0 :                                                 const rtl::OUString aBlank( ' ' );
    3067           0 :                                                 long nHalfBlankWidth = aTmpFont.QuickGetTextSize( pOutDev, aBlank, 0, 1, 0 ).Width() / 2;
    3068             : 
    3069             :                                                 const long nAdvanceX = ( nTmpIdx == nTmpEnd ?
    3070           0 :                                                                          pTextPortion->GetSize().Width() :
    3071           0 :                                                                          pDXArray[ nTmpIdx - nTextStart ] ) - nHalfBlankWidth;
    3072           0 :                                                 const long nAdvanceY = -pLine->GetMaxAscent();
    3073             : 
    3074           0 :                                                 Point aTopLeftRectPos( aTmpPos );
    3075           0 :                                                 if ( !IsVertical() )
    3076             :                                                 {
    3077           0 :                                                     aTopLeftRectPos.X() += nAdvanceX;
    3078           0 :                                                     aTopLeftRectPos.Y() += nAdvanceY;
    3079             :                                                 }
    3080             :                                                 else
    3081             :                                                 {
    3082           0 :                                                     aTopLeftRectPos.Y() += nAdvanceX;
    3083           0 :                                                     aTopLeftRectPos.X() -= nAdvanceY;
    3084             :                                                 }
    3085             : 
    3086           0 :                                                 Point aBottomRightRectPos( aTopLeftRectPos );
    3087           0 :                                                 if ( !IsVertical() )
    3088             :                                                 {
    3089           0 :                                                     aBottomRightRectPos.X() += 2 * nHalfBlankWidth;
    3090           0 :                                                     aBottomRightRectPos.Y() += pLine->GetHeight();
    3091             :                                                 }
    3092             :                                                 else
    3093             :                                                 {
    3094           0 :                                                     aBottomRightRectPos.X() -= pLine->GetHeight();
    3095           0 :                                                     aBottomRightRectPos.Y() += 2 * nHalfBlankWidth;
    3096             :                                                 }
    3097             : 
    3098           0 :                                                 pOutDev->Push( PUSH_FILLCOLOR );
    3099           0 :                                                 pOutDev->Push( PUSH_LINECOLOR );
    3100           0 :                                                 pOutDev->SetFillColor( COL_LIGHTGRAY );
    3101           0 :                                                 pOutDev->SetLineColor( COL_LIGHTGRAY );
    3102             : 
    3103           0 :                                                 const Rectangle aBackRect( aTopLeftRectPos, aBottomRightRectPos );
    3104           0 :                                                 pOutDev->DrawRect( aBackRect );
    3105             : 
    3106           0 :                                                 pOutDev->Pop();
    3107           0 :                                                 pOutDev->Pop();
    3108             : 
    3109           0 :                                                 if ( 0x200B == cChar )
    3110             :                                                 {
    3111           0 :                                                     const rtl::OUString aSlash( '/' );
    3112           0 :                                                     const short nOldEscapement = aTmpFont.GetEscapement();
    3113           0 :                                                     const sal_uInt8 nOldPropr = aTmpFont.GetPropr();
    3114             : 
    3115           0 :                                                     aTmpFont.SetEscapement( -20 );
    3116           0 :                                                     aTmpFont.SetPropr( 25 );
    3117           0 :                                                     aTmpFont.SetPhysFont( pOutDev );
    3118             : 
    3119           0 :                                                     const Size aSlashSize = aTmpFont.QuickGetTextSize( pOutDev, aSlash, 0, 1, 0 );
    3120           0 :                                                     Point aSlashPos( aTmpPos );
    3121           0 :                                                     const long nAddX = nHalfBlankWidth - aSlashSize.Width() / 2;
    3122           0 :                                                     if ( !IsVertical() )
    3123             :                                                     {
    3124           0 :                                                         aSlashPos.X() = aTopLeftRectPos.X() + nAddX;
    3125             :                                                     }
    3126             :                                                     else
    3127             :                                                     {
    3128           0 :                                                         aSlashPos.Y() = aTopLeftRectPos.Y() + nAddX;
    3129             :                                                     }
    3130             : 
    3131           0 :                                                     aTmpFont.QuickDrawText( pOutDev, aSlashPos, aSlash, 0, 1, 0 );
    3132             : 
    3133           0 :                                                     aTmpFont.SetEscapement( nOldEscapement );
    3134           0 :                                                     aTmpFont.SetPropr( nOldPropr );
    3135           0 :                                                     aTmpFont.SetPhysFont( pOutDev );
    3136           0 :                                                 }
    3137             :                                             }
    3138             :                                         }
    3139             :                                     }
    3140             :                                 }
    3141          44 :                                 else if ( pTextPortion->GetKind() == PORTIONKIND_FIELD )
    3142             :                                 {
    3143          44 :                                     const EditCharAttrib* pAttr = pPortion->GetNode()->GetCharAttribs().FindFeature(nIndex);
    3144             :                                     DBG_ASSERT( pAttr, "Field not found");
    3145             :                                     DBG_ASSERT( pAttr && pAttr->GetItem()->ISA( SvxFieldItem ), "Field of the wrong type! ");
    3146          44 :                                     aText = ((EditCharAttribField*)pAttr)->GetFieldValue();
    3147          44 :                                     nTextStart = 0;
    3148          44 :                                     nTextLen = aText.Len();
    3149          44 :                                     ExtraPortionInfo *pExtraInfo = pTextPortion->GetExtraInfos();
    3150             :                                     // Do not split the Fields into different lines while editing
    3151          44 :                                     if( bStripOnly && !bParsingFields && pExtraInfo && pExtraInfo->lineBreaksList.size() )
    3152             :                                     {
    3153           0 :                                         bParsingFields = true;
    3154           0 :                                         itSubLines = pExtraInfo->lineBreaksList.begin();
    3155             :                                     }
    3156          44 :                                     if( bParsingFields )
    3157             :                                     {
    3158           0 :                                         if( itSubLines != pExtraInfo->lineBreaksList.begin() )
    3159             :                                         {
    3160           0 :                                             if ( !IsVertical() )
    3161             :                                             {
    3162           0 :                                                 aStartPos.Y() += pLine->GetMaxAscent();
    3163           0 :                                                 aTmpPos.Y() += pLine->GetHeight();
    3164             :                                             }
    3165             :                                             else
    3166             :                                             {
    3167           0 :                                                 aTmpPos.X() -= pLine->GetMaxAscent();
    3168           0 :                                                 aStartPos.X() -= pLine->GetHeight();
    3169             :                                             }
    3170             :                                         }
    3171           0 :                                         ::std::vector< sal_Int32 >::iterator curIt = itSubLines;
    3172           0 :                                         ++itSubLines;
    3173           0 :                                         if( itSubLines != pExtraInfo->lineBreaksList.end() )
    3174             :                                         {
    3175           0 :                                             nTextStart = *curIt;
    3176           0 :                                             nTextLen = *itSubLines - nTextStart;
    3177             :                                         }
    3178             :                                         else
    3179             :                                         {
    3180           0 :                                             nTextStart = *curIt;
    3181           0 :                                             nTextLen = nTextLen - nTextStart;
    3182           0 :                                             bParsingFields = false;
    3183             :                                         }
    3184             :                                     }
    3185             : 
    3186          44 :                                     pTmpDXArray = new sal_Int32[ aText.Len() ];
    3187          44 :                                     pDXArray = pTmpDXArray;
    3188          44 :                                     Font _aOldFont( GetRefDevice()->GetFont() );
    3189          44 :                                     aTmpFont.SetPhysFont( GetRefDevice() );
    3190          44 :                                     aTmpFont.QuickGetTextSize( GetRefDevice(), aText, nTextStart, nTextLen, pTmpDXArray );
    3191          44 :                                     if ( aStatus.DoRestoreFont() )
    3192           0 :                                         GetRefDevice()->SetFont( _aOldFont );
    3193             : 
    3194             :                                     // add a meta file comment if we record to a metafile
    3195          44 :                                     if( bMetafileValid )
    3196             :                                     {
    3197           0 :                                         const SvxFieldItem* pFieldItem = dynamic_cast<const SvxFieldItem*>(pAttr->GetItem());
    3198           0 :                                         if( pFieldItem )
    3199             :                                         {
    3200           0 :                                             const SvxFieldData* pFieldData = pFieldItem->GetField();
    3201           0 :                                             if( pFieldData )
    3202           0 :                                                 pMtf->AddAction( pFieldData->createBeginComment() );
    3203             :                                         }
    3204          44 :                                     }
    3205             : 
    3206             :                                 }
    3207           0 :                                 else if ( pTextPortion->GetKind() == PORTIONKIND_HYPHENATOR )
    3208             :                                 {
    3209           0 :                                     if ( pTextPortion->GetExtraValue() )
    3210           0 :                                         aText = pTextPortion->GetExtraValue();
    3211           0 :                                     aText += CH_HYPH;
    3212           0 :                                     nTextStart = 0;
    3213           0 :                                     nTextLen = aText.Len();
    3214             : 
    3215             :                                     // crash when accessing 0 pointer in pDXArray
    3216           0 :                                     pTmpDXArray = new sal_Int32[ aText.Len() ];
    3217           0 :                                     pDXArray = pTmpDXArray;
    3218           0 :                                     Font _aOldFont( GetRefDevice()->GetFont() );
    3219           0 :                                     aTmpFont.SetPhysFont( GetRefDevice() );
    3220           0 :                                     aTmpFont.QuickGetTextSize( GetRefDevice(), aText, 0, aText.Len(), pTmpDXArray );
    3221           0 :                                     if ( aStatus.DoRestoreFont() )
    3222           0 :                                         GetRefDevice()->SetFont( _aOldFont );
    3223             :                                 }
    3224             : 
    3225         245 :                                 long nTxtWidth = pTextPortion->GetSize().Width();
    3226             : 
    3227         245 :                                 Point aOutPos( aTmpPos );
    3228         245 :                                 aRedLineTmpPos = aTmpPos;
    3229             :                                 // In RTL portions spell markup pos should be at the start of the
    3230             :                                 // first chara as well. That is on the right end of the portion
    3231         245 :                                 if (pTextPortion->IsRightToLeft())
    3232           0 :                                     aRedLineTmpPos.X() += pTextPortion->GetSize().Width();
    3233             : 
    3234         245 :                                 if ( bStripOnly )
    3235             :                                 {
    3236         214 :                                     EEngineData::WrongSpellVector aWrongSpellVector;
    3237             : 
    3238         214 :                                     if(GetStatus().DoOnlineSpelling() && pTextPortion->GetLen())
    3239             :                                     {
    3240          98 :                                         WrongList* pWrongs = pPortion->GetNode()->GetWrongList();
    3241             : 
    3242          98 :                                         if(pWrongs && !pWrongs->empty())
    3243             :                                         {
    3244           0 :                                             sal_uInt16 nStart(nIndex);
    3245           0 :                                             sal_uInt16 nEnd(0);
    3246           0 :                                             sal_Bool bWrong(pWrongs->NextWrong(nStart, nEnd));
    3247           0 :                                             const sal_uInt16 nMaxEnd(nIndex + pTextPortion->GetLen());
    3248             : 
    3249           0 :                                             while(bWrong)
    3250             :                                             {
    3251           0 :                                                 if(nStart >= nMaxEnd)
    3252             :                                                 {
    3253           0 :                                                     break;
    3254             :                                                 }
    3255             : 
    3256           0 :                                                 if(nStart < nIndex)
    3257             :                                                 {
    3258           0 :                                                     nStart = nIndex;
    3259             :                                                 }
    3260             : 
    3261           0 :                                                 if(nEnd > nMaxEnd)
    3262             :                                                 {
    3263           0 :                                                     nEnd = nMaxEnd;
    3264             :                                                 }
    3265             : 
    3266             :                                                 // add to vector
    3267           0 :                                                 aWrongSpellVector.push_back(EEngineData::WrongSpellClass(nStart, nEnd));
    3268             : 
    3269             :                                                 // goto next index
    3270           0 :                                                 nStart = nEnd + 1;
    3271             : 
    3272           0 :                                                 if(nEnd < nMaxEnd)
    3273             :                                                 {
    3274           0 :                                                     bWrong = pWrongs->NextWrong(nStart, nEnd);
    3275             :                                                 }
    3276             :                                                 else
    3277             :                                                 {
    3278           0 :                                                     bWrong = sal_False;
    3279             :                                                 }
    3280             :                                             }
    3281             :                                         }
    3282             :                                     }
    3283             : 
    3284         214 :                                     const SvxFieldData* pFieldData = 0;
    3285             : 
    3286         214 :                                     if(PORTIONKIND_FIELD == pTextPortion->GetKind())
    3287             :                                     {
    3288          44 :                                         const EditCharAttrib* pAttr = pPortion->GetNode()->GetCharAttribs().FindFeature(nIndex);
    3289          44 :                                         const SvxFieldItem* pFieldItem = dynamic_cast<const SvxFieldItem*>(pAttr->GetItem());
    3290             : 
    3291          44 :                                         if(pFieldItem)
    3292             :                                         {
    3293          44 :                                             pFieldData = pFieldItem->GetField();
    3294             :                                         }
    3295             :                                     }
    3296             : 
    3297             :                                     // support for EOC, EOW, EOS TEXT comments. To support that,
    3298             :                                     // the locale is needed. With the locale and a XBreakIterator it is
    3299             :                                     // possible to re-create the text marking info on primitive level
    3300         214 :                                     const lang::Locale aLocale(GetLocale(EditPaM(pPortion->GetNode(), nIndex + 1)));
    3301             : 
    3302             :                                     // create EOL and EOP bools
    3303         214 :                                     const bool bEndOfLine(y == pLine->GetEndPortion());
    3304         214 :                                     const bool bEndOfParagraph(bEndOfLine && nLine + 1 == nLines);
    3305             : 
    3306             :                                     // get Overline color (from ((const SvxOverlineItem*)GetItem())->GetColor() in
    3307             :                                     // consequence, but also already set at pOutDev)
    3308         214 :                                     const Color aOverlineColor(pOutDev->GetOverlineColor());
    3309             : 
    3310             :                                     // get TextLine color (from ((const SvxUnderlineItem*)GetItem())->GetColor() in
    3311             :                                     // consequence, but also already set at pOutDev)
    3312         214 :                                     const Color aTextLineColor(pOutDev->GetTextLineColor());
    3313             : 
    3314             :                                     // Unicode code points conversion according to ctl text numeral setting
    3315         214 :                                     ImplInitDigitMode( 0, &aText, nTextStart, nTextLen, aTmpFont.GetLanguage() );
    3316             : 
    3317             :                                     // StripPortions() data callback
    3318         214 :                                     GetEditEnginePtr()->DrawingText( aOutPos, aText, nTextStart, nTextLen, pDXArray,
    3319         214 :                                         aTmpFont, n, nIndex, pTextPortion->GetRightToLeft(),
    3320         214 :                                         aWrongSpellVector.size() ? &aWrongSpellVector : 0,
    3321             :                                         pFieldData,
    3322             :                                         bEndOfLine, bEndOfParagraph, false, // support for EOL/EOP TEXT comments
    3323             :                                         &aLocale,
    3324             :                                         aOverlineColor,
    3325         642 :                                         aTextLineColor);
    3326             :                                 }
    3327             :                                 else
    3328             :                                 {
    3329          31 :                                     short nEsc = aTmpFont.GetEscapement();
    3330          31 :                                     if ( nOrientation )
    3331             :                                     {
    3332             :                                         // In case of high/low do it yourself:
    3333           0 :                                         if ( aTmpFont.GetEscapement() )
    3334             :                                         {
    3335           0 :                                             long nDiff = aTmpFont.GetSize().Height() * aTmpFont.GetEscapement() / 100L;
    3336           0 :                                             if ( !IsVertical() )
    3337           0 :                                                 aOutPos.Y() -= nDiff;
    3338             :                                             else
    3339           0 :                                                 aOutPos.X() += nDiff;
    3340           0 :                                             aRedLineTmpPos = aOutPos;
    3341           0 :                                             aTmpFont.SetEscapement( 0 );
    3342             :                                         }
    3343             : 
    3344           0 :                                         aOutPos = lcl_ImplCalcRotatedPos( aOutPos, aOrigin, nSin, nCos );
    3345           0 :                                         aTmpFont.SetOrientation( aTmpFont.GetOrientation()+nOrientation );
    3346           0 :                                         aTmpFont.SetPhysFont( pOutDev );
    3347             : 
    3348             :                                     }
    3349             : 
    3350             :                                     // Take only what begins in the visible range:
    3351             :                                     // Important, because of a bug in some graphic cards
    3352             :                                     // when transparent font, output when negative
    3353          31 :                                     if ( nOrientation || ( !IsVertical() && ( ( aTmpPos.X() + nTxtWidth ) >= nFirstVisXPos ) )
    3354           0 :                                             || ( IsVertical() && ( ( aTmpPos.Y() + nTxtWidth ) >= nFirstVisYPos ) ) )
    3355             :                                     {
    3356          31 :                                         if ( nEsc && ( ( aTmpFont.GetUnderline() != UNDERLINE_NONE ) ) )
    3357             :                                         {
    3358             :                                             // Paint the high/low without underline,
    3359             :                                             // Display the Underline on the
    3360             :                                             // base line of the original font height ...
    3361             :                                             // But only if there was something underlined before!
    3362           0 :                                             sal_Bool bSpecialUnderline = sal_False;
    3363           0 :                                             EditCharAttrib* pPrev = pPortion->GetNode()->GetCharAttribs().FindAttrib( EE_CHAR_ESCAPEMENT, nIndex );
    3364           0 :                                             if ( pPrev )
    3365             :                                             {
    3366           0 :                                                 SvxFont aDummy;
    3367             :                                                 // Underscore in front?
    3368           0 :                                                 if ( pPrev->GetStart() )
    3369             :                                                 {
    3370           0 :                                                     SeekCursor( pPortion->GetNode(), pPrev->GetStart(), aDummy );
    3371           0 :                                                     if ( aDummy.GetUnderline() != UNDERLINE_NONE )
    3372           0 :                                                         bSpecialUnderline = sal_True;
    3373             :                                                 }
    3374           0 :                                                 if ( !bSpecialUnderline && ( pPrev->GetEnd() < pPortion->GetNode()->Len() ) )
    3375             :                                                 {
    3376           0 :                                                     SeekCursor( pPortion->GetNode(), pPrev->GetEnd()+1, aDummy );
    3377           0 :                                                     if ( aDummy.GetUnderline() != UNDERLINE_NONE )
    3378           0 :                                                         bSpecialUnderline = sal_True;
    3379           0 :                                                 }
    3380             :                                             }
    3381           0 :                                             if ( bSpecialUnderline )
    3382             :                                             {
    3383           0 :                                                 Size aSz = aTmpFont.GetPhysTxtSize( pOutDev, aText, nTextStart, nTextLen );
    3384           0 :                                                 sal_uInt8 nProp = aTmpFont.GetPropr();
    3385           0 :                                                 aTmpFont.SetEscapement( 0 );
    3386           0 :                                                 aTmpFont.SetPropr( 100 );
    3387           0 :                                                 aTmpFont.SetPhysFont( pOutDev );
    3388           0 :                                                 rtl::OUStringBuffer aBlanks;
    3389           0 :                                                 comphelper::string::padToLength( aBlanks, (sal_Int32) nTextLen, ' ' );
    3390           0 :                                                 Point aUnderlinePos( aOutPos );
    3391           0 :                                                 if ( nOrientation )
    3392           0 :                                                     aUnderlinePos = lcl_ImplCalcRotatedPos( aTmpPos, aOrigin, nSin, nCos );
    3393           0 :                                                 pOutDev->DrawStretchText( aUnderlinePos, aSz.Width(), aBlanks.makeStringAndClear(), 0, nTextLen );
    3394             : 
    3395           0 :                                                 aTmpFont.SetUnderline( UNDERLINE_NONE );
    3396           0 :                                                 if ( !nOrientation )
    3397           0 :                                                     aTmpFont.SetEscapement( nEsc );
    3398           0 :                                                 aTmpFont.SetPropr( nProp );
    3399           0 :                                                 aTmpFont.SetPhysFont( pOutDev );
    3400             :                                             }
    3401             :                                         }
    3402          31 :                                         Point aRealOutPos( aOutPos );
    3403          62 :                                         if ( ( pTextPortion->GetKind() == PORTIONKIND_TEXT )
    3404          31 :                                                && pTextPortion->GetExtraInfos() && pTextPortion->GetExtraInfos()->bCompressed
    3405           0 :                                                && pTextPortion->GetExtraInfos()->bFirstCharIsRightPunktuation )
    3406             :                                         {
    3407           0 :                                             aRealOutPos.X() += pTextPortion->GetExtraInfos()->nPortionOffsetX;
    3408             :                                         }
    3409             : 
    3410             :                                         // RTL portions with (#i37132#)
    3411             :                                         // compressed blank should not paint this blank:
    3412          31 :                                         if ( pTextPortion->IsRightToLeft() && nTextLen >= 2 &&
    3413           0 :                                              pDXArray[ nTextLen - 1 ] ==
    3414           0 :                                              pDXArray[ nTextLen - 2 ] &&
    3415           0 :                                              ' ' == aText.GetChar( nTextStart + nTextLen - 1 ) )
    3416           0 :                                             --nTextLen;
    3417             : 
    3418             :                                         // output directly
    3419          31 :                                         aTmpFont.QuickDrawText( pOutDev, aRealOutPos, aText, nTextStart, nTextLen, pDXArray );
    3420             : 
    3421          31 :                                         if ( bDrawFrame )
    3422             :                                         {
    3423           0 :                                             Point aTopLeft( aTmpPos );
    3424           0 :                                             aTopLeft.Y() -= pLine->GetMaxAscent();
    3425           0 :                                             if ( nOrientation )
    3426           0 :                                                 aTopLeft = lcl_ImplCalcRotatedPos( aTopLeft, aOrigin, nSin, nCos );
    3427           0 :                                             Rectangle aRect( aTopLeft, pTextPortion->GetSize() );
    3428           0 :                                             pOutDev->DrawRect( aRect );
    3429             :                                         }
    3430             : 
    3431             :                                         // PDF export:
    3432          31 :                                         if ( pPDFExtOutDevData )
    3433             :                                         {
    3434           0 :                                             if ( pTextPortion->GetKind() == PORTIONKIND_FIELD )
    3435             :                                             {
    3436           0 :                                                 const EditCharAttrib* pAttr = pPortion->GetNode()->GetCharAttribs().FindFeature(nIndex);
    3437           0 :                                                 const SvxFieldItem* pFieldItem = dynamic_cast<const SvxFieldItem*>(pAttr->GetItem());
    3438           0 :                                                 if( pFieldItem )
    3439             :                                                 {
    3440           0 :                                                     const SvxFieldData* pFieldData = pFieldItem->GetField();
    3441           0 :                                                     if ( pFieldData->ISA( SvxURLField ) )
    3442             :                                                     {
    3443           0 :                                                         Point aTopLeft( aTmpPos );
    3444           0 :                                                         aTopLeft.Y() -= pLine->GetMaxAscent();
    3445             : 
    3446           0 :                                                         Rectangle aRect( aTopLeft, pTextPortion->GetSize() );
    3447           0 :                                                         vcl::PDFExtOutDevBookmarkEntry aBookmark;
    3448           0 :                                                         aBookmark.nLinkId = pPDFExtOutDevData->CreateLink( aRect );
    3449           0 :                                                         aBookmark.aBookmark = ((SvxURLField*)pFieldData)->GetURL();
    3450           0 :                                                         std::vector< vcl::PDFExtOutDevBookmarkEntry >& rBookmarks = pPDFExtOutDevData->GetBookmarks();
    3451           0 :                                                         rBookmarks.push_back( aBookmark );
    3452             :                                                     }
    3453             :                                                 }
    3454             :                                             }
    3455             :                                         }
    3456             :                                     }
    3457             : 
    3458          31 :                                     if ( GetStatus().DoOnlineSpelling() && !pPortion->GetNode()->GetWrongList()->empty() && pTextPortion->GetLen() )
    3459             :                                     {
    3460             :                                         {//#105750# adjust LinePos for superscript or subscript text
    3461           0 :                                             short _nEsc = aTmpFont.GetEscapement();
    3462           0 :                                             if( _nEsc )
    3463             :                                             {
    3464           0 :                                                 long nShift = ((_nEsc*long(aTmpFont.GetSize().Height()))/ 100L);
    3465           0 :                                                 if( !IsVertical() )
    3466           0 :                                                     aRedLineTmpPos.Y() -= nShift;
    3467             :                                                 else
    3468           0 :                                                     aRedLineTmpPos.X() += nShift;
    3469             :                                             }
    3470             :                                         }
    3471           0 :                                         Color aOldColor( pOutDev->GetLineColor() );
    3472           0 :                                         pOutDev->SetLineColor( Color( GetColorConfig().GetColorValue( svtools::SPELL ).nColor ) );
    3473           0 :                                         lcl_DrawRedLines( pOutDev, aTmpFont.GetSize().Height(), aRedLineTmpPos, nIndex, nIndex + pTextPortion->GetLen(), pDXArray, pPortion->GetNode()->GetWrongList(), nOrientation, aOrigin, IsVertical(), pTextPortion->IsRightToLeft() );
    3474           0 :                                         pOutDev->SetLineColor( aOldColor );
    3475             :                                     }
    3476             :                                 }
    3477             : 
    3478         245 :                                 pOutDev->Pop();
    3479             : 
    3480             :                                 //The C++ language guarantees that delete p will do nothing if p is equal to NULL.
    3481         245 :                                 delete[] pTmpDXArray;
    3482             : 
    3483         245 :                                 if ( pTextPortion->GetKind() == PORTIONKIND_FIELD )
    3484             :                                 {
    3485          44 :                                     const EditCharAttrib* pAttr = pPortion->GetNode()->GetCharAttribs().FindFeature(nIndex);
    3486             :                                     DBG_ASSERT( pAttr, "Field not found" );
    3487             :                                     DBG_ASSERT( pAttr && pAttr->GetItem()->ISA( SvxFieldItem ), "Wrong type of field!" );
    3488             : 
    3489             :                                     // add a meta file comment if we record to a metafile
    3490          44 :                                     if( bMetafileValid )
    3491             :                                     {
    3492           0 :                                         const SvxFieldItem* pFieldItem = dynamic_cast<const SvxFieldItem*>(pAttr->GetItem());
    3493             : 
    3494           0 :                                         if( pFieldItem )
    3495             :                                         {
    3496           0 :                                             const SvxFieldData* pFieldData = pFieldItem->GetField();
    3497           0 :                                             if( pFieldData )
    3498           0 :                                                 pMtf->AddAction( pFieldData->createEndComment() );
    3499             :                                         }
    3500             :                                     }
    3501             : 
    3502         245 :                                 }
    3503             : 
    3504             :                             }
    3505         245 :                             break;
    3506             :                             case PORTIONKIND_TAB:
    3507             :                             {
    3508           0 :                                 if ( pTextPortion->GetExtraValue() && ( pTextPortion->GetExtraValue() != ' ' ) )
    3509             :                                 {
    3510           0 :                                     SeekCursor( pPortion->GetNode(), nIndex+1, aTmpFont, pOutDev );
    3511           0 :                                     aTmpFont.SetTransparent( sal_False );
    3512           0 :                                     aTmpFont.SetEscapement( 0 );
    3513           0 :                                     aTmpFont.SetPhysFont( pOutDev );
    3514             :                                     long nCharWidth = aTmpFont.QuickGetTextSize( pOutDev,
    3515           0 :                                         rtl::OUString(pTextPortion->GetExtraValue()), 0, 1, NULL ).Width();
    3516           0 :                                     sal_Int32 nChars = 2;
    3517           0 :                                     if( nCharWidth )
    3518           0 :                                         nChars = pTextPortion->GetSize().Width() / nCharWidth;
    3519           0 :                                     if ( nChars < 2 )
    3520           0 :                                         nChars = 2; // is compressed by DrawStretchText.
    3521           0 :                                     else if ( nChars == 2 )
    3522           0 :                                         nChars = 3; // looks better
    3523             : 
    3524           0 :                                     rtl::OUStringBuffer aBuf;
    3525           0 :                                     comphelper::string::padToLength(aBuf, nChars, pTextPortion->GetExtraValue());
    3526           0 :                                     String aText(aBuf.makeStringAndClear());
    3527           0 :                                     aTmpFont.QuickDrawText( pOutDev, aTmpPos, aText, 0, aText.Len(), NULL );
    3528           0 :                                     pOutDev->DrawStretchText( aTmpPos, pTextPortion->GetSize().Width(), aText );
    3529             : 
    3530           0 :                                     if ( bStripOnly )
    3531             :                                     {
    3532             :                                         // create EOL and EOP bools
    3533           0 :                                         const bool bEndOfLine(y == pLine->GetEndPortion());
    3534           0 :                                         const bool bEndOfParagraph(bEndOfLine && nLine + 1 == nLines);
    3535             : 
    3536           0 :                                         const Color aOverlineColor(pOutDev->GetOverlineColor());
    3537           0 :                                         const Color aTextLineColor(pOutDev->GetTextLineColor());
    3538             : 
    3539             :                                         // StripPortions() data callback
    3540           0 :                                         GetEditEnginePtr()->DrawingTab( aTmpPos,
    3541           0 :                                             pTextPortion->GetSize().Width(),
    3542           0 :                                             rtl::OUString(pTextPortion->GetExtraValue()),
    3543           0 :                                             aTmpFont, n, nIndex, pTextPortion->GetRightToLeft(),
    3544             :                                             bEndOfLine, bEndOfParagraph,
    3545           0 :                                             aOverlineColor, aTextLineColor);
    3546           0 :                                     }
    3547             :                                 }
    3548           0 :                                 else if ( bStripOnly )
    3549             :                                 {
    3550             :                                     // #i108052# When stripping, a callback for _empty_ paragraphs is also needed.
    3551             :                                     // This was optimized away (by not rendering the space-only tab portion), so do
    3552             :                                     // it manually here.
    3553           0 :                                     const bool bEndOfLine(y == pLine->GetEndPortion());
    3554           0 :                                     const bool bEndOfParagraph(bEndOfLine && nLine + 1 == nLines);
    3555             : 
    3556           0 :                                     const Color aOverlineColor(pOutDev->GetOverlineColor());
    3557           0 :                                     const Color aTextLineColor(pOutDev->GetTextLineColor());
    3558             : 
    3559           0 :                                     GetEditEnginePtr()->DrawingText(
    3560             :                                         aTmpPos, String(), 0, 0, 0,
    3561             :                                         aTmpFont, n, nIndex, 0,
    3562             :                                         0,
    3563             :                                         0,
    3564             :                                         bEndOfLine, bEndOfParagraph, false,
    3565             :                                         0,
    3566             :                                         aOverlineColor,
    3567           0 :                                         aTextLineColor);
    3568             :                                 }
    3569             :                             }
    3570           0 :                             break;
    3571             :                         }
    3572         245 :                         if( bParsingFields )
    3573           0 :                             y--;
    3574             :                         else
    3575         245 :                             nIndex = nIndex + pTextPortion->GetLen();
    3576             : 
    3577             :                     }
    3578             :                 }
    3579             : 
    3580         243 :                 if ( ( nLine != nLastLine ) && !aStatus.IsOutliner() )
    3581             :                 {
    3582          79 :                     if ( !IsVertical() )
    3583          79 :                         aStartPos.Y() += nSBL;
    3584             :                     else
    3585           0 :                         aStartPos.X() -= nSBL;
    3586             :                 }
    3587             : 
    3588             :                 // no more visible actions?
    3589         243 :                 if ( !IsVertical() && ( aStartPos.Y() >= aClipRec.Bottom() ) )
    3590          31 :                     break;
    3591         212 :                 else if ( IsVertical() && ( aStartPos.X() <= aClipRec.Left() ) )
    3592           0 :                     break;
    3593             :             }
    3594             : 
    3595         164 :             if ( !aStatus.IsOutliner() )
    3596             :             {
    3597         164 :                 const SvxULSpaceItem& rULItem = (const SvxULSpaceItem&)pPortion->GetNode()->GetContentAttribs().GetItem( EE_PARA_ULSPACE );
    3598         164 :                 long nUL = GetYValue( rULItem.GetLower() );
    3599         164 :                 if ( !IsVertical() )
    3600         164 :                     aStartPos.Y() += nUL;
    3601             :                 else
    3602           0 :                     aStartPos.X() -= nUL;
    3603             :             }
    3604             :         }
    3605             :         else
    3606             :         {
    3607           0 :             if ( !IsVertical() )
    3608           0 :                 aStartPos.Y() += nParaHeight;
    3609             :             else
    3610           0 :                 aStartPos.X() -= nParaHeight;
    3611             :         }
    3612             : 
    3613         164 :         if ( pPDFExtOutDevData )
    3614           0 :             pPDFExtOutDevData->EndStructureElement();
    3615             : 
    3616             :         // no more visible actions?
    3617         164 :         if ( !IsVertical() && ( aStartPos.Y() > aClipRec.Bottom() ) )
    3618          31 :             break;
    3619         133 :         if ( IsVertical() && ( aStartPos.X() < aClipRec.Left() ) )
    3620           0 :             break;
    3621             :     }
    3622         140 :     if ( aStatus.DoRestoreFont() )
    3623           0 :         pOutDev->SetFont( aOldFont );
    3624             : }
    3625             : 
    3626          31 : void ImpEditEngine::Paint( ImpEditView* pView, const Rectangle& rRec, sal_Bool bUseVirtDev )
    3627             : {
    3628             :     DBG_ASSERT( pView, "No View - No Paint!" );
    3629             :     DBG_CHKOBJ( GetEditEnginePtr(), EditEngine, 0 );
    3630             : 
    3631          31 :     if ( !GetUpdateMode() || IsInUndo() )
    3632             :         return;
    3633             : 
    3634             :     // Intersection of paint area and output area.
    3635          31 :     Rectangle aClipRec( pView->GetOutputArea() );
    3636          31 :     aClipRec.Intersection( rRec );
    3637             : 
    3638          31 :     Window* pOutWin = pView->GetWindow();
    3639             : 
    3640          31 :     if ( bUseVirtDev )
    3641             :     {
    3642          31 :         Rectangle aClipRecPixel( pOutWin->LogicToPixel( aClipRec ) );
    3643          31 :         if ( !IsVertical() )
    3644             :         {
    3645             :             // etwas mehr, falls abgerundet!
    3646          31 :             aClipRecPixel.Right() += 1;
    3647          31 :             aClipRecPixel.Bottom() += 1;
    3648             :         }
    3649             :         else
    3650             :         {
    3651           0 :             aClipRecPixel.Left() -= 1;
    3652           0 :             aClipRecPixel.Bottom() += 1;
    3653             :         }
    3654             : 
    3655             :         // If aClipRecPixel > XXXX, then invalidate?!
    3656             : 
    3657          31 :         VirtualDevice* pVDev = GetVirtualDevice( pOutWin->GetMapMode(), pOutWin->GetDrawMode() );
    3658          31 :         pVDev->SetDigitLanguage( GetRefDevice()->GetDigitLanguage() );
    3659             : 
    3660             :         {
    3661          31 :             Color aBackgroundColor( pView->GetBackgroundColor() );
    3662             :             // #i47161# Check if text is visible on background
    3663          31 :             SvxFont aTmpFont;
    3664          31 :             ContentNode* pNode = GetEditDoc().GetObject( 0 );
    3665          31 :             SeekCursor( pNode, 1, aTmpFont );
    3666          31 :             Color aFontColor( aTmpFont.GetColor() );
    3667          31 :             if( (aFontColor == COL_AUTO) || IsForceAutoColor() )
    3668          31 :                 aFontColor = GetAutoColor();
    3669             : 
    3670             :             // #i69346# check for reverse color of input method attribute
    3671          31 :             if( mpIMEInfos && (mpIMEInfos->aPos.GetNode() == pNode &&
    3672             :                 mpIMEInfos->pAttribs))
    3673             :             {
    3674           0 :                 sal_uInt16 nAttr = mpIMEInfos->pAttribs[ 0 ];
    3675           0 :                 if ( nAttr & EXTTEXTINPUT_ATTR_HIGHLIGHT )
    3676             :                 {
    3677           0 :                     const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
    3678           0 :                     aFontColor = rStyleSettings.GetHighlightColor() ;
    3679             :                 }
    3680             :             }
    3681             : 
    3682          31 :             sal_uInt8 nColorDiff = aFontColor.GetColorError( aBackgroundColor );
    3683          31 :             if( nColorDiff < 8 )
    3684           0 :                 aBackgroundColor = aFontColor.IsDark() ? COL_WHITE : COL_BLACK;
    3685          31 :             pVDev->SetBackground( aBackgroundColor );
    3686             :         }
    3687             : 
    3688          31 :         sal_Bool bVDevValid = sal_True;
    3689          31 :         Size aOutSz( pVDev->GetOutputSizePixel() );
    3690          77 :         if ( (  aOutSz.Width() < aClipRecPixel.GetWidth() ) ||
    3691          46 :              (  aOutSz.Height() < aClipRecPixel.GetHeight() ) )
    3692             :         {
    3693           8 :             bVDevValid = pVDev->SetOutputSizePixel( aClipRecPixel.GetSize() );
    3694             :         }
    3695             :         else
    3696             :         {
    3697             :             // The VirtDev can become very big during a Resize =>
    3698             :             // eventually make it smaller!
    3699          69 :             if ( ( aOutSz.Height() > ( aClipRecPixel.GetHeight() + RESDIFF ) ) ||
    3700          46 :                  ( aOutSz.Width() > ( aClipRecPixel.GetWidth() + RESDIFF ) ) )
    3701             :             {
    3702           0 :                 bVDevValid = pVDev->SetOutputSizePixel( aClipRecPixel.GetSize() );
    3703             :             }
    3704             :             else
    3705             :             {
    3706          23 :                 pVDev->Erase();
    3707             :             }
    3708             :         }
    3709             :         DBG_ASSERT( bVDevValid, "VDef could not be enlarged!" );
    3710          31 :         if ( !bVDevValid )
    3711             :         {
    3712           0 :             Paint( pView, rRec, sal_False /* ohne VDev */ );
    3713             :             return;
    3714             :         }
    3715             : 
    3716             :         // PaintRect for VDev not with aligned size,
    3717             :         // Otherwise, the line below must also be printed out:
    3718          31 :         Rectangle aTmpRec( Point( 0, 0 ), aClipRec.GetSize() );
    3719             : 
    3720          31 :         aClipRec = pOutWin->PixelToLogic( aClipRecPixel );
    3721          31 :         Point aStartPos;
    3722          31 :         if ( !IsVertical() )
    3723             :         {
    3724          31 :             aStartPos = aClipRec.TopLeft();
    3725          31 :             aStartPos = pView->GetDocPos( aStartPos );
    3726          31 :             aStartPos.X() *= (-1);
    3727          31 :             aStartPos.Y() *= (-1);
    3728             :         }
    3729             :         else
    3730             :         {
    3731           0 :             aStartPos = aClipRec.TopRight();
    3732           0 :             Point aDocPos( pView->GetDocPos( aStartPos ) );
    3733           0 :             aStartPos.X() = aClipRec.GetSize().Width() + aDocPos.Y();
    3734           0 :             aStartPos.Y() = -aDocPos.X();
    3735             :         }
    3736             : 
    3737          31 :         Paint( pVDev, aTmpRec, aStartPos );
    3738             : 
    3739          31 :         sal_Bool bClipRegion = sal_False;
    3740          31 :         Region aOldRegion;
    3741          31 :         MapMode aOldMapMode;
    3742          31 :         if ( GetTextRanger() )
    3743             :         {
    3744             :             // Some problems here with push/pop, why?!
    3745           0 :             bClipRegion = pOutWin->IsClipRegion();
    3746           0 :             aOldRegion = pOutWin->GetClipRegion();
    3747             :             // How do I get the polygon to the right place??
    3748             :             // The polygon is based on the view, not the Window
    3749             :             // => reset origin...
    3750           0 :             aOldMapMode = pOutWin->GetMapMode();
    3751           0 :             Point aOrigin = aOldMapMode.GetOrigin();
    3752           0 :             Point aViewPos = pView->GetOutputArea().TopLeft();
    3753           0 :             aOrigin.Move( aViewPos.X(), aViewPos.Y() );
    3754           0 :             aClipRec.Move( -aViewPos.X(), -aViewPos.Y() );
    3755           0 :             MapMode aNewMapMode( aOldMapMode );
    3756           0 :             aNewMapMode.SetOrigin( aOrigin );
    3757           0 :             pOutWin->SetMapMode( aNewMapMode );
    3758           0 :             pOutWin->SetClipRegion( Region( GetTextRanger()->GetPolyPolygon() ) );
    3759             :         }
    3760             : 
    3761             :         pOutWin->DrawOutDev( aClipRec.TopLeft(), aClipRec.GetSize(),
    3762          31 :                             Point(0,0), aClipRec.GetSize(), *pVDev );
    3763             : 
    3764          31 :         if ( GetTextRanger() )
    3765             :         {
    3766           0 :             if ( bClipRegion )
    3767           0 :                 pOutWin->SetClipRegion( aOldRegion );
    3768             :             else
    3769           0 :                 pOutWin->SetClipRegion();
    3770           0 :             pOutWin->SetMapMode( aOldMapMode );
    3771             :         }
    3772             : 
    3773             : 
    3774          31 :         pView->DrawSelection();
    3775             :     }
    3776             :     else
    3777             :     {
    3778           0 :         Point aStartPos;
    3779           0 :         if ( !IsVertical() )
    3780             :         {
    3781           0 :             aStartPos = pView->GetOutputArea().TopLeft();
    3782           0 :             aStartPos.X() -= pView->GetVisDocLeft();
    3783           0 :             aStartPos.Y() -= pView->GetVisDocTop();
    3784             :         }
    3785             :         else
    3786             :         {
    3787           0 :             aStartPos = pView->GetOutputArea().TopRight();
    3788           0 :             aStartPos.X() += pView->GetVisDocTop();
    3789           0 :             aStartPos.Y() -= pView->GetVisDocLeft();
    3790             :         }
    3791             : 
    3792             :         // If Doc-width < Output Area,Width and not wrapped fields,
    3793             :         // the fields usually protrude if > line.
    3794             :         // (Not at the top, since there the Doc-width from formatting is already
    3795             :         // there)
    3796           0 :         if ( !IsVertical() && ( pView->GetOutputArea().GetWidth() > GetPaperSize().Width() ) )
    3797             :         {
    3798           0 :             long nMaxX = pView->GetOutputArea().Left() + GetPaperSize().Width();
    3799           0 :             if ( aClipRec.Left() > nMaxX )
    3800             :                 return;
    3801           0 :             if ( aClipRec.Right() > nMaxX )
    3802           0 :                 aClipRec.Right() = nMaxX;
    3803             :         }
    3804             : 
    3805           0 :         sal_Bool bClipRegion = pOutWin->IsClipRegion();
    3806           0 :         Region aOldRegion = pOutWin->GetClipRegion();
    3807           0 :         pOutWin->IntersectClipRegion( aClipRec );
    3808             : 
    3809           0 :         Paint( pOutWin, aClipRec, aStartPos );
    3810             : 
    3811           0 :         if ( bClipRegion )
    3812           0 :             pOutWin->SetClipRegion( aOldRegion );
    3813             :         else
    3814           0 :             pOutWin->SetClipRegion();
    3815             : 
    3816           0 :         pView->DrawSelection();
    3817             :     }
    3818             : 
    3819             : }
    3820             : 
    3821           0 : void ImpEditEngine::InsertContent( ContentNode* pNode, sal_uInt16 nPos )
    3822             : {
    3823             :     DBG_ASSERT( pNode, "NULL-Pointer in InsertContent! " );
    3824             :     DBG_ASSERT( IsInUndo(), "InsertContent only for Undo()!" );
    3825           0 :     ParaPortion* pNew = new ParaPortion( pNode );
    3826           0 :     GetParaPortions().Insert(nPos, pNew);
    3827           0 :     aEditDoc.Insert(nPos, pNode);
    3828           0 :     if ( IsCallParaInsertedOrDeleted() )
    3829           0 :         GetEditEnginePtr()->ParagraphInserted( nPos );
    3830           0 : }
    3831             : 
    3832           0 : EditPaM ImpEditEngine::SplitContent( sal_uInt16 nNode, sal_uInt16 nSepPos )
    3833             : {
    3834           0 :     ContentNode* pNode = aEditDoc.GetObject( nNode );
    3835             :     DBG_ASSERT( pNode, "Invalid Node in SplitContent" );
    3836             :     DBG_ASSERT( IsInUndo(), "SplitContent only for Undo()!" );
    3837             :     DBG_ASSERT( nSepPos <= pNode->Len(), "Index out of range: SplitContent" );
    3838           0 :     EditPaM aPaM( pNode, nSepPos );
    3839           0 :     return ImpInsertParaBreak( aPaM );
    3840             : }
    3841             : 
    3842           0 : EditPaM ImpEditEngine::ConnectContents( sal_uInt16 nLeftNode, sal_Bool bBackward )
    3843             : {
    3844           0 :     ContentNode* pLeftNode = aEditDoc.GetObject( nLeftNode );
    3845           0 :     ContentNode* pRightNode = aEditDoc.GetObject( nLeftNode+1 );
    3846             :     DBG_ASSERT( pLeftNode, "Invalid left node in ConnectContents ");
    3847             :     DBG_ASSERT( pRightNode, "Invalid right node in ConnectContents ");
    3848             :     DBG_ASSERT( IsInUndo(), "ConnectContent only for Undo()!" );
    3849           0 :     return ImpConnectParagraphs( pLeftNode, pRightNode, bBackward );
    3850             : }
    3851             : 
    3852      188181 : void ImpEditEngine::SetUpdateMode( bool bUp, EditView* pCurView, sal_Bool bForceUpdate )
    3853             : {
    3854      188181 :     bool bChanged = ( GetUpdateMode() != bUp );
    3855             : 
    3856             :     // When switching from sal_True to sal_False, all selections were visible,
    3857             :     // => paint over
    3858             :     // the other hand, were all invisible => paint
    3859             :     // If !bFormatted, e.g. after SetText, then if UpdateMode=sal_True
    3860             :     // formatting is not needed immediately, probably because more text is coming.
    3861             :     // At latest it is formatted at a Paint/CalcTextWidth.
    3862      188181 :     bUpdate = bUp;
    3863      188181 :     if ( bUpdate && ( bChanged || bForceUpdate ) )
    3864       21675 :         FormatAndUpdate( pCurView );
    3865      188181 : }
    3866             : 
    3867           0 : void ImpEditEngine::ShowParagraph( sal_uInt16 nParagraph, bool bShow )
    3868             : {
    3869           0 :     ParaPortion* pPPortion = GetParaPortions().SafeGetObject( nParagraph );
    3870             :     DBG_ASSERT( pPPortion, "ShowParagraph: Paragraph does not exist! ");
    3871           0 :     if ( pPPortion && ( pPPortion->IsVisible() != bShow ) )
    3872             :     {
    3873           0 :         pPPortion->SetVisible( bShow );
    3874             : 
    3875           0 :         if ( !bShow )
    3876             :         {
    3877             :             // Mark as deleted, so that no selection will end or begin at
    3878             :             // this paragraph...
    3879           0 :             DeletedNodeInfo* pDelInfo = new DeletedNodeInfo( (sal_uIntPtr)pPPortion->GetNode(), nParagraph );
    3880           0 :             aDeletedNodes.push_back(pDelInfo);
    3881           0 :             UpdateSelections();
    3882             :             // The region below will not be invalidated if UpdateMode = sal_False!
    3883             :             // If anyway, then save as sal_False before SetVisible !
    3884             :         }
    3885             : 
    3886           0 :         if ( bShow && ( pPPortion->IsInvalid() || !pPPortion->nHeight ) )
    3887             :         {
    3888           0 :             if ( !GetTextRanger() )
    3889             :             {
    3890           0 :                 if ( pPPortion->IsInvalid() )
    3891             :                 {
    3892           0 :                     Font aOldFont( GetRefDevice()->GetFont() );
    3893           0 :                     CreateLines( nParagraph, 0 );   // 0: No TextRanger
    3894           0 :                     if ( aStatus.DoRestoreFont() )
    3895           0 :                         GetRefDevice()->SetFont( aOldFont );
    3896             :                 }
    3897             :                 else
    3898             :                 {
    3899           0 :                     CalcHeight( pPPortion );
    3900             :                 }
    3901           0 :                 nCurTextHeight += pPPortion->GetHeight();
    3902             :             }
    3903             :             else
    3904             :             {
    3905           0 :                 nCurTextHeight = 0x7fffffff;
    3906             :             }
    3907             :         }
    3908             : 
    3909           0 :         pPPortion->SetMustRepaint( sal_True );
    3910           0 :         if ( GetUpdateMode() && !IsInUndo() && !GetTextRanger() )
    3911             :         {
    3912           0 :             aInvalidRec = Rectangle(    Point( 0, GetParaPortions().GetYOffset( pPPortion ) ),
    3913           0 :                                         Point( GetPaperSize().Width(), nCurTextHeight ) );
    3914           0 :             UpdateViews( GetActiveView() );
    3915             :         }
    3916             :     }
    3917           0 : }
    3918             : 
    3919           0 : EditSelection ImpEditEngine::MoveParagraphs( Range aOldPositions, sal_uInt16 nNewPos, EditView* pCurView )
    3920             : {
    3921             :     DBG_ASSERT( GetParaPortions().Count() != 0, "No paragraphs found: MoveParagraphs" );
    3922           0 :     if ( GetParaPortions().Count() == 0 )
    3923           0 :         return EditSelection();
    3924           0 :     aOldPositions.Justify();
    3925             : 
    3926           0 :     EditSelection aSel( ImpMoveParagraphs( aOldPositions, nNewPos ) );
    3927             : 
    3928           0 :     if ( nNewPos >= GetParaPortions().Count() )
    3929           0 :         nNewPos = GetParaPortions().Count() - 1;
    3930             : 
    3931             :     // Where the paragraph was inserted it has to be properly redrawn:
    3932             :     // Where the paragraph was removed it has to be properly redrawn:
    3933             :     // ( and correspondingly in between as well...)
    3934           0 :     if ( pCurView && ( GetUpdateMode() == sal_True ) )
    3935             :     {
    3936             :         // in this case one can redraw directly whithout invalidating the
    3937             :         // Portions
    3938           0 :         sal_uInt16 nFirstPortion = Min( (sal_uInt16)aOldPositions.Min(), nNewPos );
    3939           0 :         sal_uInt16 nLastPortion = Max( (sal_uInt16)aOldPositions.Max(), nNewPos );
    3940             : 
    3941           0 :         ParaPortion* pUpperPortion = GetParaPortions().SafeGetObject( nFirstPortion );
    3942           0 :         ParaPortion* pLowerPortion = GetParaPortions().SafeGetObject( nLastPortion );
    3943             : 
    3944           0 :         aInvalidRec = Rectangle();  // make empty
    3945           0 :         aInvalidRec.Left() = 0;
    3946           0 :         aInvalidRec.Right() = aPaperSize.Width();
    3947           0 :         aInvalidRec.Top() = GetParaPortions().GetYOffset( pUpperPortion );
    3948           0 :         aInvalidRec.Bottom() = GetParaPortions().GetYOffset( pLowerPortion ) + pLowerPortion->GetHeight();
    3949             : 
    3950           0 :         UpdateViews( pCurView );
    3951             :     }
    3952             :     else
    3953             :     {
    3954             :         // redraw from the upper invalid position
    3955           0 :         sal_uInt16 nFirstInvPara = Min( (sal_uInt16)aOldPositions.Min(), nNewPos );
    3956           0 :         InvalidateFromParagraph( nFirstInvPara );
    3957             :     }
    3958           0 :     return aSel;
    3959             : }
    3960             : 
    3961           0 : void ImpEditEngine::InvalidateFromParagraph( sal_uInt16 nFirstInvPara )
    3962             : {
    3963             :     // The following paragraphs are not invalidated, since ResetHeight()
    3964             :     // => size change => all the following are re-issued anyway.
    3965             :     ParaPortion* pTmpPortion;
    3966           0 :     if ( nFirstInvPara != 0 )
    3967             :     {
    3968           0 :         pTmpPortion = GetParaPortions()[nFirstInvPara-1];
    3969           0 :         pTmpPortion->MarkInvalid( pTmpPortion->GetNode()->Len(), 0 );
    3970             :     }
    3971             :     else
    3972             :     {
    3973           0 :         pTmpPortion = GetParaPortions()[0];
    3974           0 :         pTmpPortion->MarkSelectionInvalid( 0, pTmpPortion->GetNode()->Len() );
    3975             :     }
    3976           0 :     pTmpPortion->ResetHeight();
    3977           0 : }
    3978             : 
    3979           1 : IMPL_LINK_NOARG_INLINE_START(ImpEditEngine, StatusTimerHdl)
    3980             : {
    3981           1 :     CallStatusHdl();
    3982           1 :     return 0;
    3983             : }
    3984           1 : IMPL_LINK_NOARG_INLINE_END(ImpEditEngine, StatusTimerHdl)
    3985             : 
    3986       51583 : void ImpEditEngine::CallStatusHdl()
    3987             : {
    3988       51583 :     if ( aStatusHdlLink.IsSet() && aStatus.GetStatusWord() )
    3989             :     {
    3990             :         // The Status has to be reset before the Call,
    3991             :         // since other Flags might be set in the handler...
    3992           4 :         EditStatus aTmpStatus( aStatus );
    3993           4 :         aStatus.Clear();
    3994           4 :         aStatusHdlLink.Call( &aTmpStatus );
    3995           4 :         aStatusTimer.Stop();    // If called by hand ...
    3996             :     }
    3997       51583 : }
    3998             : 
    3999           0 : ContentNode* ImpEditEngine::GetPrevVisNode( ContentNode* pCurNode )
    4000             : {
    4001           0 :     const ParaPortion* pPortion = FindParaPortion( pCurNode );
    4002             :     DBG_ASSERT( pPortion, "GetPrevVisibleNode: No matching portion!" );
    4003           0 :     pPortion = GetPrevVisPortion( pPortion );
    4004           0 :     if ( pPortion )
    4005           0 :         return pPortion->GetNode();
    4006           0 :     return 0;
    4007             : }
    4008             : 
    4009           0 : ContentNode* ImpEditEngine::GetNextVisNode( ContentNode* pCurNode )
    4010             : {
    4011           0 :     const ParaPortion* pPortion = FindParaPortion( pCurNode );
    4012             :     DBG_ASSERT( pPortion, "GetNextVisibleNode: No matching portion!" );
    4013           0 :     pPortion = GetNextVisPortion( pPortion );
    4014           0 :     if ( pPortion )
    4015           0 :         return pPortion->GetNode();
    4016           0 :     return 0;
    4017             : }
    4018             : 
    4019           0 : const ParaPortion* ImpEditEngine::GetPrevVisPortion( const ParaPortion* pCurPortion ) const
    4020             : {
    4021           0 :     sal_uInt16 nPara = GetParaPortions().GetPos( pCurPortion );
    4022             :     DBG_ASSERT( nPara < GetParaPortions().Count() , "Portion not found: GetPrevVisPortion" );
    4023           0 :     const ParaPortion* pPortion = nPara ? GetParaPortions()[--nPara] : 0;
    4024           0 :     while ( pPortion && !pPortion->IsVisible() )
    4025           0 :         pPortion = nPara ? GetParaPortions()[--nPara] : 0;
    4026             : 
    4027           0 :     return pPortion;
    4028             : }
    4029             : 
    4030           0 : const ParaPortion* ImpEditEngine::GetNextVisPortion( const ParaPortion* pCurPortion ) const
    4031             : {
    4032           0 :     sal_uInt16 nPara = GetParaPortions().GetPos( pCurPortion );
    4033             :     DBG_ASSERT( nPara < GetParaPortions().Count() , "Portion not found: GetPrevVisNode" );
    4034           0 :     const ParaPortion* pPortion = GetParaPortions().SafeGetObject( ++nPara );
    4035           0 :     while ( pPortion && !pPortion->IsVisible() )
    4036           0 :         pPortion = GetParaPortions().SafeGetObject( ++nPara );
    4037             : 
    4038           0 :     return pPortion;
    4039             : }
    4040             : 
    4041         140 : long ImpEditEngine::CalcVertLineSpacing(Point& rStartPos) const
    4042             : {
    4043         140 :     long nTotalOccupiedHeight = 0;
    4044         140 :     sal_uInt16 nTotalLineCount = 0;
    4045         140 :     const ParaPortionList& rParaPortions = GetParaPortions();
    4046         140 :     sal_uInt16 nParaCount = rParaPortions.Count();
    4047             : 
    4048         140 :     for (sal_uInt16 i = 0; i < nParaCount; ++i)
    4049             :     {
    4050         140 :         if (GetVerJustification(i) != SVX_VER_JUSTIFY_BLOCK)
    4051             :             // All paragraphs must have the block justification set.
    4052         140 :             return 0;
    4053             : 
    4054           0 :         const ParaPortion* pPortion = rParaPortions[i];
    4055           0 :         nTotalOccupiedHeight += pPortion->GetFirstLineOffset();
    4056             : 
    4057           0 :         const SvxLineSpacingItem& rLSItem = (const SvxLineSpacingItem&)pPortion->GetNode()->GetContentAttribs().GetItem(EE_PARA_SBL);
    4058           0 :         sal_uInt16 nSBL = ( rLSItem.GetInterLineSpaceRule() == SVX_INTER_LINE_SPACE_FIX )
    4059           0 :                             ? GetYValue( rLSItem.GetInterLineSpace() ) : 0;
    4060             : 
    4061           0 :         const SvxULSpaceItem& rULItem = (const SvxULSpaceItem&)pPortion->GetNode()->GetContentAttribs().GetItem(EE_PARA_ULSPACE);
    4062           0 :         long nUL = GetYValue( rULItem.GetLower() );
    4063             : 
    4064           0 :         const EditLineList& rLines = pPortion->GetLines();
    4065           0 :         sal_uInt16 nLineCount = rLines.Count();
    4066           0 :         nTotalLineCount += nLineCount;
    4067           0 :         for (sal_uInt16 j = 0; j < nLineCount; ++j)
    4068             :         {
    4069           0 :             const EditLine* pLine = rLines[j];
    4070           0 :             nTotalOccupiedHeight += pLine->GetHeight();
    4071           0 :             if (j < nLineCount-1)
    4072           0 :                 nTotalOccupiedHeight += nSBL;
    4073           0 :             nTotalOccupiedHeight += nUL;
    4074             :         }
    4075             :     }
    4076             : 
    4077           0 :     long nTotalSpace = IsVertical() ? aPaperSize.Width() : aPaperSize.Height();
    4078           0 :     nTotalSpace -= nTotalOccupiedHeight;
    4079           0 :     if (nTotalSpace <= 0 || nTotalLineCount <= 1)
    4080           0 :         return 0;
    4081             : 
    4082           0 :     if (IsVertical())
    4083             :         // Shift the text to the right for the asian layout mode.
    4084           0 :         rStartPos.X() += nTotalSpace;
    4085             : 
    4086           0 :     return nTotalSpace / (nTotalLineCount-1);
    4087             : }
    4088             : 
    4089         288 : EditPaM ImpEditEngine::InsertParagraph( sal_uInt16 nPara )
    4090             : {
    4091         288 :     EditPaM aPaM;
    4092         288 :     if ( nPara != 0 )
    4093             :     {
    4094         288 :         ContentNode* pNode = GetEditDoc().GetObject( nPara-1 );
    4095         288 :         if ( !pNode )
    4096           0 :             pNode = GetEditDoc().GetObject( GetEditDoc().Count() - 1 );
    4097             :         DBG_ASSERT( pNode, "Not a single paragraph in InsertParagraph ?" );
    4098         288 :         aPaM = EditPaM( pNode, pNode->Len() );
    4099             :     }
    4100             :     else
    4101             :     {
    4102           0 :         ContentNode* pNode = GetEditDoc().GetObject( 0 );
    4103           0 :         aPaM = EditPaM( pNode, 0 );
    4104             :     }
    4105             : 
    4106         288 :     return ImpInsertParaBreak( aPaM );
    4107             : }
    4108             : 
    4109        2050 : EditSelection* ImpEditEngine::SelectParagraph( sal_uInt16 nPara )
    4110             : {
    4111        2050 :     EditSelection* pSel = 0;
    4112        2050 :     ContentNode* pNode = GetEditDoc().GetObject( nPara );
    4113             :     DBG_ASSERTWARNING( pNode, "Paragraph does not exist: SelectParagraph" );
    4114        2050 :     if ( pNode )
    4115        2050 :         pSel = new EditSelection( EditPaM( pNode, 0 ), EditPaM( pNode, pNode->Len() ) );
    4116             : 
    4117        2050 :     return pSel;
    4118             : }
    4119             : 
    4120      101081 : void ImpEditEngine::FormatAndUpdate( EditView* pCurView )
    4121             : {
    4122      101081 :     if ( bDowning )
    4123      101081 :         return ;
    4124             : 
    4125      101081 :     if ( IsInUndo() )
    4126           0 :         IdleFormatAndUpdate( pCurView );
    4127             :     else
    4128             :     {
    4129      101081 :         FormatDoc();
    4130      101081 :         UpdateViews( pCurView );
    4131             :     }
    4132             : }
    4133             : 
    4134           0 : void ImpEditEngine::SetFlatMode( sal_Bool bFlat )
    4135             : {
    4136           0 :     if ( bFlat != aStatus.UseCharAttribs() )
    4137           0 :         return;
    4138             : 
    4139           0 :     if ( !bFlat )
    4140           0 :         aStatus.TurnOnFlags( EE_CNTRL_USECHARATTRIBS );
    4141             :     else
    4142           0 :         aStatus.TurnOffFlags( EE_CNTRL_USECHARATTRIBS );
    4143             : 
    4144           0 :     aEditDoc.CreateDefFont( !bFlat );
    4145             : 
    4146           0 :     FormatFullDoc();
    4147           0 :     UpdateViews( (EditView*) 0);
    4148           0 :     if ( pActiveView )
    4149           0 :         pActiveView->ShowCursor();
    4150             : }
    4151             : 
    4152       25163 : void ImpEditEngine::SetCharStretching( sal_uInt16 nX, sal_uInt16 nY )
    4153             : {
    4154       25163 :     bool bChanged(false);
    4155       25163 :     if ( !IsVertical() )
    4156             :     {
    4157       25163 :         bChanged = nStretchX!=nX || nStretchY!=nY;
    4158       25163 :         nStretchX = nX;
    4159       25163 :         nStretchY = nY;
    4160             :     }
    4161             :     else
    4162             :     {
    4163           0 :         bChanged = nStretchX!=nY || nStretchY!=nX;
    4164           0 :         nStretchX = nY;
    4165           0 :         nStretchY = nX;
    4166             :     }
    4167             : 
    4168       25163 :     if (bChanged && aStatus.DoStretch())
    4169             :     {
    4170           0 :         FormatFullDoc();
    4171             :         // (potentially) need everything redrawn
    4172           0 :         aInvalidRec=Rectangle(0,0,1000000,1000000);
    4173           0 :         UpdateViews( GetActiveView() );
    4174             :     }
    4175       25163 : }
    4176             : 
    4177       27641 : const SvxNumberFormat* ImpEditEngine::GetNumberFormat( const ContentNode *pNode ) const
    4178             : {
    4179       27641 :     const SvxNumberFormat *pRes = 0;
    4180             : 
    4181       27641 :     if (pNode)
    4182             :     {
    4183             :         // get index of paragraph
    4184       27641 :         sal_uInt16 nPara = GetEditDoc().GetPos( const_cast< ContentNode * >(pNode) );
    4185             :         DBG_ASSERT( nPara < USHRT_MAX, "node not found in array" );
    4186       27641 :         if (nPara < USHRT_MAX)
    4187             :         {
    4188             :             // the called function may be overloaded by an OutlinerEditEng object to provide
    4189             :             // access to the SvxNumberFormat of the Outliner.
    4190             :             // The EditEngine implementation will just return 0.
    4191       27641 :             pRes = pEditEngine->GetNumberFormat( nPara );
    4192             :         }
    4193             :     }
    4194             : 
    4195       27641 :     return pRes;
    4196             : }
    4197             : 
    4198       27641 : sal_Int32 ImpEditEngine::GetSpaceBeforeAndMinLabelWidth(
    4199             :     const ContentNode *pNode,
    4200             :     sal_Int32 *pnSpaceBefore, sal_Int32 *pnMinLabelWidth ) const
    4201             : {
    4202             :     // nSpaceBefore     matches the ODF attribut text:space-before
    4203             :     // nMinLabelWidth   matches the ODF attribut text:min-label-width
    4204             : 
    4205       27641 :     const SvxNumberFormat *pNumFmt = GetNumberFormat( pNode );
    4206             : 
    4207             :     // if no number format was found we have no Outliner or the numbering level
    4208             :     // within the Outliner is -1 which means no number format should be applied.
    4209             :     // Thus the default values to be returned are 0.
    4210       27641 :     sal_Int32 nSpaceBefore   = 0;
    4211       27641 :     sal_Int32 nMinLabelWidth = 0;
    4212             : 
    4213       27641 :     if (pNumFmt)
    4214             :     {
    4215        2789 :         nMinLabelWidth = -pNumFmt->GetFirstLineOffset();
    4216        2789 :         nSpaceBefore   = pNumFmt->GetAbsLSpace() - nMinLabelWidth;
    4217             :         DBG_ASSERT( nMinLabelWidth >= 0, "ImpEditEngine::GetSpaceBeforeAndMinLabelWidth: min-label-width < 0 encountered" );
    4218             :     }
    4219       27641 :     if (pnSpaceBefore)
    4220       25094 :         *pnSpaceBefore      = nSpaceBefore;
    4221       27641 :     if (pnMinLabelWidth)
    4222        7058 :         *pnMinLabelWidth    = nMinLabelWidth;
    4223             : 
    4224       27641 :     return nSpaceBefore + nMinLabelWidth;
    4225             : }
    4226             : 
    4227       27641 : const SvxLRSpaceItem& ImpEditEngine::GetLRSpaceItem( ContentNode* pNode )
    4228             : {
    4229       27641 :     return (const SvxLRSpaceItem&)pNode->GetContentAttribs().GetItem( aStatus.IsOutliner() ? EE_PARA_OUTLLRSPACE : EE_PARA_LRSPACE );
    4230             : }
    4231             : 
    4232             : // Either sets the digit mode at the output device or
    4233             : // modifies the passed string according to the text numeral setting:
    4234       23290 : void ImpEditEngine::ImplInitDigitMode( OutputDevice* pOutDev, String* pString, xub_StrLen nStt, xub_StrLen nLen, LanguageType eCurLang )
    4235             : {
    4236             :     // #114278# Also setting up digit language from Svt options
    4237             :     // (cannot reliably inherit the outdev's setting)
    4238       23290 :     if( !pCTLOptions )
    4239           0 :         pCTLOptions = new SvtCTLOptions;
    4240             : 
    4241       23290 :     LanguageType eLang = eCurLang;
    4242       23290 :     const SvtCTLOptions::TextNumerals nCTLTextNumerals = pCTLOptions->GetCTLTextNumerals();
    4243             : 
    4244       23290 :     if ( SvtCTLOptions::NUMERALS_HINDI == nCTLTextNumerals )
    4245           0 :         eLang = LANGUAGE_ARABIC_SAUDI_ARABIA;
    4246       23290 :     else if ( SvtCTLOptions::NUMERALS_ARABIC == nCTLTextNumerals )
    4247       23290 :         eLang = LANGUAGE_ENGLISH;
    4248           0 :     else if ( SvtCTLOptions::NUMERALS_SYSTEM == nCTLTextNumerals )
    4249           0 :         eLang = (LanguageType) Application::GetSettings().GetLanguageTag().getLanguageType();
    4250             : 
    4251       23290 :     if(pOutDev)
    4252             :     {
    4253       23076 :         pOutDev->SetDigitLanguage( eLang );
    4254             :     }
    4255         214 :     else if (pString)
    4256             :     {
    4257             :         // see sallayout.cxx in vcl
    4258             :         int nOffset;
    4259         214 :         switch( eLang & LANGUAGE_MASK_PRIMARY )
    4260             :         {
    4261             :             default:
    4262         214 :                 nOffset = 0;
    4263         214 :                 break;
    4264             :             case LANGUAGE_ARABIC_SAUDI_ARABIA  & LANGUAGE_MASK_PRIMARY:
    4265           0 :                 nOffset = 0x0660 - '0';  // arabic-indic digits
    4266           0 :                 break;
    4267             :             case LANGUAGE_URDU          & LANGUAGE_MASK_PRIMARY:
    4268             :             case LANGUAGE_PUNJABI       & LANGUAGE_MASK_PRIMARY: //???
    4269             :             case LANGUAGE_SINDHI        & LANGUAGE_MASK_PRIMARY:
    4270           0 :                 nOffset = 0x06F0 - '0';  // eastern arabic-indic digits
    4271           0 :                 break;
    4272             :         }
    4273         214 :         if (nOffset)
    4274             :         {
    4275           0 :             const xub_StrLen nEnd = nStt + nLen;
    4276           0 :             for( xub_StrLen nIdx = nStt; nIdx < nEnd; ++nIdx )
    4277             :             {
    4278           0 :                 sal_Unicode nChar = pString->GetChar( nIdx );
    4279           0 :                 if( (nChar < '0') || ('9' < nChar) )
    4280           0 :                     continue;
    4281           0 :                 nChar = (sal_Unicode)(nChar + nOffset);
    4282           0 :                 pString->SetChar( nIdx, nChar );
    4283             :             }
    4284             :         }
    4285             :     }
    4286       23290 : }
    4287             : 
    4288        9929 : void ImpEditEngine::ImplInitLayoutMode( OutputDevice* pOutDev, sal_uInt16 nPara, sal_uInt16 nIndex )
    4289             : {
    4290        9929 :     sal_Bool bCTL = sal_False;
    4291        9929 :     sal_uInt8 bR2L = sal_False;
    4292        9929 :     if ( nIndex == 0xFFFF )
    4293             :     {
    4294        9684 :         bCTL = HasScriptType( nPara, i18n::ScriptType::COMPLEX );
    4295        9684 :         bR2L = IsRightToLeft( nPara );
    4296             :     }
    4297             :     else
    4298             :     {
    4299         245 :         ContentNode* pNode = GetEditDoc().GetObject( nPara );
    4300         245 :         short nScriptType = GetScriptType( EditPaM( pNode, nIndex+1 ) );
    4301         245 :         bCTL = nScriptType == i18n::ScriptType::COMPLEX;
    4302         245 :         bR2L = GetRightToLeft( nPara, nIndex + 1);  // this change was discussed in issue 37190
    4303             :                                                     // it also works for issue 55927
    4304             :     }
    4305             : 
    4306        9929 :     sal_uLong nLayoutMode = pOutDev->GetLayoutMode();
    4307             : 
    4308             :     // We always use the left postion for DrawText()
    4309        9929 :     nLayoutMode &= ~(TEXT_LAYOUT_BIDI_RTL);
    4310             : 
    4311        9929 :     if ( !bCTL && !bR2L)
    4312             :     {
    4313             :         // No CTL/Bidi checking neccessary
    4314        9929 :         nLayoutMode |= ( TEXT_LAYOUT_COMPLEX_DISABLED | TEXT_LAYOUT_BIDI_STRONG );
    4315             :     }
    4316             :     else
    4317             :     {
    4318             :         // CTL/Bidi checking neccessary
    4319             :         // Don't use BIDI_STRONG, VCL must do some checks.
    4320           0 :         nLayoutMode &= ~( TEXT_LAYOUT_COMPLEX_DISABLED | TEXT_LAYOUT_BIDI_STRONG );
    4321             : 
    4322           0 :         if ( bR2L )
    4323           0 :             nLayoutMode |= TEXT_LAYOUT_BIDI_RTL|TEXT_LAYOUT_TEXTORIGIN_LEFT;
    4324             :     }
    4325             : 
    4326        9929 :     pOutDev->SetLayoutMode( nLayoutMode );
    4327             : 
    4328             :     // #114278# Also setting up digit language from Svt options
    4329             :     // (cannot reliably inherit the outdev's setting)
    4330             :     LanguageType eLang;
    4331             : 
    4332        9929 :     if( !pCTLOptions )
    4333         347 :         pCTLOptions = new SvtCTLOptions;
    4334             : 
    4335        9929 :     if ( SvtCTLOptions::NUMERALS_HINDI == pCTLOptions->GetCTLTextNumerals() )
    4336           0 :         eLang = LANGUAGE_ARABIC_SAUDI_ARABIA;
    4337        9929 :     else if ( SvtCTLOptions::NUMERALS_ARABIC == pCTLOptions->GetCTLTextNumerals() )
    4338        9929 :         eLang = LANGUAGE_ENGLISH;
    4339             :     else
    4340           0 :         eLang = (LanguageType) Application::GetSettings().GetLanguageTag().getLanguageType();
    4341             : 
    4342        9929 :     pOutDev->SetDigitLanguage( eLang );
    4343        9929 : }
    4344             : 
    4345       19426 : Reference < i18n::XBreakIterator > ImpEditEngine::ImplGetBreakIterator() const
    4346             : {
    4347       19426 :     if ( !xBI.is() )
    4348             :     {
    4349        1280 :         Reference< uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
    4350        1280 :         xBI = i18n::BreakIterator::create( xContext );
    4351             :     }
    4352       19426 :     return xBI;
    4353             : }
    4354             : 
    4355           0 : Reference < i18n::XExtendedInputSequenceChecker > ImpEditEngine::ImplGetInputSequenceChecker() const
    4356             : {
    4357           0 :     if ( !xISC.is() )
    4358             :     {
    4359           0 :         Reference< lang::XMultiServiceFactory > xMSF = ::comphelper::getProcessServiceFactory();
    4360           0 :         Reference < XInterface > xI = xMSF->createInstance( OUString( "com.sun.star.i18n.InputSequenceChecker" ) );
    4361           0 :         if ( xI.is() )
    4362             :         {
    4363           0 :             Any x = xI->queryInterface( ::getCppuType((const Reference< i18n::XExtendedInputSequenceChecker >*)0) );
    4364           0 :             x >>= xISC;
    4365           0 :         }
    4366             :     }
    4367           0 :     return xISC;
    4368             : }
    4369             : 
    4370         447 : Color ImpEditEngine::GetAutoColor() const
    4371             : {
    4372         447 :     Color aColor = const_cast<ImpEditEngine*>(this)->GetColorConfig().GetColorValue( svtools::FONTCOLOR ).nColor;
    4373             : 
    4374         447 :     if ( GetBackgroundColor() != COL_AUTO )
    4375             :     {
    4376           1 :         if ( GetBackgroundColor().IsDark() && aColor.IsDark() )
    4377           0 :             aColor = COL_WHITE;
    4378           1 :         else if ( GetBackgroundColor().IsBright() && aColor.IsBright() )
    4379           0 :             aColor = COL_BLACK;
    4380             :     }
    4381             : 
    4382         447 :     return aColor;
    4383             : }
    4384             : 
    4385             : 
    4386           0 : sal_Bool ImpEditEngine::ImplCalcAsianCompression( ContentNode* pNode, TextPortion* pTextPortion, sal_uInt16 nStartPos, sal_Int32* pDXArray, sal_uInt16 n100thPercentFromMax, sal_Bool bManipulateDXArray )
    4387             : {
    4388             :     DBG_ASSERT( GetAsianCompressionMode(), "ImplCalcAsianCompression - Why?" );
    4389             :     DBG_ASSERT( pTextPortion->GetLen(), "ImplCalcAsianCompression - Empty Portion?" );
    4390             : 
    4391             :     // Percent is 1/100 Percent...
    4392           0 :     if ( n100thPercentFromMax == 10000 )
    4393           0 :         pTextPortion->SetExtraInfos( NULL );
    4394             : 
    4395           0 :     sal_Bool bCompressed = sal_False;
    4396             : 
    4397           0 :     if ( GetScriptType( EditPaM( pNode, nStartPos+1 ) ) == i18n::ScriptType::ASIAN )
    4398             :     {
    4399           0 :         long nNewPortionWidth = pTextPortion->GetSize().Width();
    4400           0 :         sal_uInt16 nPortionLen = pTextPortion->GetLen();
    4401           0 :         for ( sal_uInt16 n = 0; n < nPortionLen; n++ )
    4402             :         {
    4403           0 :             sal_uInt8 nType = GetCharTypeForCompression( pNode->GetChar( n+nStartPos ) );
    4404             : 
    4405           0 :             sal_Bool bCompressPunctuation = ( nType == CHAR_PUNCTUATIONLEFT ) || ( nType == CHAR_PUNCTUATIONRIGHT );
    4406           0 :             sal_Bool bCompressKana = ( nType == CHAR_KANA ) && ( GetAsianCompressionMode() == text::CharacterCompressionType::PUNCTUATION_AND_KANA );
    4407             : 
    4408             :             // create Extra infos only if needed...
    4409           0 :             if ( bCompressPunctuation || bCompressKana )
    4410             :             {
    4411           0 :                 if ( !pTextPortion->GetExtraInfos() )
    4412             :                 {
    4413           0 :                     ExtraPortionInfo* pExtraInfos = new ExtraPortionInfo;
    4414           0 :                     pTextPortion->SetExtraInfos( pExtraInfos );
    4415           0 :                     pExtraInfos->nOrgWidth = pTextPortion->GetSize().Width();
    4416           0 :                     pExtraInfos->nAsianCompressionTypes = CHAR_NORMAL;
    4417             :                 }
    4418           0 :                 pTextPortion->GetExtraInfos()->nMaxCompression100thPercent = n100thPercentFromMax;
    4419           0 :                 pTextPortion->GetExtraInfos()->nAsianCompressionTypes |= nType;
    4420             : 
    4421             :                 long nOldCharWidth;
    4422           0 :                 if ( (n+1) < nPortionLen )
    4423             :                 {
    4424           0 :                     nOldCharWidth = pDXArray[n];
    4425             :                 }
    4426             :                 else
    4427             :                 {
    4428           0 :                     if ( bManipulateDXArray )
    4429           0 :                         nOldCharWidth = nNewPortionWidth - pTextPortion->GetExtraInfos()->nPortionOffsetX;
    4430             :                     else
    4431           0 :                         nOldCharWidth = pTextPortion->GetExtraInfos()->nOrgWidth;
    4432             :                 }
    4433           0 :                 nOldCharWidth -= ( n ? pDXArray[n-1] : 0 );
    4434             : 
    4435           0 :                 long nCompress = 0;
    4436             : 
    4437           0 :                 if ( bCompressPunctuation )
    4438             :                 {
    4439           0 :                     nCompress = nOldCharWidth / 2;
    4440             :                 }
    4441             :                 else // Kana
    4442             :                 {
    4443           0 :                     nCompress = nOldCharWidth / 10;
    4444             :                 }
    4445             : 
    4446           0 :                 if ( n100thPercentFromMax != 10000 )
    4447             :                 {
    4448           0 :                     nCompress *= n100thPercentFromMax;
    4449           0 :                     nCompress /= 10000;
    4450             :                 }
    4451             : 
    4452           0 :                 if ( nCompress )
    4453             :                 {
    4454           0 :                     bCompressed = sal_True;
    4455           0 :                     nNewPortionWidth -= nCompress;
    4456           0 :                     pTextPortion->GetExtraInfos()->bCompressed = sal_True;
    4457             : 
    4458             : 
    4459             :                     // Special handling for rightpunctuation: For the 'compression' we must
    4460             :                     // start the output before the normal char position....
    4461           0 :                     if ( bManipulateDXArray && ( pTextPortion->GetLen() > 1 ) )
    4462             :                     {
    4463           0 :                         if ( !pTextPortion->GetExtraInfos()->pOrgDXArray )
    4464           0 :                             pTextPortion->GetExtraInfos()->SaveOrgDXArray( pDXArray, pTextPortion->GetLen()-1 );
    4465             : 
    4466           0 :                         if ( nType == CHAR_PUNCTUATIONRIGHT )
    4467             :                         {
    4468             :                             // If it's the first char, I must handle it in Paint()...
    4469           0 :                             if ( n )
    4470             :                             {
    4471             :                                 // -1: No entry for the last character
    4472           0 :                                 for ( sal_uInt16 i = n-1; i < (nPortionLen-1); i++ )
    4473           0 :                                     pDXArray[i] -= nCompress;
    4474             :                             }
    4475             :                             else
    4476             :                             {
    4477           0 :                                 pTextPortion->GetExtraInfos()->bFirstCharIsRightPunktuation = sal_True;
    4478           0 :                                 pTextPortion->GetExtraInfos()->nPortionOffsetX = -nCompress;
    4479             :                             }
    4480             :                         }
    4481             :                         else
    4482             :                         {
    4483             :                             // -1: No entry for the last character
    4484           0 :                             for ( sal_uInt16 i = n; i < (nPortionLen-1); i++ )
    4485           0 :                                 pDXArray[i] -= nCompress;
    4486             :                         }
    4487             :                     }
    4488             :                 }
    4489             :             }
    4490             :         }
    4491             : 
    4492           0 :         if ( bCompressed && ( n100thPercentFromMax == 10000 ) )
    4493           0 :             pTextPortion->GetExtraInfos()->nWidthFullCompression = nNewPortionWidth;
    4494             : 
    4495           0 :         pTextPortion->GetSize().Width() = nNewPortionWidth;
    4496             : 
    4497           0 :         if ( pTextPortion->GetExtraInfos() && ( n100thPercentFromMax != 10000 ) )
    4498             :         {
    4499             :             // Maybe rounding errors in nNewPortionWidth, assure that width not bigger than expected
    4500           0 :             long nShrink = pTextPortion->GetExtraInfos()->nOrgWidth - pTextPortion->GetExtraInfos()->nWidthFullCompression;
    4501           0 :             nShrink *= n100thPercentFromMax;
    4502           0 :             nShrink /= 10000;
    4503           0 :             long nNewWidth = pTextPortion->GetExtraInfos()->nOrgWidth - nShrink;
    4504           0 :             if ( nNewWidth < pTextPortion->GetSize().Width() )
    4505           0 :             pTextPortion->GetSize().Width() = nNewWidth;
    4506             :         }
    4507             :     }
    4508           0 :     return bCompressed;
    4509             : }
    4510             : 
    4511             : 
    4512           0 : void ImpEditEngine::ImplExpandCompressedPortions( EditLine* pLine, ParaPortion* pParaPortion, long nRemainingWidth )
    4513             : {
    4514           0 :     sal_Bool bFoundCompressedPortion = sal_False;
    4515           0 :     long nCompressed = 0;
    4516           0 :     std::vector<TextPortion*> aCompressedPortions;
    4517             : 
    4518           0 :     sal_uInt16 nPortion = pLine->GetEndPortion();
    4519           0 :     TextPortion* pTP = pParaPortion->GetTextPortions()[ nPortion ];
    4520           0 :     while ( pTP && ( pTP->GetKind() == PORTIONKIND_TEXT ) )
    4521             :     {
    4522           0 :         if ( pTP->GetExtraInfos() && pTP->GetExtraInfos()->bCompressed )
    4523             :         {
    4524           0 :             bFoundCompressedPortion = sal_True;
    4525           0 :             nCompressed += pTP->GetExtraInfos()->nOrgWidth - pTP->GetSize().Width();
    4526           0 :             aCompressedPortions.push_back(pTP);
    4527             :         }
    4528           0 :         pTP = ( nPortion > pLine->GetStartPortion() ) ? pParaPortion->GetTextPortions()[ --nPortion ] : NULL;
    4529             :     }
    4530             : 
    4531           0 :     if ( bFoundCompressedPortion )
    4532             :     {
    4533           0 :         long nCompressPercent = 0;
    4534           0 :         if ( nCompressed > nRemainingWidth )
    4535             :         {
    4536           0 :             nCompressPercent = nCompressed - nRemainingWidth;
    4537             :             DBG_ASSERT( nCompressPercent < 200000, "ImplExpandCompressedPortions - Overflow!" );
    4538           0 :             nCompressPercent *= 10000;
    4539           0 :             nCompressPercent /= nCompressed;
    4540             :         }
    4541             : 
    4542           0 :         for (size_t i = 0, n = aCompressedPortions.size(); i < n; ++i)
    4543             :         {
    4544           0 :             pTP = aCompressedPortions[i];
    4545           0 :             pTP->GetExtraInfos()->bCompressed = sal_False;
    4546           0 :             pTP->GetSize().Width() = pTP->GetExtraInfos()->nOrgWidth;
    4547           0 :             if ( nCompressPercent )
    4548             :             {
    4549           0 :                 size_t nTxtPortion = pParaPortion->GetTextPortions().GetPos( pTP );
    4550           0 :                 sal_uInt16 nTxtPortionStart = pParaPortion->GetTextPortions().GetStartPos( nTxtPortion );
    4551             :                 DBG_ASSERT( nTxtPortionStart >= pLine->GetStart(), "Portion doesn't belong to the line!!!" );
    4552           0 :                 sal_Int32* pDXArray = NULL;
    4553           0 :                 if (!pLine->GetCharPosArray().empty())
    4554           0 :                     pDXArray = &pLine->GetCharPosArray()[0]+( nTxtPortionStart-pLine->GetStart() );
    4555           0 :                 if ( pTP->GetExtraInfos()->pOrgDXArray )
    4556           0 :                     memcpy( pDXArray, pTP->GetExtraInfos()->pOrgDXArray, (pTP->GetLen()-1)*sizeof(sal_Int32) );
    4557           0 :                 ImplCalcAsianCompression( pParaPortion->GetNode(), pTP, nTxtPortionStart, pDXArray, (sal_uInt16)nCompressPercent, sal_True );
    4558             :             }
    4559             :         }
    4560           0 :     }
    4561           0 : }
    4562             : 
    4563             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10