LCOV - code coverage report
Current view: top level - editeng/source/editeng - impedit3.cxx (source / functions) Hit Total Coverage
Test: commit 0e63ca4fde4e446f346e35849c756a30ca294aab Lines: 1404 2297 61.1 %
Date: 2014-04-11 Functions: 44 66 66.7 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10