LCOV - code coverage report
Current view: top level - editeng/source/editeng - impedit3.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 1411 2298 61.4 %
Date: 2014-11-03 Functions: 46 68 67.6 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10