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

Generated by: LCOV version 1.11