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

Generated by: LCOV version 1.10