LCOV - code coverage report
Current view: top level - vcl/source/outdev - text.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 880 1535 57.3 %
Date: 2014-11-03 Functions: 41 48 85.4 %
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             : #include <sal/config.h>
      21             : 
      22             : #include <cmath>
      23             : 
      24             : #include <sal/types.h>
      25             : 
      26             : #include <basegfx/matrix/b2dhommatrix.hxx>
      27             : 
      28             : #include <com/sun/star/i18n/WordType.hpp>
      29             : #include <com/sun/star/i18n/XBreakIterator.hpp>
      30             : #include <com/sun/star/linguistic2/LinguServiceManager.hpp>
      31             : 
      32             : #include <comphelper/processfactory.hxx>
      33             : 
      34             : #include <vcl/outdev.hxx>
      35             : #include <vcl/virdev.hxx>
      36             : #include <vcl/bmpacc.hxx>
      37             : #include <vcl/settings.hxx>
      38             : #include <vcl/sysdata.hxx>
      39             : #include <vcl/unohelp.hxx>
      40             : #include <vcl/controllayout.hxx>
      41             : 
      42             : #include <outdata.hxx>
      43             : #include <outdev.h>
      44             : #include <salgdi.hxx>
      45             : #include <svdata.hxx>
      46             : #include <textlayout.hxx>
      47             : 
      48             : #include <config_graphite.h>
      49             : #if ENABLE_GRAPHITE
      50             : #include "graphite_features.hxx"
      51             : #endif
      52             : 
      53             : #define TEXT_DRAW_ELLIPSIS  (TEXT_DRAW_ENDELLIPSIS | TEXT_DRAW_PATHELLIPSIS | TEXT_DRAW_NEWSELLIPSIS)
      54             : 
      55       22758 : ImplMultiTextLineInfo::ImplMultiTextLineInfo()
      56             : {
      57       22758 :     mpLines = new PImplTextLineInfo[MULTITEXTLINEINFO_RESIZE];
      58       22758 :     mnLines = 0;
      59       22758 :     mnSize  = MULTITEXTLINEINFO_RESIZE;
      60       22758 : }
      61             : 
      62       22758 : ImplMultiTextLineInfo::~ImplMultiTextLineInfo()
      63             : {
      64       72193 :     for( sal_Int32 i = 0; i < mnLines; i++ )
      65       49435 :         delete mpLines[i];
      66       22758 :     delete [] mpLines;
      67       22758 : }
      68             : 
      69       49435 : void ImplMultiTextLineInfo::AddLine( ImplTextLineInfo* pLine )
      70             : {
      71       49435 :     if ( mnSize == mnLines )
      72             :     {
      73           0 :         mnSize += MULTITEXTLINEINFO_RESIZE;
      74           0 :         PImplTextLineInfo* pNewLines = new PImplTextLineInfo[mnSize];
      75           0 :         memcpy( pNewLines, mpLines, mnLines*sizeof(PImplTextLineInfo) );
      76           0 :         mpLines = pNewLines;
      77             :     }
      78             : 
      79       49435 :     mpLines[mnLines] = pLine;
      80       49435 :     mnLines++;
      81       49435 : }
      82             : 
      83       22758 : void ImplMultiTextLineInfo::Clear()
      84             : {
      85       22758 :     for( sal_Int32 i = 0; i < mnLines; i++ )
      86           0 :         delete mpLines[i];
      87       22758 :     mnLines = 0;
      88       22758 : }
      89             : 
      90       96261 : void OutputDevice::ImplInitTextColor()
      91             : {
      92             :     DBG_TESTSOLARMUTEX();
      93             : 
      94       96261 :     if ( mbInitTextColor )
      95             :     {
      96       92673 :         mpGraphics->SetTextColor( ImplColorToSal( GetTextColor() ) );
      97       92673 :         mbInitTextColor = false;
      98             :     }
      99       96261 : }
     100             : 
     101       85856 : void OutputDevice::ImplDrawTextRect( long nBaseX, long nBaseY,
     102             :                                      long nDistX, long nDistY, long nWidth, long nHeight )
     103             : {
     104       85856 :     long nX = nDistX;
     105       85856 :     long nY = nDistY;
     106             : 
     107       85856 :     short nOrientation = mpFontEntry->mnOrientation;
     108       85856 :     if ( nOrientation )
     109             :     {
     110             :         // Rotate rect without rounding problems for 90 degree rotations
     111       27858 :         if ( !(nOrientation % 900) )
     112             :         {
     113       18206 :             if ( nOrientation == 900 )
     114             :             {
     115           0 :                 long nTemp = nX;
     116           0 :                 nX = nY;
     117           0 :                 nY = -nTemp;
     118           0 :                 nTemp = nWidth;
     119           0 :                 nWidth = nHeight;
     120           0 :                 nHeight = nTemp;
     121           0 :                 nY -= nHeight;
     122             :             }
     123       18206 :             else if ( nOrientation == 1800 )
     124             :             {
     125           0 :                 nX = -nX;
     126           0 :                 nY = -nY;
     127           0 :                 nX -= nWidth;
     128           0 :                 nY -= nHeight;
     129             :             }
     130             :             else /* ( nOrientation == 2700 ) */
     131             :             {
     132       18206 :                 long nTemp = nX;
     133       18206 :                 nX = -nY;
     134       18206 :                 nY = nTemp;
     135       18206 :                 nTemp = nWidth;
     136       18206 :                 nWidth = nHeight;
     137       18206 :                 nHeight = nTemp;
     138       18206 :                 nX -= nWidth;
     139             :             }
     140             :         }
     141             :         else
     142             :         {
     143        9652 :             nX += nBaseX;
     144        9652 :             nY += nBaseY;
     145             :             // inflate because polygons are drawn smaller
     146        9652 :             Rectangle aRect( Point( nX, nY ), Size( nWidth+1, nHeight+1 ) );
     147        9652 :             Polygon   aPoly( aRect );
     148        9652 :             aPoly.Rotate( Point( nBaseX, nBaseY ), mpFontEntry->mnOrientation );
     149        9652 :             ImplDrawPolygon( aPoly );
     150       95508 :             return;
     151             :         }
     152             :     }
     153             : 
     154       76204 :     nX += nBaseX;
     155       76204 :     nY += nBaseY;
     156       76204 :     mpGraphics->DrawRect( nX, nY, nWidth, nHeight, this ); // original code
     157             : 
     158             : }
     159             : 
     160       21080 : void OutputDevice::ImplDrawTextBackground( const SalLayout& rSalLayout )
     161             : {
     162       21080 :     const long nWidth = rSalLayout.GetTextWidth() / rSalLayout.GetUnitsPerPixel();
     163       21080 :     const Point aBase = rSalLayout.DrawBase();
     164       21080 :     const long nX = aBase.X();
     165       21080 :     const long nY = aBase.Y();
     166             : 
     167       21080 :     if ( mbLineColor || mbInitLineColor )
     168             :     {
     169       21051 :         mpGraphics->SetLineColor();
     170       21051 :         mbInitLineColor = true;
     171             :     }
     172       21080 :     mpGraphics->SetFillColor( ImplColorToSal( GetTextFillColor() ) );
     173       21080 :     mbInitFillColor = true;
     174             : 
     175       21080 :     ImplDrawTextRect( nX, nY, 0, -(mpFontEntry->maMetric.mnAscent + mnEmphasisAscent),
     176             :                       nWidth,
     177       42160 :                       mpFontEntry->mnLineHeight+mnEmphasisAscent+mnEmphasisDescent );
     178       21080 : }
     179             : 
     180           0 : Rectangle OutputDevice::ImplGetTextBoundRect( const SalLayout& rSalLayout )
     181             : {
     182           0 :     Point aPoint = rSalLayout.GetDrawPosition();
     183           0 :     long nX = aPoint.X();
     184           0 :     long nY = aPoint.Y();
     185             : 
     186           0 :     long nWidth = rSalLayout.GetTextWidth();
     187           0 :     long nHeight = mpFontEntry->mnLineHeight + mnEmphasisAscent + mnEmphasisDescent;
     188             : 
     189           0 :     nY -= mpFontEntry->maMetric.mnAscent + mnEmphasisAscent;
     190             : 
     191           0 :     if ( mpFontEntry->mnOrientation )
     192             :     {
     193           0 :         long nBaseX = nX, nBaseY = nY;
     194           0 :         if ( !(mpFontEntry->mnOrientation % 900) )
     195             :         {
     196           0 :             long nX2 = nX+nWidth;
     197           0 :             long nY2 = nY+nHeight;
     198             : 
     199           0 :             Point aBasePt( nBaseX, nBaseY );
     200           0 :             aBasePt.RotateAround( nX, nY, mpFontEntry->mnOrientation );
     201           0 :             aBasePt.RotateAround( nX2, nY2, mpFontEntry->mnOrientation );
     202           0 :             nWidth = nX2-nX;
     203           0 :             nHeight = nY2-nY;
     204             :         }
     205             :         else
     206             :         {
     207             :             // inflate by +1+1 because polygons are drawn smaller
     208           0 :             Rectangle aRect( Point( nX, nY ), Size( nWidth+1, nHeight+1 ) );
     209           0 :             Polygon   aPoly( aRect );
     210           0 :             aPoly.Rotate( Point( nBaseX, nBaseY ), mpFontEntry->mnOrientation );
     211           0 :             return aPoly.GetBoundRect();
     212             :         }
     213             :     }
     214             : 
     215           0 :     return Rectangle( Point( nX, nY ), Size( nWidth, nHeight ) );
     216             : }
     217             : 
     218           0 : bool OutputDevice::ImplDrawRotateText( SalLayout& rSalLayout )
     219             : {
     220           0 :     int nX = rSalLayout.DrawBase().X();
     221           0 :     int nY = rSalLayout.DrawBase().Y();
     222             : 
     223           0 :     Rectangle aBoundRect;
     224           0 :     rSalLayout.DrawBase() = Point( 0, 0 );
     225           0 :     rSalLayout.DrawOffset() = Point( 0, 0 );
     226           0 :     if( !rSalLayout.GetBoundRect( *mpGraphics, aBoundRect ) )
     227             :     {
     228             :         // guess vertical text extents if GetBoundRect failed
     229           0 :         int nRight = rSalLayout.GetTextWidth();
     230           0 :         int nTop = mpFontEntry->maMetric.mnAscent + mnEmphasisAscent;
     231           0 :         long nHeight = mpFontEntry->mnLineHeight + mnEmphasisAscent + mnEmphasisDescent;
     232           0 :         aBoundRect = Rectangle( 0, -nTop, nRight, nHeight - nTop );
     233             :     }
     234             : 
     235             :     // cache virtual device for rotation
     236           0 :     if ( !mpOutDevData->mpRotateDev )
     237           0 :         mpOutDevData->mpRotateDev = new VirtualDevice( *this, 1 );
     238           0 :     VirtualDevice* pVDev = mpOutDevData->mpRotateDev;
     239             : 
     240             :     // size it accordingly
     241           0 :     if( !pVDev->SetOutputSizePixel( aBoundRect.GetSize() ) )
     242           0 :         return false;
     243             : 
     244           0 :     vcl::Font aFont( GetFont() );
     245           0 :     aFont.SetOrientation( 0 );
     246           0 :     aFont.SetSize( Size( mpFontEntry->maFontSelData.mnWidth, mpFontEntry->maFontSelData.mnHeight ) );
     247           0 :     pVDev->SetFont( aFont );
     248           0 :     pVDev->SetTextColor( Color( COL_BLACK ) );
     249           0 :     pVDev->SetTextFillColor();
     250           0 :     pVDev->ImplNewFont();
     251           0 :     pVDev->InitFont();
     252           0 :     pVDev->ImplInitTextColor();
     253             : 
     254             :     // draw text into upper left corner
     255           0 :     rSalLayout.DrawBase() -= aBoundRect.TopLeft();
     256           0 :     rSalLayout.DrawText( *((OutputDevice*)pVDev)->mpGraphics );
     257             : 
     258           0 :     Bitmap aBmp = pVDev->GetBitmap( Point(), aBoundRect.GetSize() );
     259           0 :     if ( !aBmp || !aBmp.Rotate( mpFontEntry->mnOwnOrientation, COL_WHITE ) )
     260           0 :         return false;
     261             : 
     262             :     // calculate rotation offset
     263           0 :     Polygon aPoly( aBoundRect );
     264           0 :     aPoly.Rotate( Point(), mpFontEntry->mnOwnOrientation );
     265           0 :     Point aPoint = aPoly.GetBoundRect().TopLeft();
     266           0 :     aPoint += Point( nX, nY );
     267             : 
     268             :     // mask output with text colored bitmap
     269           0 :     GDIMetaFile* pOldMetaFile = mpMetaFile;
     270           0 :     long nOldOffX = mnOutOffX;
     271           0 :     long nOldOffY = mnOutOffY;
     272           0 :     bool bOldMap = mbMap;
     273             : 
     274           0 :     mnOutOffX   = 0L;
     275           0 :     mnOutOffY   = 0L;
     276           0 :     mpMetaFile  = NULL;
     277           0 :     EnableMapMode( false );
     278             : 
     279           0 :     DrawMask( aPoint, aBmp, GetTextColor() );
     280             : 
     281           0 :     EnableMapMode( bOldMap );
     282           0 :     mnOutOffX   = nOldOffX;
     283           0 :     mnOutOffY   = nOldOffY;
     284           0 :     mpMetaFile  = pOldMetaFile;
     285             : 
     286           0 :     return true;
     287             : }
     288             : 
     289      340441 : bool OutputDevice::ImplDrawTextDirect( SalLayout& rSalLayout,
     290             :                                        bool bTextLines,
     291             :                                        sal_uInt32 flags )
     292             : {
     293      340441 :     if( mpFontEntry->mnOwnOrientation )
     294           0 :         if( ImplDrawRotateText( rSalLayout ) )
     295           0 :             return true;
     296             : 
     297             : 
     298             : 
     299             : 
     300      340441 :     long nOldX = rSalLayout.DrawBase().X();
     301      340441 :     if( HasMirroredGraphics() )
     302             :     {
     303         222 :         long w = meOutDevType == OUTDEV_VIRDEV ? mnOutWidth : mpGraphics->GetGraphicsWidth();
     304         222 :         long x = rSalLayout.DrawBase().X();
     305         222 :            rSalLayout.DrawBase().X() = w - 1 - x;
     306         222 :         if( !IsRTLEnabled() )
     307             :         {
     308           0 :             OutputDevice *pOutDevRef = (OutputDevice *)this;
     309             :             // mirror this window back
     310           0 :             long devX = w-pOutDevRef->mnOutWidth-pOutDevRef->mnOutOffX;   // re-mirrored mnOutOffX
     311           0 :             rSalLayout.DrawBase().X() = devX + ( pOutDevRef->mnOutWidth - 1 - (rSalLayout.DrawBase().X() - devX) ) ;
     312             :         }
     313             :     }
     314      340219 :     else if( IsRTLEnabled() )
     315             :     {
     316           0 :         OutputDevice *pOutDevRef = (OutputDevice *)this;
     317             : 
     318             :         // mirror this window back
     319           0 :         long devX = pOutDevRef->mnOutOffX;   // re-mirrored mnOutOffX
     320           0 :         rSalLayout.DrawBase().X() = pOutDevRef->mnOutWidth - 1 - (rSalLayout.DrawBase().X() - devX) + devX;
     321             :     }
     322             : 
     323      340441 :     if(flags)
     324             :     {
     325         132 :         if( ! rSalLayout.DrawTextSpecial( *mpGraphics, flags ))
     326             :         {
     327         132 :             rSalLayout.DrawBase().X() = nOldX;
     328         132 :             return false;
     329             :         }
     330             :     }
     331             :     else
     332             :     {
     333      340309 :         rSalLayout.DrawText( *mpGraphics );
     334             :     }
     335      340309 :     rSalLayout.DrawBase().X() = nOldX;
     336             : 
     337      340309 :     if( bTextLines )
     338             :         ImplDrawTextLines( rSalLayout,
     339             :             maFont.GetStrikeout(), maFont.GetUnderline(), maFont.GetOverline(),
     340       12378 :             maFont.IsWordLineMode(), ImplIsUnderlineAbove( maFont ) );
     341             : 
     342             : 
     343             :     // emphasis marks
     344      340309 :     if( maFont.GetEmphasisMark() & EMPHASISMARK_STYLE )
     345       10674 :         ImplDrawEmphasisMarks( rSalLayout );
     346             : 
     347      340309 :     return true;
     348             : }
     349             : 
     350        5025 : void OutputDevice::ImplDrawSpecialText( SalLayout& rSalLayout )
     351             : {
     352        5025 :     Color       aOldColor           = GetTextColor();
     353        5025 :     Color       aOldTextLineColor   = GetTextLineColor();
     354        5025 :     Color       aOldOverlineColor   = GetOverlineColor();
     355        5025 :     FontRelief  eRelief             = maFont.GetRelief();
     356             : 
     357        5025 :     Point aOrigPos = rSalLayout.DrawBase();
     358        5025 :     if ( eRelief != RELIEF_NONE )
     359             :     {
     360        4848 :         Color   aReliefColor( COL_LIGHTGRAY );
     361        4848 :         Color   aTextColor( aOldColor );
     362             : 
     363        4848 :         Color   aTextLineColor( aOldTextLineColor );
     364        4848 :         Color   aOverlineColor( aOldOverlineColor );
     365             : 
     366             :         // we don't have a automatic color, so black is always drawn on white
     367        4848 :         if ( aTextColor.GetColor() == COL_BLACK )
     368        1872 :             aTextColor = Color( COL_WHITE );
     369        4848 :         if ( aTextLineColor.GetColor() == COL_BLACK )
     370        1371 :             aTextLineColor = Color( COL_WHITE );
     371        4848 :         if ( aOverlineColor.GetColor() == COL_BLACK )
     372        1371 :             aOverlineColor = Color( COL_WHITE );
     373             : 
     374             :         // relief-color is black for white text, in all other cases
     375             :         // we set this to LightGray
     376        4848 :         if ( aTextColor.GetColor() == COL_WHITE )
     377        1892 :             aReliefColor = Color( COL_BLACK );
     378        4848 :         SetTextLineColor( aReliefColor );
     379        4848 :         SetOverlineColor( aReliefColor );
     380        4848 :         SetTextColor( aReliefColor );
     381        4848 :         ImplInitTextColor();
     382             : 
     383             :         // calculate offset - for high resolution printers the offset
     384             :         // should be greater so that the effect is visible
     385        4848 :         long nOff = 1;
     386        4848 :         nOff += mnDPIX/300;
     387             : 
     388        4848 :         if ( eRelief == RELIEF_ENGRAVED )
     389        2617 :             nOff = -nOff;
     390        4848 :         rSalLayout.DrawOffset() += Point( nOff, nOff);
     391        4848 :         ImplDrawTextDirect( rSalLayout, mbTextLines );
     392        4848 :         rSalLayout.DrawOffset() -= Point( nOff, nOff);
     393             : 
     394        4848 :         SetTextLineColor( aTextLineColor );
     395        4848 :         SetOverlineColor( aOverlineColor );
     396        4848 :         SetTextColor( aTextColor );
     397        4848 :         ImplInitTextColor();
     398        4848 :         ImplDrawTextDirect( rSalLayout, mbTextLines );
     399             : 
     400        4848 :         SetTextLineColor( aOldTextLineColor );
     401        4848 :         SetOverlineColor( aOldOverlineColor );
     402             : 
     403        4848 :         if ( aTextColor != aOldColor )
     404             :         {
     405        1872 :             SetTextColor( aOldColor );
     406        1872 :             ImplInitTextColor();
     407             :         }
     408             :     }
     409             :     else
     410             :     {
     411         177 :         if ( maFont.IsShadow() )
     412             :         {
     413         155 :             long nOff = 1 + ((mpFontEntry->mnLineHeight-24)/24);
     414         155 :             if ( maFont.IsOutline() )
     415         110 :                 nOff++;
     416         155 :             SetTextLineColor();
     417         155 :             SetOverlineColor();
     418         310 :             if ( (GetTextColor().GetColor() == COL_BLACK)
     419         155 :             ||   (GetTextColor().GetLuminance() < 8) )
     420         155 :                 SetTextColor( Color( COL_LIGHTGRAY ) );
     421             :             else
     422           0 :                 SetTextColor( Color( COL_BLACK ) );
     423         155 :             ImplInitTextColor();
     424         155 :             rSalLayout.DrawBase() += Point( nOff, nOff );
     425         155 :             ImplDrawTextDirect( rSalLayout, mbTextLines );
     426         155 :             rSalLayout.DrawBase() -= Point( nOff, nOff );
     427         155 :             SetTextColor( aOldColor );
     428         155 :             SetTextLineColor( aOldTextLineColor );
     429         155 :             SetOverlineColor( aOldOverlineColor );
     430         155 :             ImplInitTextColor();
     431             : 
     432         155 :             if ( !maFont.IsOutline() )
     433          45 :                 ImplDrawTextDirect( rSalLayout, mbTextLines );
     434             :         }
     435             : 
     436         177 :         if ( maFont.IsOutline() )
     437             :         {
     438         132 :             if(! ImplDrawTextDirect( rSalLayout, mbTextLines, DRAWTEXT_F_OUTLINE))
     439             :             {
     440         132 :                 rSalLayout.DrawBase() = aOrigPos + Point(-1,-1);
     441         132 :                 ImplDrawTextDirect( rSalLayout, mbTextLines );
     442         132 :                 rSalLayout.DrawBase() = aOrigPos + Point(+1,+1);
     443         132 :                 ImplDrawTextDirect( rSalLayout, mbTextLines );
     444         132 :                 rSalLayout.DrawBase() = aOrigPos + Point(-1,+0);
     445         132 :                 ImplDrawTextDirect( rSalLayout, mbTextLines );
     446         132 :                 rSalLayout.DrawBase() = aOrigPos + Point(-1,+1);
     447         132 :                 ImplDrawTextDirect( rSalLayout, mbTextLines );
     448         132 :                 rSalLayout.DrawBase() = aOrigPos + Point(+0,+1);
     449         132 :                 ImplDrawTextDirect( rSalLayout, mbTextLines );
     450         132 :                 rSalLayout.DrawBase() = aOrigPos + Point(+0,-1);
     451         132 :                 ImplDrawTextDirect( rSalLayout, mbTextLines );
     452         132 :                 rSalLayout.DrawBase() = aOrigPos + Point(+1,-1);
     453         132 :                 ImplDrawTextDirect( rSalLayout, mbTextLines );
     454         132 :                 rSalLayout.DrawBase() = aOrigPos + Point(+1,+0);
     455         132 :                 ImplDrawTextDirect( rSalLayout, mbTextLines );
     456         132 :                 rSalLayout.DrawBase() = aOrigPos;
     457             : 
     458         132 :                 SetTextColor( Color( COL_WHITE ) );
     459         132 :                 SetTextLineColor( Color( COL_WHITE ) );
     460         132 :                 SetOverlineColor( Color( COL_WHITE ) );
     461         132 :                 ImplInitTextColor();
     462         132 :                 ImplDrawTextDirect( rSalLayout, mbTextLines );
     463         132 :                 SetTextColor( aOldColor );
     464         132 :                 SetTextLineColor( aOldTextLineColor );
     465         132 :                 SetOverlineColor( aOldOverlineColor );
     466         132 :                 ImplInitTextColor();
     467             :             }
     468             :         }
     469             :     }
     470        5025 : }
     471             : 
     472      337526 : void OutputDevice::ImplDrawText( SalLayout& rSalLayout )
     473             : {
     474             : 
     475      337526 :     if( mbInitClipRegion )
     476       17266 :         InitClipRegion();
     477      337526 :     if( mbOutputClipped )
     478      340802 :         return;
     479      334250 :     if( mbInitTextColor )
     480       82403 :         ImplInitTextColor();
     481             : 
     482      334250 :     rSalLayout.DrawBase() += Point( mnTextOffX, mnTextOffY );
     483             : 
     484      334250 :     if( IsTextFillColor() )
     485       21080 :         ImplDrawTextBackground( rSalLayout );
     486             : 
     487      334250 :     if( mbTextSpecial )
     488        5025 :         ImplDrawSpecialText( rSalLayout );
     489             :     else
     490      329225 :         ImplDrawTextDirect( rSalLayout, mbTextLines );
     491             : }
     492             : 
     493       22758 : long OutputDevice::ImplGetTextLines( ImplMultiTextLineInfo& rLineInfo,
     494             :                                      long nWidth, const OUString& rStr,
     495             :                                      sal_uInt16 nStyle, const ::vcl::ITextLayout& _rLayout )
     496             : {
     497             :     DBG_ASSERTWARNING( nWidth >= 0, "ImplGetTextLines: nWidth <= 0!" );
     498             : 
     499       22758 :     if ( nWidth <= 0 )
     500           0 :         nWidth = 1;
     501             : 
     502       22758 :     long nMaxLineWidth  = 0;
     503       22758 :     rLineInfo.Clear();
     504       22758 :     if ( !rStr.isEmpty() && (nWidth > 0) )
     505             :     {
     506       22503 :         css::uno::Reference < css::i18n::XBreakIterator > xBI;
     507             :         // get service provider
     508       45006 :         css::uno::Reference< css::uno::XComponentContext > xContext( comphelper::getProcessComponentContext() );
     509             : 
     510       22503 :         bool bHyphenate = (nStyle & TEXT_DRAW_WORDBREAK_HYPHENATION)
     511       22503 :             == TEXT_DRAW_WORDBREAK_HYPHENATION;
     512       45006 :         css::uno::Reference< css::linguistic2::XHyphenator > xHyph;
     513       22503 :         if ( bHyphenate )
     514             :         {
     515           0 :             css::uno::Reference< css::linguistic2::XLinguServiceManager2> xLinguMgr = css::linguistic2::LinguServiceManager::create(xContext);
     516           0 :             xHyph = xLinguMgr->getHyphenator();
     517             :         }
     518             : 
     519       22503 :         sal_Int32 nPos = 0;
     520       22503 :         sal_Int32 nLen = rStr.getLength();
     521       94441 :         while ( nPos < nLen )
     522             :         {
     523       49435 :             sal_Int32 nBreakPos = nPos;
     524             : 
     525     2346993 :             while ( ( nBreakPos < nLen ) && ( rStr[ nBreakPos ] != '\r' ) && ( rStr[ nBreakPos ] != '\n' ) )
     526     2248123 :                 nBreakPos++;
     527             : 
     528       49435 :             long nLineWidth = _rLayout.GetTextWidth( rStr, nPos, nBreakPos-nPos );
     529       49435 :             if ( ( nLineWidth > nWidth ) && ( nStyle & TEXT_DRAW_WORDBREAK ) )
     530             :             {
     531       26932 :                 if ( !xBI.is() )
     532       13468 :                     xBI = vcl::unohelper::CreateBreakIterator();
     533             : 
     534       26932 :                 if ( xBI.is() )
     535             :                 {
     536       26932 :                     const css::lang::Locale& rDefLocale(Application::GetSettings().GetUILanguageTag().getLocale());
     537       26932 :                     sal_Int32 nSoftBreak = _rLayout.GetTextBreak( rStr, nWidth, nPos, nBreakPos - nPos );
     538       26932 :                     if (nSoftBreak == -1)
     539             :                     {
     540           0 :                         nSoftBreak = nPos;
     541             :                     }
     542             :                     DBG_ASSERT( nSoftBreak < nBreakPos, "Break?!" );
     543       26932 :                     css::i18n::LineBreakHyphenationOptions aHyphOptions( xHyph, css::uno::Sequence <css::beans::PropertyValue>(), 1 );
     544       53864 :                     css::i18n::LineBreakUserOptions aUserOptions;
     545       53864 :                     css::i18n::LineBreakResults aLBR = xBI->getLineBreak( rStr, nSoftBreak, rDefLocale, nPos, aHyphOptions, aUserOptions );
     546       26932 :                     nBreakPos = aLBR.breakIndex;
     547       26932 :                     if ( nBreakPos <= nPos )
     548           0 :                         nBreakPos = nSoftBreak;
     549       26932 :                     if ( bHyphenate )
     550             :                     {
     551             :                         // Whether hyphen or not: Put the word after the hyphen through
     552             :                         // word boundary.
     553             : 
     554             :                         // nMaxBreakPos the last char that fits into the line
     555             :                         // nBreakPos is the word's start
     556             : 
     557             :                         // We run into a problem if the doc is so narrow, that a word
     558             :                         // is broken into more than two lines ...
     559           0 :                         if ( xHyph.is() )
     560             :                         {
     561           0 :                             sal_Unicode cAlternateReplChar = 0;
     562           0 :                             css::i18n::Boundary aBoundary = xBI->getWordBoundary( rStr, nBreakPos, rDefLocale, css::i18n::WordType::DICTIONARY_WORD, sal_True );
     563           0 :                             sal_Int32 nWordStart = nPos;
     564           0 :                             sal_Int32 nWordEnd = aBoundary.endPos;
     565             :                             DBG_ASSERT( nWordEnd > nWordStart, "ImpBreakLine: Start >= End?" );
     566             : 
     567           0 :                             sal_Int32 nWordLen = nWordEnd - nWordStart;
     568           0 :                             if ( ( nWordEnd >= nSoftBreak ) && ( nWordLen > 3 ) )
     569             :                             {
     570             :                                 // #104415# May happen, because getLineBreak may differ from getWordBoudary with DICTIONARY_WORD
     571             :                                 // DBG_ASSERT( nWordEnd >= nMaxBreakPos, "Hyph: Break?" );
     572           0 :                                 OUString aWord = rStr.copy( nWordStart, nWordLen );
     573           0 :                                 sal_Int32 nMinTrail = nWordEnd-nSoftBreak+1;  //+1: Before the "broken off" char
     574           0 :                                 css::uno::Reference< css::linguistic2::XHyphenatedWord > xHyphWord;
     575           0 :                                 if (xHyph.is())
     576           0 :                                     xHyphWord = xHyph->hyphenate( aWord, rDefLocale, aWord.getLength() - nMinTrail, css::uno::Sequence< css::beans::PropertyValue >() );
     577           0 :                                 if (xHyphWord.is())
     578             :                                 {
     579           0 :                                     bool bAlternate = xHyphWord->isAlternativeSpelling();
     580           0 :                                     sal_Int32 _nWordLen = 1 + xHyphWord->getHyphenPos();
     581             : 
     582           0 :                                     if ( ( _nWordLen >= 2 ) && ( (nWordStart+_nWordLen) >= ( 2 ) ) )
     583             :                                     {
     584           0 :                                         if ( !bAlternate )
     585             :                                         {
     586           0 :                                             nBreakPos = nWordStart + _nWordLen;
     587             :                                         }
     588             :                                         else
     589             :                                         {
     590           0 :                                             OUString aAlt( xHyphWord->getHyphenatedWord() );
     591             : 
     592             :                                             // We can have two cases:
     593             :                                             // 1) "packen" turns into "pak-ken"
     594             :                                             // 2) "Schiffahrt" turns into "Schiff-fahrt"
     595             : 
     596             :                                             // In case 1 we need to replace a char
     597             :                                             // In case 2 we add a char
     598             : 
     599             :                                             // Correct recognition is made harder by words such as
     600             :                                             // "Schiffahrtsbrennesseln", as the Hyphenator splits all
     601             :                                             // positions of the word and comes up with "Schifffahrtsbrennnesseln"
     602             :                                             // Thus, we cannot infer the aWord from the AlternativWord's
     603             :                                             // index.
     604             :                                             // TODO: The whole junk will be made easier by a function in
     605             :                                             // the Hyphenator, as soon as AMA adds it.
     606           0 :                                             sal_Int32 nAltStart = _nWordLen - 1;
     607           0 :                                             sal_Int32 nTxtStart = nAltStart - (aAlt.getLength() - aWord.getLength());
     608           0 :                                             sal_Int32 nTxtEnd = nTxtStart;
     609           0 :                                             sal_Int32 nAltEnd = nAltStart;
     610             : 
     611             :                                             // The area between nStart and nEnd is the difference
     612             :                                             // between AlternativString and OriginalString
     613           0 :                                             while( nTxtEnd < aWord.getLength() && nAltEnd < aAlt.getLength() &&
     614           0 :                                                    aWord[nTxtEnd] != aAlt[nAltEnd] )
     615             :                                             {
     616           0 :                                                 ++nTxtEnd;
     617           0 :                                                 ++nAltEnd;
     618             :                                             }
     619             : 
     620             :                                             // If a char was added, we notice it now:
     621           0 :                                             if( nAltEnd > nTxtEnd && nAltStart == nAltEnd &&
     622           0 :                                                 aWord[ nTxtEnd ] == aAlt[nAltEnd] )
     623             :                                             {
     624           0 :                                                 ++nAltEnd;
     625           0 :                                                 ++nTxtStart;
     626           0 :                                                 ++nTxtEnd;
     627             :                                             }
     628             : 
     629             :                                             DBG_ASSERT( ( nAltEnd - nAltStart ) == 1, "Alternate: Wrong assumption!" );
     630             : 
     631           0 :                                             if ( nTxtEnd > nTxtStart )
     632           0 :                                                 cAlternateReplChar = aAlt[ nAltStart ];
     633             : 
     634           0 :                                             nBreakPos = nWordStart + nTxtStart;
     635           0 :                                             if ( cAlternateReplChar )
     636           0 :                                                 nBreakPos++;
     637             :                                         }
     638             :                                     }
     639           0 :                                 }
     640             :                             }
     641             :                         }
     642             :                     }
     643       53864 :                     nLineWidth = _rLayout.GetTextWidth( rStr, nPos, nBreakPos-nPos );
     644             :                 }
     645             :                 else
     646             :                 {
     647             :                     // fallback to something really simple
     648           0 :                     sal_Int32 nSpacePos = rStr.getLength();
     649           0 :                     long nW = 0;
     650           0 :                     do
     651             :                     {
     652           0 :                         nSpacePos = rStr.lastIndexOf( ' ', nSpacePos );
     653           0 :                         if( nSpacePos != -1 )
     654             :                         {
     655           0 :                             if( nSpacePos > nPos )
     656           0 :                                 nSpacePos--;
     657           0 :                             nW = _rLayout.GetTextWidth( rStr, nPos, nSpacePos-nPos );
     658             :                         }
     659             :                     } while( nW > nWidth );
     660             : 
     661           0 :                     if( nSpacePos != -1 )
     662             :                     {
     663           0 :                         nBreakPos = nSpacePos;
     664           0 :                         nLineWidth = _rLayout.GetTextWidth( rStr, nPos, nBreakPos-nPos );
     665           0 :                         if( nBreakPos < rStr.getLength()-1 )
     666           0 :                             nBreakPos++;
     667             :                     }
     668             :                 }
     669             :             }
     670             : 
     671       49435 :             if ( nLineWidth > nMaxLineWidth )
     672       35967 :                 nMaxLineWidth = nLineWidth;
     673             : 
     674       49435 :             rLineInfo.AddLine( new ImplTextLineInfo( nLineWidth, nPos, nBreakPos-nPos ) );
     675             : 
     676       49435 :             if ( nBreakPos == nPos )
     677           0 :                 nBreakPos++;
     678       49435 :             nPos = nBreakPos;
     679             : 
     680       49435 :             if ( nPos < nLen && ( ( rStr[ nPos ] == '\r' ) || ( rStr[ nPos ] == '\n' ) ) )
     681             :             {
     682           0 :                 nPos++;
     683             :                 // CR/LF?
     684           0 :                 if ( ( nPos < nLen ) && ( rStr[ nPos ] == '\n' ) && ( rStr[ nPos-1 ] == '\r' ) )
     685           0 :                     nPos++;
     686             :             }
     687       22503 :         }
     688             :     }
     689             : #ifdef DBG_UTIL
     690             :     for ( sal_uInt16 nL = 0; nL < rLineInfo.Count(); nL++ )
     691             :     {
     692             :         ImplTextLineInfo* pLine = rLineInfo.GetLine( nL );
     693             :         OUString aLine = rStr.copy( pLine->GetIndex(), pLine->GetLen() );
     694             :         DBG_ASSERT( aLine.indexOf( '\r' ) == -1, "ImplGetTextLines - Found CR!" );
     695             :         DBG_ASSERT( aLine.indexOf( '\n' ) == -1, "ImplGetTextLines - Found LF!" );
     696             :     }
     697             : #endif
     698             : 
     699       22758 :     return nMaxLineWidth;
     700             : }
     701             : 
     702     1024250 : void OutputDevice::SetTextColor( const Color& rColor )
     703             : {
     704             : 
     705     1024250 :     Color aColor( rColor );
     706             : 
     707     1024250 :     if ( mnDrawMode & ( DRAWMODE_BLACKTEXT | DRAWMODE_WHITETEXT |
     708             :                         DRAWMODE_GRAYTEXT | DRAWMODE_GHOSTEDTEXT |
     709             :                         DRAWMODE_SETTINGSTEXT ) )
     710             :     {
     711           0 :         if ( mnDrawMode & DRAWMODE_BLACKTEXT )
     712           0 :             aColor = Color( COL_BLACK );
     713           0 :         else if ( mnDrawMode & DRAWMODE_WHITETEXT )
     714           0 :             aColor = Color( COL_WHITE );
     715           0 :         else if ( mnDrawMode & DRAWMODE_GRAYTEXT )
     716             :         {
     717           0 :             const sal_uInt8 cLum = aColor.GetLuminance();
     718           0 :             aColor = Color( cLum, cLum, cLum );
     719             :         }
     720           0 :         else if ( mnDrawMode & DRAWMODE_SETTINGSTEXT )
     721           0 :             aColor = GetSettings().GetStyleSettings().GetFontColor();
     722             : 
     723           0 :         if ( mnDrawMode & DRAWMODE_GHOSTEDTEXT )
     724             :         {
     725           0 :             aColor = Color( (aColor.GetRed() >> 1) | 0x80,
     726           0 :                             (aColor.GetGreen() >> 1) | 0x80,
     727           0 :                             (aColor.GetBlue() >> 1) | 0x80 );
     728             :         }
     729             :     }
     730             : 
     731     1024250 :     if ( mpMetaFile )
     732       84993 :         mpMetaFile->AddAction( new MetaTextColorAction( aColor ) );
     733             : 
     734     1024250 :     if ( maTextColor != aColor )
     735             :     {
     736       33157 :         maTextColor = aColor;
     737       33157 :         mbInitTextColor = true;
     738             :     }
     739             : 
     740     1024250 :     if( mpAlphaVDev )
     741       19850 :         mpAlphaVDev->SetTextColor( COL_BLACK );
     742     1024250 : }
     743             : 
     744      275522 : void OutputDevice::SetTextFillColor()
     745             : {
     746             : 
     747      275522 :     if ( mpMetaFile )
     748        7159 :         mpMetaFile->AddAction( new MetaTextFillColorAction( Color(), false ) );
     749             : 
     750      275522 :     if ( maFont.GetColor() != Color( COL_TRANSPARENT ) ) {
     751        3908 :         maFont.SetFillColor( Color( COL_TRANSPARENT ) );
     752             :     }
     753      275522 :     if ( !maFont.IsTransparent() )
     754          18 :         maFont.SetTransparent( true );
     755             : 
     756      275522 :     if( mpAlphaVDev )
     757       20215 :         mpAlphaVDev->SetTextFillColor();
     758      275522 : }
     759             : 
     760       37015 : void OutputDevice::SetTextFillColor( const Color& rColor )
     761             : {
     762             : 
     763       37015 :     Color aColor( rColor );
     764       37015 :     bool bTransFill = ImplIsColorTransparent( aColor );
     765             : 
     766       37015 :     if ( !bTransFill )
     767             :     {
     768       27121 :         if ( mnDrawMode & ( DRAWMODE_BLACKFILL | DRAWMODE_WHITEFILL |
     769             :                             DRAWMODE_GRAYFILL | DRAWMODE_NOFILL |
     770             :                             DRAWMODE_GHOSTEDFILL | DRAWMODE_SETTINGSFILL ) )
     771             :         {
     772           0 :             if ( mnDrawMode & DRAWMODE_BLACKFILL )
     773           0 :                 aColor = Color( COL_BLACK );
     774           0 :             else if ( mnDrawMode & DRAWMODE_WHITEFILL )
     775           0 :                 aColor = Color( COL_WHITE );
     776           0 :             else if ( mnDrawMode & DRAWMODE_GRAYFILL )
     777             :             {
     778           0 :                 const sal_uInt8 cLum = aColor.GetLuminance();
     779           0 :                 aColor = Color( cLum, cLum, cLum );
     780             :             }
     781           0 :             else if( mnDrawMode & DRAWMODE_SETTINGSFILL )
     782           0 :                 aColor = GetSettings().GetStyleSettings().GetWindowColor();
     783           0 :             else if ( mnDrawMode & DRAWMODE_NOFILL )
     784             :             {
     785           0 :                 aColor = Color( COL_TRANSPARENT );
     786           0 :                 bTransFill = true;
     787             :             }
     788             : 
     789           0 :             if ( !bTransFill && (mnDrawMode & DRAWMODE_GHOSTEDFILL) )
     790             :             {
     791           0 :                 aColor = Color( (aColor.GetRed() >> 1) | 0x80,
     792           0 :                                 (aColor.GetGreen() >> 1) | 0x80,
     793           0 :                                 (aColor.GetBlue() >> 1) | 0x80 );
     794             :             }
     795             :         }
     796             :     }
     797             : 
     798       37015 :     if ( mpMetaFile )
     799        1563 :         mpMetaFile->AddAction( new MetaTextFillColorAction( aColor, true ) );
     800             : 
     801       37015 :     if ( maFont.GetFillColor() != aColor )
     802       17709 :         maFont.SetFillColor( aColor );
     803       37015 :     if ( maFont.IsTransparent() != bTransFill )
     804       17657 :         maFont.SetTransparent( bTransFill );
     805             : 
     806       37015 :     if( mpAlphaVDev )
     807        1625 :         mpAlphaVDev->SetTextFillColor( COL_BLACK );
     808       37015 : }
     809             : 
     810       46419 : Color OutputDevice::GetTextFillColor() const
     811             : {
     812       46419 :     if ( maFont.IsTransparent() )
     813       24890 :         return Color( COL_TRANSPARENT );
     814             :     else
     815       21529 :         return maFont.GetFillColor();
     816             : }
     817             : 
     818      106788 : void OutputDevice::SetTextAlign( TextAlign eAlign )
     819             : {
     820             : 
     821      106788 :     if ( mpMetaFile )
     822        7015 :         mpMetaFile->AddAction( new MetaTextAlignAction( eAlign ) );
     823             : 
     824      106788 :     if ( maFont.GetAlign() != eAlign )
     825             :     {
     826        1872 :         maFont.SetAlign( eAlign );
     827        1872 :         mbNewFont = true;
     828             :     }
     829             : 
     830      106788 :     if( mpAlphaVDev )
     831       20163 :         mpAlphaVDev->SetTextAlign( eAlign );
     832      106788 : }
     833             : 
     834      288108 : void OutputDevice::DrawText( const Point& rStartPt, const OUString& rStr,
     835             :                              sal_Int32 nIndex, sal_Int32 nLen,
     836             :                              MetricVector* pVector, OUString* pDisplayText
     837             :                              )
     838             : {
     839             : 
     840             : 
     841      288108 :     if(nLen == 0x0FFFF)
     842             :     {
     843             :         SAL_INFO("sal.rtl.xub",
     844             :                  "GetTextOutlines Suspicious arguments nLen:" << nLen);
     845             :     }
     846      288108 :     if( (nLen < 0) || (nIndex + nLen >= rStr.getLength()))
     847             :     {
     848      274578 :         nLen = rStr.getLength() - nIndex;
     849             :     }
     850             : 
     851             : 
     852      288108 :     if( mpOutDevData && mpOutDevData->mpRecordLayout )
     853             :     {
     854        4920 :         pVector = &mpOutDevData->mpRecordLayout->m_aUnicodeBoundRects;
     855        4920 :         pDisplayText = &mpOutDevData->mpRecordLayout->m_aDisplayText;
     856             :     }
     857             : 
     858             : #if OSL_DEBUG_LEVEL > 2
     859             :     fprintf( stderr, "   OutputDevice::DrawText(\"%s\")\n",
     860             :          OUStringToOString( rStr, RTL_TEXTENCODING_UTF8 ).getStr() );
     861             : #endif
     862             : 
     863      288108 :     if ( mpMetaFile )
     864        4325 :         mpMetaFile->AddAction( new MetaTextAction( rStartPt, rStr, nIndex, nLen ) );
     865      288108 :     if( pVector )
     866             :     {
     867        4974 :         vcl::Region aClip( GetClipRegion() );
     868        4974 :         if( meOutDevType == OUTDEV_WINDOW )
     869        4974 :             aClip.Intersect( Rectangle( Point(), GetOutputSize() ) );
     870        4974 :         if( mpOutDevData && mpOutDevData->mpRecordLayout )
     871             :         {
     872        4920 :             mpOutDevData->mpRecordLayout->m_aLineIndices.push_back( mpOutDevData->mpRecordLayout->m_aDisplayText.getLength() );
     873        4920 :             aClip.Intersect( mpOutDevData->maRecordRect );
     874             :         }
     875        4974 :         if( ! aClip.IsNull() )
     876             :         {
     877        4974 :             MetricVector aTmp;
     878        4974 :             GetGlyphBoundRects( rStartPt, rStr, nIndex, nLen, nIndex, aTmp );
     879             : 
     880        4974 :             bool bInserted = false;
     881       30888 :             for( MetricVector::const_iterator it = aTmp.begin(); it != aTmp.end(); ++it, nIndex++ )
     882             :             {
     883       25914 :                 bool bAppend = false;
     884             : 
     885       25914 :                 if( aClip.IsOver( *it ) )
     886        7778 :                     bAppend = true;
     887       18136 :                 else if( rStr[ nIndex ] == ' ' && bInserted )
     888             :                 {
     889        1242 :                     MetricVector::const_iterator next = it;
     890        1242 :                     ++next;
     891        1242 :                     if( next != aTmp.end() && aClip.IsOver( *next ) )
     892        1242 :                         bAppend = true;
     893             :                 }
     894             : 
     895       25914 :                 if( bAppend )
     896             :                 {
     897        9020 :                     pVector->push_back( *it );
     898        9020 :                     if( pDisplayText )
     899        9020 :                         *pDisplayText += OUString(rStr[ nIndex ]);
     900        9020 :                     bInserted = true;
     901             :                 }
     902        4974 :             }
     903             :         }
     904             :         else
     905             :         {
     906           0 :             GetGlyphBoundRects( rStartPt, rStr, nIndex, nLen, nIndex, *pVector );
     907           0 :             if( pDisplayText )
     908           0 :                 *pDisplayText += rStr.copy( nIndex, nLen );
     909        4974 :         }
     910             :     }
     911             : 
     912      288108 :     if ( !IsDeviceOutputNecessary() || pVector )
     913      298400 :         return;
     914             : 
     915      277816 :     SalLayout* pSalLayout = ImplLayout(rStr, nIndex, nLen, rStartPt, 0, NULL);
     916      277816 :     if( pSalLayout )
     917             :     {
     918      277816 :         ImplDrawText( *pSalLayout );
     919      277816 :         pSalLayout->Release();
     920             :     }
     921             : 
     922      277816 :     if( mpAlphaVDev )
     923        2034 :         mpAlphaVDev->DrawText( rStartPt, rStr, nIndex, nLen, pVector, pDisplayText );
     924             : }
     925             : 
     926     1184373 : long OutputDevice::GetTextWidth( const OUString& rStr, sal_Int32 nIndex, sal_Int32 nLen ) const
     927             : {
     928             : 
     929     1184373 :     long nWidth = GetTextArray( rStr, NULL, nIndex, nLen );
     930             : 
     931     1184373 :     return nWidth;
     932             : }
     933             : 
     934     1106341 : long OutputDevice::GetTextHeight() const
     935             : {
     936             : 
     937     1106341 :     if( mbNewFont )
     938      454490 :         if( !ImplNewFont() )
     939           0 :             return 0;
     940     1106341 :     if( mbInitFont )
     941      450067 :         if( !ImplNewFont() )
     942           0 :             return 0;
     943             : 
     944     1106341 :     long nHeight = mpFontEntry->mnLineHeight + mnEmphasisAscent + mnEmphasisDescent;
     945             : 
     946     1106341 :     if ( mbMap )
     947      663923 :         nHeight = ImplDevicePixelToLogicHeight( nHeight );
     948             : 
     949     1106341 :     return nHeight;
     950             : }
     951             : 
     952         712 : float OutputDevice::approximate_char_width() const
     953             : {
     954         712 :     return GetTextWidth("aemnnxEM") / 8.0;
     955             : }
     956             : 
     957       60379 : void OutputDevice::DrawTextArray( const Point& rStartPt, const OUString& rStr,
     958             :                                   const long* pDXAry,
     959             :                                   sal_Int32 nIndex, sal_Int32 nLen, int flags )
     960             : {
     961       60379 :     if(nLen == 0x0FFFF)
     962             :     {
     963             :         SAL_INFO("sal.rtl.xub",
     964             :                  "DrawTextArray Suspicious arguments nLen:" << nLen);
     965             :     }
     966       60379 :     if( nLen < 0 || nIndex + nLen >= rStr.getLength() )
     967             :     {
     968       28693 :         nLen = rStr.getLength() - nIndex;
     969             :     }
     970       60379 :     if ( mpMetaFile )
     971        2263 :         mpMetaFile->AddAction( new MetaTextArrayAction( rStartPt, rStr, pDXAry, nIndex, nLen ) );
     972             : 
     973       60379 :     if ( !IsDeviceOutputNecessary() )
     974        2032 :         return;
     975       58347 :     if( !mpGraphics && !AcquireGraphics() )
     976           0 :         return;
     977       58347 :     if( mbInitClipRegion )
     978       11222 :         InitClipRegion();
     979       58347 :     if( mbOutputClipped )
     980         487 :         return;
     981             : 
     982       57860 :     SalLayout* pSalLayout = ImplLayout(rStr, nIndex, nLen, rStartPt, 0, pDXAry, flags);
     983       57860 :     if( pSalLayout )
     984             :     {
     985       57860 :         ImplDrawText( *pSalLayout );
     986       57860 :         pSalLayout->Release();
     987             :     }
     988             : 
     989       57860 :     if( mpAlphaVDev )
     990         231 :         mpAlphaVDev->DrawTextArray( rStartPt, rStr, pDXAry, nIndex, nLen, flags );
     991             : }
     992             : 
     993     1490590 : long OutputDevice::GetTextArray( const OUString& rStr, long* pDXAry,
     994             :                                  sal_Int32 nIndex, sal_Int32 nLen ) const
     995             : {
     996     1490590 :     if(nLen == 0x0FFFF)
     997             :     {
     998             :         SAL_INFO("sal.rtl.xub",
     999             :                  "GetTextArray Suspicious arguments nLen:" << nLen);
    1000             :     }
    1001             : 
    1002     1490590 :     if( nIndex >= rStr.getLength() )
    1003      243302 :         return 0;
    1004             : 
    1005     1247288 :     if( nLen < 0 || nIndex + nLen >= rStr.getLength() )
    1006             :     {
    1007     1037756 :         nLen = rStr.getLength() - nIndex;
    1008             :     }
    1009             :     // do layout
    1010     1247288 :     SalLayout* pSalLayout = ImplLayout( rStr, nIndex, nLen );
    1011     1247288 :     if( !pSalLayout )
    1012           0 :         return 0;
    1013             : #if VCL_FLOAT_DEVICE_PIXEL
    1014             :     DeviceCoordinate* pDXPixelArray = NULL;
    1015             :     if(pDXAry)
    1016             :     {
    1017             :         pDXPixelArray = (DeviceCoordinate*)alloca(nLen * sizeof(DeviceCoordinate));
    1018             :     }
    1019             :     DeviceCoordinate nWidth = pSalLayout->FillDXArray( pDXPixelArray );
    1020             :     int nWidthFactor = pSalLayout->GetUnitsPerPixel();
    1021             :     pSalLayout->Release();
    1022             : 
    1023             :     // convert virtual char widths to virtual absolute positions
    1024             :     if( pDXPixelArray )
    1025             :     {
    1026             :         for( int i = 1; i < nLen; ++i )
    1027             :         {
    1028             :             pDXPixelArray[ i ] += pDXPixelArray[ i-1 ];
    1029             :         }
    1030             :     }
    1031             :     if( mbMap )
    1032             :     {
    1033             :         if( pDXPixelArray )
    1034             :         {
    1035             :             for( int i = 0; i < nLen; ++i )
    1036             :             {
    1037             :                 pDXPixelArray[i] = ImplDevicePixelToLogicWidth( pDXPixelArray[i] );
    1038             :             }
    1039             :         }
    1040             :         nWidth = ImplDevicePixelToLogicWidth( nWidth );
    1041             :     }
    1042             :     if( nWidthFactor > 1 )
    1043             :     {
    1044             :         if( pDXPixelArray )
    1045             :         {
    1046             :             for( int i = 0; i < nLen; ++i )
    1047             :             {
    1048             :                 pDXPixelArray[i] /= nWidthFactor;
    1049             :             }
    1050             :         }
    1051             :         nWidth /= nWidthFactor;
    1052             :     }
    1053             :     if(pDXAry)
    1054             :     {
    1055             :         for( int i = 0; i < nLen; ++i )
    1056             :         {
    1057             :             pDXAry[i] = basegfx::fround(pDXPixelArray[i]);
    1058             :         }
    1059             :     }
    1060             :     return basegfx::fround(nWidth);
    1061             : 
    1062             : #else /* ! VCL_FLOAT_DEVICE_PIXEL */
    1063             : 
    1064     1247288 :     long nWidth = pSalLayout->FillDXArray( pDXAry );
    1065     1247288 :     int nWidthFactor = pSalLayout->GetUnitsPerPixel();
    1066     1247288 :     pSalLayout->Release();
    1067             : 
    1068             :     // convert virtual char widths to virtual absolute positions
    1069     1247288 :     if( pDXAry )
    1070     6167275 :         for( int i = 1; i < nLen; ++i )
    1071     5872368 :             pDXAry[ i ] += pDXAry[ i-1 ];
    1072             : 
    1073             :     // convert from font units to logical units
    1074     1247288 :     if( mbMap )
    1075             :     {
    1076      513290 :         if( pDXAry )
    1077     6458926 :             for( int i = 0; i < nLen; ++i )
    1078     6165174 :                 pDXAry[i] = ImplDevicePixelToLogicWidth( pDXAry[i] );
    1079      513290 :         nWidth = ImplDevicePixelToLogicWidth( nWidth );
    1080             :     }
    1081             : 
    1082     1247288 :     if( nWidthFactor > 1 )
    1083             :     {
    1084          90 :         if( pDXAry )
    1085        4186 :             for( int i = 0; i < nLen; ++i )
    1086        4100 :                 pDXAry[i] /= nWidthFactor;
    1087          90 :         nWidth /= nWidthFactor;
    1088             :     }
    1089     1247288 :     return nWidth;
    1090             : #endif /* VCL_FLOAT_DEVICE_PIXEL */
    1091             : }
    1092             : 
    1093       50572 : bool OutputDevice::GetCaretPositions( const OUString& rStr, long* pCaretXArray,
    1094             :                                       sal_Int32 nIndex, sal_Int32 nLen,
    1095             :                                       long* pDXAry, long nLayoutWidth,
    1096             :                                       bool bCellBreaking ) const
    1097             : {
    1098             : 
    1099       50572 :     if( nIndex >= rStr.getLength() )
    1100           0 :         return false;
    1101       50572 :     if( nIndex+nLen >= rStr.getLength() )
    1102       50572 :         nLen = rStr.getLength() - nIndex;
    1103             : 
    1104             :     // layout complex text
    1105             :     SalLayout* pSalLayout = ImplLayout( rStr, nIndex, nLen,
    1106       50572 :                                         Point(0,0), nLayoutWidth, pDXAry );
    1107       50572 :     if( !pSalLayout )
    1108           0 :         return false;
    1109             : 
    1110       50572 :     int nWidthFactor = pSalLayout->GetUnitsPerPixel();
    1111       50572 :     pSalLayout->GetCaretPositions( 2*nLen, pCaretXArray );
    1112       50572 :     long nWidth = pSalLayout->GetTextWidth();
    1113       50572 :     pSalLayout->Release();
    1114             : 
    1115             :     // fixup unknown caret positions
    1116             :     int i;
    1117       50640 :     for( i = 0; i < 2 * nLen; ++i )
    1118       50636 :         if( pCaretXArray[ i ] >= 0 )
    1119       50568 :             break;
    1120       50572 :     long nXPos = pCaretXArray[ i ];
    1121      568190 :     for( i = 0; i < 2 * nLen; ++i )
    1122             :     {
    1123      517618 :         if( pCaretXArray[ i ] >= 0 )
    1124      517550 :             nXPos = pCaretXArray[ i ];
    1125             :         else
    1126          68 :             pCaretXArray[ i ] = nXPos;
    1127             :     }
    1128             : 
    1129             :     // handle window mirroring
    1130       50572 :     if( IsRTLEnabled() )
    1131             :     {
    1132          73 :         for( i = 0; i < 2 * nLen; ++i )
    1133          54 :             pCaretXArray[i] = nWidth - pCaretXArray[i] - 1;
    1134             :     }
    1135             : 
    1136             :     // convert from font units to logical units
    1137       50572 :     if( mbMap )
    1138             :     {
    1139           0 :         for( i = 0; i < 2*nLen; ++i )
    1140           0 :             pCaretXArray[i] = ImplDevicePixelToLogicWidth( pCaretXArray[i] );
    1141             :     }
    1142             : 
    1143       50572 :     if( nWidthFactor != 1 )
    1144             :     {
    1145           0 :         for( i = 0; i < 2*nLen; ++i )
    1146           0 :             pCaretXArray[i] /= nWidthFactor;
    1147             :     }
    1148             : 
    1149             :     // if requested move caret position to cell limits
    1150             :     if( bCellBreaking )
    1151             :     {
    1152             :         ; // FIXME
    1153             :     }
    1154             : 
    1155       50572 :     return true;
    1156             : }
    1157             : 
    1158       72970 : void OutputDevice::DrawStretchText( const Point& rStartPt, sal_uLong nWidth,
    1159             :                                     const OUString& rStr,
    1160             :                                     sal_Int32 nIndex, sal_Int32 nLen)
    1161             : {
    1162       72970 :     if(nIndex < 0 || nIndex == 0x0FFFF || nLen == 0x0FFFF)
    1163             :     {
    1164             :         SAL_INFO("sal.rtl.xub",
    1165             :                  "DrawStretchText Suspicious arguments nIndex:" << nIndex << " nLen:" << nLen);
    1166             :     }
    1167       72970 :     if( (nLen < 0) || (nIndex + nLen >= rStr.getLength()))
    1168             :     {
    1169       72970 :         nLen = rStr.getLength() - nIndex;
    1170             :     }
    1171             : 
    1172       72970 :     if ( mpMetaFile )
    1173       71120 :         mpMetaFile->AddAction( new MetaStretchTextAction( rStartPt, nWidth, rStr, nIndex, nLen ) );
    1174             : 
    1175       72970 :     if ( !IsDeviceOutputNecessary() )
    1176      144090 :         return;
    1177             : 
    1178        1850 :     SalLayout* pSalLayout = ImplLayout(rStr, nIndex, nLen, rStartPt, nWidth, NULL);
    1179        1850 :     if( pSalLayout )
    1180             :     {
    1181        1850 :         ImplDrawText( *pSalLayout );
    1182        1850 :         pSalLayout->Release();
    1183             :     }
    1184             : 
    1185        1850 :     if( mpAlphaVDev )
    1186           0 :         mpAlphaVDev->DrawStretchText( rStartPt, nWidth, rStr, nIndex, nLen );
    1187             : }
    1188             : 
    1189     2155743 : ImplLayoutArgs OutputDevice::ImplPrepareLayoutArgs( OUString& rStr,
    1190             :                                                     const sal_Int32 nMinIndex, const sal_Int32 nLen,
    1191             :                                                     DeviceCoordinate nPixelWidth, const DeviceCoordinate* pDXArray,
    1192             :                                                     int nLayoutFlags ) const
    1193             : {
    1194             :     assert(nMinIndex >= 0);
    1195             :     assert(nLen >= 0);
    1196             : 
    1197             :     // get string length for calculating extents
    1198     2155743 :     sal_Int32 nEndIndex = rStr.getLength();
    1199     2155743 :     if( nMinIndex + nLen < nEndIndex )
    1200      346690 :         nEndIndex = nMinIndex + nLen;
    1201             : 
    1202             :     // don't bother if there is nothing to do
    1203     2155743 :     if( nEndIndex < nMinIndex )
    1204           0 :         nEndIndex = nMinIndex;
    1205             : 
    1206     2155743 :     if( mnTextLayoutMode & TEXT_LAYOUT_BIDI_RTL )
    1207        4112 :         nLayoutFlags |= SAL_LAYOUT_BIDI_RTL;
    1208     2155743 :     if( mnTextLayoutMode & TEXT_LAYOUT_BIDI_STRONG )
    1209      556892 :         nLayoutFlags |= SAL_LAYOUT_BIDI_STRONG;
    1210     1598851 :     else if( !(mnTextLayoutMode & TEXT_LAYOUT_BIDI_RTL) )
    1211             :     {
    1212             :         // disable Bidi if no RTL hint and no RTL codes used
    1213     1594763 :         const sal_Unicode* pStr = rStr.getStr() + nMinIndex;
    1214     1594763 :         const sal_Unicode* pEnd = rStr.getStr() + nEndIndex;
    1215    16012656 :         for( ; pStr < pEnd; ++pStr )
    1216    14417933 :             if( ((*pStr >= 0x0580) && (*pStr < 0x0800))   // middle eastern scripts
    1217    14417893 :             ||  ((*pStr >= 0xFB18) && (*pStr < 0xFE00))   // hebrew + arabic A presentation forms
    1218    14417893 :             ||  ((*pStr >= 0xFE70) && (*pStr < 0xFEFF)) ) // arabic presentation forms B
    1219             :                 break;
    1220     1594763 :         if( pStr >= pEnd )
    1221     1594723 :             nLayoutFlags |= SAL_LAYOUT_BIDI_STRONG;
    1222             :     }
    1223             : 
    1224     2155743 :     if( mbKerning )
    1225      345951 :         nLayoutFlags |= SAL_LAYOUT_KERNING_PAIRS;
    1226     2155743 :     if( maFont.GetKerning() & KERNING_ASIAN )
    1227           0 :         nLayoutFlags |= SAL_LAYOUT_KERNING_ASIAN;
    1228     2155743 :     if( maFont.IsVertical() )
    1229          80 :         nLayoutFlags |= SAL_LAYOUT_VERTICAL;
    1230             : 
    1231     2155743 :     if( mnTextLayoutMode & TEXT_LAYOUT_ENABLE_LIGATURES )
    1232           0 :         nLayoutFlags |= SAL_LAYOUT_ENABLE_LIGATURES;
    1233     2155743 :     else if( mnTextLayoutMode & TEXT_LAYOUT_COMPLEX_DISABLED )
    1234      206014 :         nLayoutFlags |= SAL_LAYOUT_COMPLEX_DISABLED;
    1235             :     else
    1236             :     {
    1237             :         // disable CTL for non-CTL text
    1238     1949729 :         const sal_Unicode* pStr = rStr.getStr() + nMinIndex;
    1239     1949729 :         const sal_Unicode* pEnd = rStr.getStr() + nEndIndex;
    1240    41929158 :         for( ; pStr < pEnd; ++pStr )
    1241    39979477 :             if( ((*pStr >= 0x0300) && (*pStr < 0x0370))   // diacritical marks
    1242    39979477 :             ||  ((*pStr >= 0x0590) && (*pStr < 0x10A0))   // many CTL scripts
    1243    39979429 :             ||  ((*pStr >= 0x1100) && (*pStr < 0x1200))   // hangul jamo
    1244    39979429 :             ||  ((*pStr >= 0x1700) && (*pStr < 0x1900))   // many CTL scripts
    1245    39979429 :             ||  ((*pStr >= 0xFB1D) && (*pStr < 0xFE00))   // middle east presentation
    1246    39979429 :             ||  ((*pStr >= 0xFE70) && (*pStr < 0xFEFF))   // arabic presentation B
    1247    39979429 :             ||  ((*pStr >= 0xFE00) && (*pStr < 0xFE10))   // variation selectors in BMP
    1248    39979429 :             ||  ((pStr + 1 < pEnd) && (pStr[0] == 0xDB40) && (0xDD00 <= pStr[1]) && (pStr[1] < 0xDEF0)) // variation selector supplement
    1249             :             )
    1250             :                 break;
    1251     1949729 :         if( pStr >= pEnd )
    1252     1949681 :             nLayoutFlags |= SAL_LAYOUT_COMPLEX_DISABLED;
    1253             :     }
    1254             : 
    1255     2155743 :     if( meTextLanguage ) //TODO: (mnTextLayoutMode & TEXT_LAYOUT_SUBSTITUTE_DIGITS)
    1256             :     {
    1257             :         // disable character localization when no digits used
    1258      659658 :         const sal_Unicode* pBase = rStr.getStr();
    1259      659658 :         const sal_Unicode* pStr = pBase + nMinIndex;
    1260      659658 :         const sal_Unicode* pEnd = pBase + nEndIndex;
    1261      659658 :         OUStringBuffer sTmpStr(rStr);
    1262    24397452 :         for( ; pStr < pEnd; ++pStr )
    1263             :         {
    1264             :             // TODO: are there non-digit localizations?
    1265    23737794 :             if( (*pStr >= '0') && (*pStr <= '9') )
    1266             :             {
    1267             :                 // translate characters to local preference
    1268    10298325 :                 sal_UCS4 cChar = GetLocalizedChar( *pStr, meTextLanguage );
    1269    10298325 :                 if( cChar != *pStr )
    1270             :                     // TODO: are the localized digit surrogates?
    1271           0 :                     sTmpStr[pStr - pBase] = cChar;
    1272             :             }
    1273             :         }
    1274      659658 :         rStr = sTmpStr.makeStringAndClear();
    1275             :     }
    1276             : 
    1277             :     // right align for RTL text, DRAWPOS_REVERSED, RTL window style
    1278     2155743 :     bool bRightAlign = bool(mnTextLayoutMode & TEXT_LAYOUT_BIDI_RTL);
    1279     2155743 :     if( mnTextLayoutMode & TEXT_LAYOUT_TEXTORIGIN_LEFT )
    1280      164239 :         bRightAlign = false;
    1281     1991504 :     else if ( mnTextLayoutMode & TEXT_LAYOUT_TEXTORIGIN_RIGHT )
    1282           0 :         bRightAlign = true;
    1283             :     // SSA: hack for western office, ie text get right aligned
    1284             :     //      for debugging purposes of mirrored UI
    1285     2155743 :     bool bRTLWindow = IsRTLEnabled();
    1286     2155743 :     bRightAlign ^= bRTLWindow;
    1287     2155743 :     if( bRightAlign )
    1288         907 :         nLayoutFlags |= SAL_LAYOUT_RIGHT_ALIGN;
    1289             : 
    1290             :     // set layout options
    1291     2155743 :     ImplLayoutArgs aLayoutArgs( rStr.getStr(), rStr.getLength(), nMinIndex, nEndIndex, nLayoutFlags, maFont.GetLanguageTag() );
    1292             : 
    1293     2155743 :     int nOrientation = mpFontEntry ? mpFontEntry->mnOrientation : 0;
    1294     2155743 :     aLayoutArgs.SetOrientation( nOrientation );
    1295             : 
    1296     2155743 :     aLayoutArgs.SetLayoutWidth( nPixelWidth );
    1297     2155743 :     aLayoutArgs.SetDXArray( pDXArray );
    1298             : 
    1299     2155743 :     return aLayoutArgs;
    1300             : }
    1301             : 
    1302     2155741 : SalLayout* OutputDevice::ImplLayout(const OUString& rOrigStr,
    1303             :                                     sal_Int32 nMinIndex, sal_Int32 nLen,
    1304             :                                     const Point& rLogicalPos, long nLogicalWidth,
    1305             :                                     const long* pDXArray, int flags) const
    1306             : {
    1307             :     // we need a graphics
    1308     2155741 :     if( !mpGraphics )
    1309         292 :         if( !AcquireGraphics() )
    1310           0 :             return NULL;
    1311             : 
    1312             :     // initialize font if needed
    1313     2155741 :     if( mbNewFont )
    1314      239012 :         if( !ImplNewFont() )
    1315           0 :             return NULL;
    1316     2155741 :     if( mbInitFont )
    1317      265818 :         InitFont();
    1318             : 
    1319             :     // check string index and length
    1320     2155741 :     if( -1 == nLen || nMinIndex + nLen > rOrigStr.getLength() )
    1321             :     {
    1322      336652 :         const sal_Int32 nNewLen = rOrigStr.getLength() - nMinIndex;
    1323      336652 :         if( nNewLen <= 0 )
    1324           0 :             return NULL;
    1325      336652 :         nLen = nNewLen;
    1326             :     }
    1327             : 
    1328     2155741 :     OUString aStr = rOrigStr;
    1329             : 
    1330             :     // convert from logical units to physical units
    1331             :     // recode string if needed
    1332     2155741 :     if( mpFontEntry->mpConversion ) {
    1333        5938 :         mpFontEntry->mpConversion->RecodeString( aStr, 0, aStr.getLength() );
    1334             :     }
    1335     2155741 :     DeviceCoordinate nPixelWidth = (DeviceCoordinate)nLogicalWidth;
    1336     2155741 :     DeviceCoordinate* pDXPixelArray = NULL;
    1337     2155741 :     if( nLogicalWidth && mbMap )
    1338             :     {
    1339        1844 :         nPixelWidth = LogicWidthToDeviceCoordinate( nLogicalWidth );
    1340             :     }
    1341             : 
    1342     2155741 :     if( pDXArray)
    1343             :     {
    1344       57142 :         if(mbMap)
    1345             :         {
    1346             :             // convert from logical units to font units using a temporary array
    1347       49729 :             pDXPixelArray = (DeviceCoordinate*)alloca( nLen * sizeof(DeviceCoordinate) );
    1348             :             // using base position for better rounding a.k.a. "dancing characters"
    1349       49729 :             DeviceCoordinate nPixelXOfs = LogicWidthToDeviceCoordinate( rLogicalPos.X() );
    1350     2337837 :             for( int i = 0; i < nLen; ++i )
    1351             :             {
    1352     2288108 :                 pDXPixelArray[i] = LogicWidthToDeviceCoordinate( rLogicalPos.X() + pDXArray[i] ) - nPixelXOfs;
    1353             :             }
    1354             :         }
    1355             :         else
    1356             :         {
    1357             : #if VCL_FLOAT_DEVICE_PIXEL
    1358             :             pDXPixelArray = (DeviceCoordinate*)alloca( nLen * sizeof(DeviceCoordinate) );
    1359             :             for( int i = 0; i < nLen; ++i )
    1360             :             {
    1361             :                 pDXPixelArray[i] = pDXArray[i];
    1362             :             }
    1363             : #else /* !VCL_FLOAT_DEVICE_PIXEL */
    1364        7413 :             pDXPixelArray = (DeviceCoordinate*)pDXArray;
    1365             : #endif /* !VCL_FLOAT_DEVICE_PIXEL */
    1366             :         }
    1367             :     }
    1368             : 
    1369     4311482 :     ImplLayoutArgs aLayoutArgs = ImplPrepareLayoutArgs( aStr, nMinIndex, nLen, nPixelWidth, pDXPixelArray, flags);
    1370             : 
    1371             :     // get matching layout object for base font
    1372     2155741 :     SalLayout* pSalLayout = mpGraphics->GetTextLayout( aLayoutArgs, 0 );
    1373             : 
    1374             :     // layout text
    1375     2155741 :     if( pSalLayout && !pSalLayout->LayoutText( aLayoutArgs ) )
    1376             :     {
    1377           0 :         pSalLayout->Release();
    1378           0 :         pSalLayout = NULL;
    1379             :     }
    1380             : 
    1381     2155741 :     if( !pSalLayout )
    1382           0 :         return NULL;
    1383             : 
    1384             :     // do glyph fallback if needed
    1385             :     // #105768# avoid fallback for very small font sizes
    1386     2155741 :     if (aLayoutArgs.NeedFallback() && mpFontEntry->maFontSelData.mnHeight >= 3)
    1387        1938 :         pSalLayout = ImplGlyphFallbackLayout(pSalLayout, aLayoutArgs);
    1388             : 
    1389             :     // position, justify, etc. the layout
    1390     2155741 :     pSalLayout->AdjustLayout( aLayoutArgs );
    1391     2155741 :     pSalLayout->DrawBase() = ImplLogicToDevicePixel( rLogicalPos );
    1392             :     // adjust to right alignment if necessary
    1393     2155741 :     if( aLayoutArgs.mnFlags & SAL_LAYOUT_RIGHT_ALIGN )
    1394             :     {
    1395             :         DeviceCoordinate nRTLOffset;
    1396         907 :         if( pDXPixelArray )
    1397          10 :             nRTLOffset = pDXPixelArray[ nLen - 1 ];
    1398         897 :         else if( nPixelWidth )
    1399           0 :             nRTLOffset = nPixelWidth;
    1400             :         else
    1401         897 :             nRTLOffset = pSalLayout->GetTextWidth() / pSalLayout->GetUnitsPerPixel();
    1402         907 :         pSalLayout->DrawOffset().X() = 1 - nRTLOffset;
    1403             :     }
    1404             : 
    1405     4311482 :     return pSalLayout;
    1406             : }
    1407             : 
    1408           2 : bool OutputDevice::GetTextIsRTL( const OUString& rString, sal_Int32 nIndex, sal_Int32 nLen ) const
    1409             : {
    1410           2 :     OUString aStr( rString );
    1411           4 :     ImplLayoutArgs aArgs = ImplPrepareLayoutArgs( aStr, nIndex, nLen, 0, NULL );
    1412           2 :     bool bRTL = false;
    1413           2 :     int nCharPos = -1;
    1414           2 :     if (!aArgs.GetNextPos(&nCharPos, &bRTL))
    1415           0 :         return false;
    1416           4 :     return (nCharPos != nIndex);
    1417             : }
    1418             : 
    1419      108846 : sal_Int32 OutputDevice::GetTextBreak( const OUString& rStr, long nTextWidth,
    1420             :                                        sal_Int32 nIndex, sal_Int32 nLen,
    1421             :                                        long nCharExtra ) const
    1422             : {
    1423      108846 :     SalLayout* pSalLayout = ImplLayout( rStr, nIndex, nLen );
    1424      108846 :     sal_Int32 nRetVal = -1;
    1425      108846 :     if( pSalLayout )
    1426             :     {
    1427             :         // convert logical widths into layout units
    1428             :         // NOTE: be very careful to avoid rounding errors for nCharExtra case
    1429             :         // problem with rounding errors especially for small nCharExtras
    1430             :         // TODO: remove when layout units have subpixel granularity
    1431      108846 :         long nWidthFactor = pSalLayout->GetUnitsPerPixel();
    1432      108846 :         long nSubPixelFactor = (nWidthFactor < 64 ) ? 64 : 1;
    1433      108846 :         nTextWidth *= nWidthFactor * nSubPixelFactor;
    1434      108846 :         DeviceCoordinate nTextPixelWidth = LogicWidthToDeviceCoordinate( nTextWidth );
    1435      108846 :         DeviceCoordinate nExtraPixelWidth = 0;
    1436      108846 :         if( nCharExtra != 0 )
    1437             :         {
    1438         266 :             nCharExtra *= nWidthFactor * nSubPixelFactor;
    1439         266 :             nExtraPixelWidth = LogicWidthToDeviceCoordinate( nCharExtra );
    1440             :         }
    1441      108846 :         nRetVal = pSalLayout->GetTextBreak( nTextPixelWidth, nExtraPixelWidth, nSubPixelFactor );
    1442             : 
    1443      108846 :         pSalLayout->Release();
    1444             :     }
    1445             : 
    1446      108846 :     return nRetVal;
    1447             : }
    1448             : 
    1449           0 : sal_Int32 OutputDevice::GetTextBreak( const OUString& rStr, long nTextWidth,
    1450             :                                        sal_Unicode nHyphenChar, sal_Int32& rHyphenPos,
    1451             :                                        sal_Int32 nIndex, sal_Int32 nLen,
    1452             :                                        long nCharExtra ) const
    1453             : {
    1454           0 :     rHyphenPos = -1;
    1455             : 
    1456           0 :     SalLayout* pSalLayout = ImplLayout( rStr, nIndex, nLen );
    1457           0 :     sal_Int32 nRetVal = -1;
    1458           0 :     if( pSalLayout )
    1459             :     {
    1460             :         // convert logical widths into layout units
    1461             :         // NOTE: be very careful to avoid rounding errors for nCharExtra case
    1462             :         // problem with rounding errors especially for small nCharExtras
    1463             :         // TODO: remove when layout units have subpixel granularity
    1464           0 :         long nWidthFactor = pSalLayout->GetUnitsPerPixel();
    1465           0 :         long nSubPixelFactor = (nWidthFactor < 64 ) ? 64 : 1;
    1466             : 
    1467           0 :         nTextWidth *= nWidthFactor * nSubPixelFactor;
    1468           0 :         DeviceCoordinate nTextPixelWidth = LogicWidthToDeviceCoordinate( nTextWidth );
    1469           0 :         DeviceCoordinate nExtraPixelWidth = 0;
    1470           0 :         if( nCharExtra != 0 )
    1471             :         {
    1472           0 :             nCharExtra *= nWidthFactor * nSubPixelFactor;
    1473           0 :             nExtraPixelWidth = LogicWidthToDeviceCoordinate( nCharExtra );
    1474             :         }
    1475             : 
    1476             :         // calculate un-hyphenated break position
    1477           0 :         nRetVal = pSalLayout->GetTextBreak( nTextPixelWidth, nExtraPixelWidth, nSubPixelFactor );
    1478             : 
    1479             :         // calculate hyphenated break position
    1480           0 :         OUString aHyphenStr(nHyphenChar);
    1481           0 :         sal_Int32 nTempLen = 1;
    1482           0 :         SalLayout* pHyphenLayout = ImplLayout( aHyphenStr, 0, nTempLen );
    1483           0 :         if( pHyphenLayout )
    1484             :         {
    1485             :             // calculate subpixel width of hyphenation character
    1486           0 :             long nHyphenPixelWidth = pHyphenLayout->GetTextWidth() * nSubPixelFactor;
    1487           0 :             pHyphenLayout->Release();
    1488             : 
    1489             :             // calculate hyphenated break position
    1490           0 :             nTextPixelWidth -= nHyphenPixelWidth;
    1491           0 :             if( nExtraPixelWidth > 0 )
    1492           0 :                 nTextPixelWidth -= nExtraPixelWidth;
    1493             : 
    1494           0 :             rHyphenPos = pSalLayout->GetTextBreak(nTextPixelWidth, nExtraPixelWidth, nSubPixelFactor);
    1495             : 
    1496           0 :             if( rHyphenPos > nRetVal )
    1497           0 :                 rHyphenPos = nRetVal;
    1498             :         }
    1499             : 
    1500           0 :         pSalLayout->Release();
    1501             :     }
    1502             : 
    1503           0 :     return nRetVal;
    1504             : }
    1505             : 
    1506       27818 : void OutputDevice::ImplDrawText( OutputDevice& rTargetDevice, const Rectangle& rRect,
    1507             :                                  const OUString& rOrigStr, sal_uInt16 nStyle,
    1508             :                                  MetricVector* pVector, OUString* pDisplayText,
    1509             :                                  ::vcl::ITextLayout& _rLayout )
    1510             : {
    1511             : 
    1512       27818 :     Color aOldTextColor;
    1513       27818 :     Color aOldTextFillColor;
    1514       27818 :     bool  bRestoreFillColor = false;
    1515       27818 :     if ( (nStyle & TEXT_DRAW_DISABLE) && ! pVector )
    1516             :     {
    1517         751 :         bool  bHighContrastBlack = false;
    1518         751 :         bool  bHighContrastWhite = false;
    1519         751 :         const StyleSettings& rStyleSettings( rTargetDevice.GetSettings().GetStyleSettings() );
    1520         751 :         if( rStyleSettings.GetHighContrastMode() )
    1521             :         {
    1522           0 :             Color aCol;
    1523           0 :             if( rTargetDevice.IsBackground() )
    1524           0 :                 aCol = rTargetDevice.GetBackground().GetColor();
    1525             :             else
    1526             :                 // best guess is the face color here
    1527             :                 // but it may be totally wrong. the background color
    1528             :                 // was typically already reset
    1529           0 :                 aCol = rStyleSettings.GetFaceColor();
    1530             : 
    1531           0 :             bHighContrastBlack = aCol.IsDark();
    1532           0 :             bHighContrastWhite = aCol.IsBright();
    1533             :         }
    1534             : 
    1535         751 :         aOldTextColor = rTargetDevice.GetTextColor();
    1536         751 :         if ( rTargetDevice.IsTextFillColor() )
    1537             :         {
    1538           0 :             bRestoreFillColor = true;
    1539           0 :             aOldTextFillColor = rTargetDevice.GetTextFillColor();
    1540             :         }
    1541         751 :         if( bHighContrastBlack )
    1542           0 :             rTargetDevice.SetTextColor( COL_GREEN );
    1543         751 :         else if( bHighContrastWhite )
    1544           0 :             rTargetDevice.SetTextColor( COL_LIGHTGREEN );
    1545             :         else
    1546             :         {
    1547             :             // draw disabled text always without shadow
    1548             :             // as it fits better with native look
    1549         751 :             rTargetDevice.SetTextColor( rTargetDevice.GetSettings().GetStyleSettings().GetDisableColor() );
    1550             :         }
    1551             :     }
    1552             : 
    1553       27818 :     long        nWidth          = rRect.GetWidth();
    1554       27818 :     long        nHeight         = rRect.GetHeight();
    1555             : 
    1556       27818 :     if ( ((nWidth <= 0) || (nHeight <= 0)) && (nStyle & TEXT_DRAW_CLIP) )
    1557       27818 :         return;
    1558             : 
    1559       27818 :     Point       aPos            = rRect.TopLeft();
    1560             : 
    1561       27818 :     long        nTextHeight     = rTargetDevice.GetTextHeight();
    1562       27818 :     TextAlign   eAlign          = rTargetDevice.GetTextAlign();
    1563       27818 :     sal_Int32   nMnemonicPos    = -1;
    1564             : 
    1565       27818 :     OUString aStr = rOrigStr;
    1566       27818 :     if ( nStyle & TEXT_DRAW_MNEMONIC )
    1567       10764 :         aStr = GetNonMnemonicString( aStr, nMnemonicPos );
    1568             : 
    1569       27818 :     const bool bDrawMnemonics = !(rTargetDevice.GetSettings().GetStyleSettings().GetOptions() & STYLE_OPTION_NOMNEMONICS) && !pVector;
    1570             : 
    1571             :     // We treat multiline text differently
    1572       27818 :     if ( nStyle & TEXT_DRAW_MULTILINE )
    1573             :     {
    1574             : 
    1575       10804 :         OUString                aLastLine;
    1576       21608 :         ImplMultiTextLineInfo   aMultiLineInfo;
    1577             :         ImplTextLineInfo*       pLineInfo;
    1578             :         sal_Int32               i;
    1579             :         sal_Int32               nLines;
    1580             :         sal_Int32               nFormatLines;
    1581             : 
    1582       10804 :         if ( nTextHeight )
    1583             :         {
    1584       10804 :             long nMaxTextWidth = ImplGetTextLines( aMultiLineInfo, nWidth, aStr, nStyle, _rLayout );
    1585       10804 :             nLines = (sal_Int32)(nHeight/nTextHeight);
    1586       10804 :             nFormatLines = aMultiLineInfo.Count();
    1587       10804 :             if (nLines <= 0)
    1588          80 :                 nLines = 1;
    1589       10804 :             if ( nFormatLines > nLines )
    1590             :             {
    1591           0 :                 if ( nStyle & TEXT_DRAW_ENDELLIPSIS )
    1592             :                 {
    1593             :                     // Create last line and shorten it
    1594           0 :                     nFormatLines = nLines-1;
    1595             : 
    1596           0 :                     pLineInfo = aMultiLineInfo.GetLine( nFormatLines );
    1597           0 :                     aLastLine = convertLineEnd(aStr.copy(pLineInfo->GetIndex()), LINEEND_LF);
    1598             :                     // Replace all LineFeeds with Spaces
    1599           0 :                     OUStringBuffer aLastLineBuffer(aLastLine);
    1600           0 :                     sal_Int32 nLastLineLen = aLastLineBuffer.getLength();
    1601           0 :                     for ( i = 0; i < nLastLineLen; i++ )
    1602             :                     {
    1603           0 :                         if ( aLastLineBuffer[ i ] == '\n' )
    1604           0 :                             aLastLineBuffer[ i ] = ' ';
    1605             :                     }
    1606           0 :                     aLastLine = aLastLineBuffer.makeStringAndClear();
    1607           0 :                     aLastLine = ImplGetEllipsisString( rTargetDevice, aLastLine, nWidth, nStyle, _rLayout );
    1608           0 :                     nStyle &= ~(TEXT_DRAW_VCENTER | TEXT_DRAW_BOTTOM);
    1609           0 :                     nStyle |= TEXT_DRAW_TOP;
    1610             :                 }
    1611             :             }
    1612             :             else
    1613             :             {
    1614       10804 :                 if ( nMaxTextWidth <= nWidth )
    1615       10789 :                     nStyle &= ~TEXT_DRAW_CLIP;
    1616             :             }
    1617             : 
    1618             :             // Do we need to clip the height?
    1619       10804 :             if ( nFormatLines*nTextHeight > nHeight )
    1620          80 :                 nStyle |= TEXT_DRAW_CLIP;
    1621             : 
    1622             :             // Set clipping
    1623       10804 :             if ( nStyle & TEXT_DRAW_CLIP )
    1624             :             {
    1625          80 :                 rTargetDevice.Push( PushFlags::CLIPREGION );
    1626          80 :                 rTargetDevice.IntersectClipRegion( rRect );
    1627             :             }
    1628             : 
    1629             :             // Vertical alignment
    1630       10804 :             if ( nStyle & TEXT_DRAW_BOTTOM )
    1631           0 :                 aPos.Y() += nHeight-(nFormatLines*nTextHeight);
    1632       10804 :             else if ( nStyle & TEXT_DRAW_VCENTER )
    1633        3819 :                 aPos.Y() += (nHeight-(nFormatLines*nTextHeight))/2;
    1634             : 
    1635             :             // Font alignment
    1636       10804 :             if ( eAlign == ALIGN_BOTTOM )
    1637           0 :                 aPos.Y() += nTextHeight;
    1638       10804 :             else if ( eAlign == ALIGN_BASELINE )
    1639           0 :                 aPos.Y() += rTargetDevice.GetFontMetric().GetAscent();
    1640             : 
    1641             :             // Output all lines except for the last one
    1642       35074 :             for ( i = 0; i < nFormatLines; i++ )
    1643             :             {
    1644       24270 :                 pLineInfo = aMultiLineInfo.GetLine( i );
    1645       24270 :                 if ( nStyle & TEXT_DRAW_RIGHT )
    1646           0 :                     aPos.X() += nWidth-pLineInfo->GetWidth();
    1647       24270 :                 else if ( nStyle & TEXT_DRAW_CENTER )
    1648         474 :                     aPos.X() += (nWidth-pLineInfo->GetWidth())/2;
    1649       24270 :                 sal_Int32 nIndex   = pLineInfo->GetIndex();
    1650       24270 :                 sal_Int32 nLineLen = pLineInfo->GetLen();
    1651       24270 :                 _rLayout.DrawText( aPos, aStr, nIndex, nLineLen, pVector, pDisplayText );
    1652       24270 :                 if ( bDrawMnemonics )
    1653             :                 {
    1654       24268 :                     if ( (nMnemonicPos >= nIndex) && (nMnemonicPos < nIndex+nLineLen) )
    1655             :                     {
    1656             :                         long        nMnemonicX;
    1657             :                         long        nMnemonicY;
    1658             :                         DeviceCoordinate nMnemonicWidth;
    1659             : 
    1660        2866 :                         long* pCaretXArray = (long*) alloca( 2 * sizeof(long) * nLineLen );
    1661             :                         /*sal_Bool bRet =*/ _rLayout.GetCaretPositions( aStr, pCaretXArray,
    1662        2866 :                                                 nIndex, nLineLen );
    1663        2866 :                         long lc_x1 = pCaretXArray[2*(nMnemonicPos - nIndex)];
    1664        2866 :                         long lc_x2 = pCaretXArray[2*(nMnemonicPos - nIndex)+1];
    1665        2866 :                         nMnemonicWidth = rTargetDevice.LogicWidthToDeviceCoordinate( std::abs(lc_x1 - lc_x2) );
    1666             : 
    1667        2866 :                         Point       aTempPos = rTargetDevice.LogicToPixel( aPos );
    1668        2866 :                         nMnemonicX = rTargetDevice.GetOutOffXPixel() + aTempPos.X() + rTargetDevice.ImplLogicWidthToDevicePixel( std::min( lc_x1, lc_x2 ) );
    1669        2866 :                         nMnemonicY = rTargetDevice.GetOutOffYPixel() + aTempPos.Y() + rTargetDevice.ImplLogicWidthToDevicePixel( rTargetDevice.GetFontMetric().GetAscent() );
    1670        2866 :                         rTargetDevice.ImplDrawMnemonicLine( nMnemonicX, nMnemonicY, nMnemonicWidth );
    1671             :                     }
    1672             :                 }
    1673       24270 :                 aPos.Y() += nTextHeight;
    1674       24270 :                 aPos.X() = rRect.Left();
    1675             :             }
    1676             : 
    1677             :             // If there still is a last line, we output it left-aligned as the line would be clipped
    1678       10804 :             if ( !aLastLine.isEmpty() )
    1679           0 :                 _rLayout.DrawText( aPos, aLastLine, 0, aLastLine.getLength(), pVector, pDisplayText );
    1680             : 
    1681             :             // Reset clipping
    1682       10804 :             if ( nStyle & TEXT_DRAW_CLIP )
    1683          80 :                 rTargetDevice.Pop();
    1684       10804 :         }
    1685             :     }
    1686             :     else
    1687             :     {
    1688       17014 :         long nTextWidth = _rLayout.GetTextWidth( aStr, 0, -1 );
    1689             : 
    1690             :         // Clip text if needed
    1691       17014 :         if ( nTextWidth > nWidth )
    1692             :         {
    1693         116 :             if ( nStyle & TEXT_DRAW_ELLIPSIS )
    1694             :             {
    1695           0 :                 aStr = ImplGetEllipsisString( rTargetDevice, aStr, nWidth, nStyle, _rLayout );
    1696           0 :                 nStyle &= ~(TEXT_DRAW_CENTER | TEXT_DRAW_RIGHT);
    1697           0 :                 nStyle |= TEXT_DRAW_LEFT;
    1698           0 :                 nTextWidth = _rLayout.GetTextWidth( aStr, 0, aStr.getLength() );
    1699             :             }
    1700             :         }
    1701             :         else
    1702             :         {
    1703       16898 :             if ( nTextHeight <= nHeight )
    1704       16898 :                 nStyle &= ~TEXT_DRAW_CLIP;
    1705             :         }
    1706             : 
    1707             :         // horizontal text alignment
    1708       17014 :         if ( nStyle & TEXT_DRAW_RIGHT )
    1709         474 :             aPos.X() += nWidth-nTextWidth;
    1710       16540 :         else if ( nStyle & TEXT_DRAW_CENTER )
    1711          96 :             aPos.X() += (nWidth-nTextWidth)/2;
    1712             : 
    1713             :         // vertical font alignment
    1714       17014 :         if ( eAlign == ALIGN_BOTTOM )
    1715           0 :             aPos.Y() += nTextHeight;
    1716       17014 :         else if ( eAlign == ALIGN_BASELINE )
    1717           0 :             aPos.Y() += rTargetDevice.GetFontMetric().GetAscent();
    1718             : 
    1719       17014 :         if ( nStyle & TEXT_DRAW_BOTTOM )
    1720           0 :             aPos.Y() += nHeight-nTextHeight;
    1721       17014 :         else if ( nStyle & TEXT_DRAW_VCENTER )
    1722       15083 :             aPos.Y() += (nHeight-nTextHeight)/2;
    1723             : 
    1724       17014 :         long nMnemonicX = 0;
    1725       17014 :         long nMnemonicY = 0;
    1726       17014 :         DeviceCoordinate nMnemonicWidth = 0;
    1727       17014 :         if ( nMnemonicPos != -1 )
    1728             :         {
    1729           0 :             long* pCaretXArray = (long*) alloca( 2 * sizeof(long) * aStr.getLength() );
    1730           0 :             /*sal_Bool bRet =*/ _rLayout.GetCaretPositions( aStr, pCaretXArray, 0, aStr.getLength() );
    1731           0 :             long lc_x1 = pCaretXArray[2*(nMnemonicPos)];
    1732           0 :             long lc_x2 = pCaretXArray[2*(nMnemonicPos)+1];
    1733           0 :             nMnemonicWidth = rTargetDevice.LogicWidthToDeviceCoordinate( std::abs(lc_x1 - lc_x2) );
    1734             : 
    1735           0 :             Point aTempPos = rTargetDevice.LogicToPixel( aPos );
    1736           0 :             nMnemonicX = rTargetDevice.GetOutOffXPixel() + aTempPos.X() + rTargetDevice.ImplLogicWidthToDevicePixel( std::min(lc_x1, lc_x2) );
    1737           0 :             nMnemonicY = rTargetDevice.GetOutOffYPixel() + aTempPos.Y() + rTargetDevice.ImplLogicWidthToDevicePixel( rTargetDevice.GetFontMetric().GetAscent() );
    1738             :         }
    1739             : 
    1740       17014 :         if ( nStyle & TEXT_DRAW_CLIP )
    1741             :         {
    1742           0 :             rTargetDevice.Push( PushFlags::CLIPREGION );
    1743           0 :             rTargetDevice.IntersectClipRegion( rRect );
    1744           0 :             _rLayout.DrawText( aPos, aStr, 0, aStr.getLength(), pVector, pDisplayText );
    1745           0 :             if ( bDrawMnemonics )
    1746             :             {
    1747           0 :                 if ( nMnemonicPos != -1 )
    1748           0 :                     rTargetDevice.ImplDrawMnemonicLine( nMnemonicX, nMnemonicY, nMnemonicWidth );
    1749             :             }
    1750           0 :             rTargetDevice.Pop();
    1751             :         }
    1752             :         else
    1753             :         {
    1754       17014 :             _rLayout.DrawText( aPos, aStr, 0, aStr.getLength(), pVector, pDisplayText );
    1755       17014 :             if ( bDrawMnemonics )
    1756             :             {
    1757       17014 :                 if ( nMnemonicPos != -1 )
    1758           0 :                     rTargetDevice.ImplDrawMnemonicLine( nMnemonicX, nMnemonicY, nMnemonicWidth );
    1759             :             }
    1760             :         }
    1761             :     }
    1762             : 
    1763       27818 :     if ( nStyle & TEXT_DRAW_DISABLE && !pVector )
    1764             :     {
    1765         751 :         rTargetDevice.SetTextColor( aOldTextColor );
    1766         751 :         if ( bRestoreFillColor )
    1767           0 :             rTargetDevice.SetTextFillColor( aOldTextFillColor );
    1768       27818 :     }
    1769             : }
    1770             : 
    1771           0 : void OutputDevice::AddTextRectActions( const Rectangle& rRect,
    1772             :                                        const OUString&  rOrigStr,
    1773             :                                        sal_uInt16       nStyle,
    1774             :                                        GDIMetaFile&     rMtf )
    1775             : {
    1776             : 
    1777           0 :     if ( rOrigStr.isEmpty() || rRect.IsEmpty() )
    1778           0 :         return;
    1779             : 
    1780             :     // we need a graphics
    1781           0 :     if( !mpGraphics && !AcquireGraphics() )
    1782           0 :         return;
    1783           0 :     if( mbInitClipRegion )
    1784           0 :         InitClipRegion();
    1785             : 
    1786             :     // temporarily swap in passed mtf for action generation, and
    1787             :     // disable output generation.
    1788           0 :     const bool bOutputEnabled( IsOutputEnabled() );
    1789           0 :     GDIMetaFile* pMtf = mpMetaFile;
    1790             : 
    1791           0 :     mpMetaFile = &rMtf;
    1792           0 :     EnableOutput( false );
    1793             : 
    1794             :     // #i47157# Factored out to ImplDrawTextRect(), to be shared
    1795             :     // between us and DrawText()
    1796           0 :     vcl::DefaultTextLayout aLayout( *this );
    1797           0 :     ImplDrawText( *this, rRect, rOrigStr, nStyle, NULL, NULL, aLayout );
    1798             : 
    1799             :     // and restore again
    1800           0 :     EnableOutput( bOutputEnabled );
    1801           0 :     mpMetaFile = pMtf;
    1802             : }
    1803             : 
    1804       31041 : void OutputDevice::DrawText( const Rectangle& rRect, const OUString& rOrigStr, sal_uInt16 nStyle,
    1805             :                              MetricVector* pVector, OUString* pDisplayText,
    1806             :                              ::vcl::ITextLayout* _pTextLayout )
    1807             : {
    1808       31041 :     if( mpOutDevData && mpOutDevData->mpRecordLayout )
    1809             :     {
    1810           0 :         pVector = &mpOutDevData->mpRecordLayout->m_aUnicodeBoundRects;
    1811           0 :         pDisplayText = &mpOutDevData->mpRecordLayout->m_aDisplayText;
    1812             :     }
    1813             : 
    1814       31041 :     bool bDecomposeTextRectAction = ( _pTextLayout != NULL ) && _pTextLayout->DecomposeTextRectAction();
    1815       31041 :     if ( mpMetaFile && !bDecomposeTextRectAction )
    1816         819 :         mpMetaFile->AddAction( new MetaTextRectAction( rRect, rOrigStr, nStyle ) );
    1817             : 
    1818       31041 :     if ( ( !IsDeviceOutputNecessary() && !pVector && !bDecomposeTextRectAction ) || rOrigStr.isEmpty() || rRect.IsEmpty() )
    1819        5939 :         return;
    1820             : 
    1821             :     // we need a graphics
    1822       28325 :     if( !mpGraphics && !AcquireGraphics() )
    1823           0 :         return;
    1824       28325 :     if( mbInitClipRegion )
    1825        3198 :         InitClipRegion();
    1826       28325 :     if( mbOutputClipped && !bDecomposeTextRectAction )
    1827         507 :         return;
    1828             : 
    1829             :     // temporarily disable mtf action generation (ImplDrawText _does_
    1830             :     // create META_TEXT_ACTIONs otherwise)
    1831       27818 :     GDIMetaFile* pMtf = mpMetaFile;
    1832       27818 :     if ( !bDecomposeTextRectAction )
    1833       27555 :         mpMetaFile = NULL;
    1834             : 
    1835             :     // #i47157# Factored out to ImplDrawText(), to be used also
    1836             :     // from AddTextRectActions()
    1837       27818 :     vcl::DefaultTextLayout aDefaultLayout( *this );
    1838       27818 :     ImplDrawText( *this, rRect, rOrigStr, nStyle, pVector, pDisplayText, _pTextLayout ? *_pTextLayout : aDefaultLayout );
    1839             : 
    1840             :     // and enable again
    1841       27818 :     mpMetaFile = pMtf;
    1842             : 
    1843       27818 :     if( mpAlphaVDev )
    1844         503 :         mpAlphaVDev->DrawText( rRect, rOrigStr, nStyle, pVector, pDisplayText );
    1845             : }
    1846             : 
    1847       26303 : Rectangle OutputDevice::GetTextRect( const Rectangle& rRect,
    1848             :                                      const OUString& rStr, sal_uInt16 nStyle,
    1849             :                                      TextRectInfo* pInfo,
    1850             :                                      const ::vcl::ITextLayout* _pTextLayout ) const
    1851             : {
    1852             : 
    1853       26303 :     Rectangle           aRect = rRect;
    1854             :     sal_Int32           nLines;
    1855       26303 :     long                nWidth = rRect.GetWidth();
    1856             :     long                nMaxWidth;
    1857       26303 :     long                nTextHeight = GetTextHeight();
    1858             : 
    1859       26303 :     OUString aStr = rStr;
    1860       26303 :     if ( nStyle & TEXT_DRAW_MNEMONIC )
    1861       12291 :         aStr = GetNonMnemonicString( aStr );
    1862             : 
    1863       26303 :     if ( nStyle & TEXT_DRAW_MULTILINE )
    1864             :     {
    1865       11954 :         ImplMultiTextLineInfo   aMultiLineInfo;
    1866             :         ImplTextLineInfo*       pLineInfo;
    1867             :         sal_Int32               nFormatLines;
    1868             :         sal_Int32               i;
    1869             : 
    1870       11954 :         nMaxWidth = 0;
    1871       23908 :         vcl::DefaultTextLayout aDefaultLayout( *const_cast< OutputDevice* >( this ) );
    1872       11954 :         ImplGetTextLines( aMultiLineInfo, nWidth, aStr, nStyle, _pTextLayout ? *_pTextLayout : aDefaultLayout );
    1873       11954 :         nFormatLines = aMultiLineInfo.Count();
    1874       11954 :         if ( !nTextHeight )
    1875           0 :             nTextHeight = 1;
    1876       11954 :         nLines = (sal_uInt16)(aRect.GetHeight()/nTextHeight);
    1877       11954 :         if ( pInfo )
    1878           0 :             pInfo->mnLineCount = nFormatLines;
    1879       11954 :         if ( !nLines )
    1880          38 :             nLines = 1;
    1881       11954 :         if ( nFormatLines <= nLines )
    1882       11954 :             nLines = nFormatLines;
    1883             :         else
    1884             :         {
    1885           0 :             if ( !(nStyle & TEXT_DRAW_ENDELLIPSIS) )
    1886           0 :                 nLines = nFormatLines;
    1887             :             else
    1888             :             {
    1889           0 :                 if ( pInfo )
    1890           0 :                     pInfo->mbEllipsis = true;
    1891           0 :                 nMaxWidth = nWidth;
    1892             :             }
    1893             :         }
    1894       11954 :         if ( pInfo )
    1895             :         {
    1896           0 :             bool bMaxWidth = nMaxWidth == 0;
    1897           0 :             pInfo->mnMaxWidth = 0;
    1898           0 :             for ( i = 0; i < nLines; i++ )
    1899             :             {
    1900           0 :                 pLineInfo = aMultiLineInfo.GetLine( i );
    1901           0 :                 if ( bMaxWidth && (pLineInfo->GetWidth() > nMaxWidth) )
    1902           0 :                     nMaxWidth = pLineInfo->GetWidth();
    1903           0 :                 if ( pLineInfo->GetWidth() > pInfo->mnMaxWidth )
    1904           0 :                     pInfo->mnMaxWidth = pLineInfo->GetWidth();
    1905             :             }
    1906             :         }
    1907       11954 :         else if ( !nMaxWidth )
    1908             :         {
    1909       37119 :             for ( i = 0; i < nLines; i++ )
    1910             :             {
    1911       25165 :                 pLineInfo = aMultiLineInfo.GetLine( i );
    1912       25165 :                 if ( pLineInfo->GetWidth() > nMaxWidth )
    1913       18431 :                     nMaxWidth = pLineInfo->GetWidth();
    1914             :             }
    1915       11954 :         }
    1916             :     }
    1917             :     else
    1918             :     {
    1919       14349 :         nLines      = 1;
    1920       14349 :         nMaxWidth   = _pTextLayout ? _pTextLayout->GetTextWidth( aStr, 0, aStr.getLength() ) : GetTextWidth( aStr );
    1921             : 
    1922       14349 :         if ( pInfo )
    1923             :         {
    1924           0 :             pInfo->mnLineCount  = 1;
    1925           0 :             pInfo->mnMaxWidth   = nMaxWidth;
    1926             :         }
    1927             : 
    1928       14349 :         if ( (nMaxWidth > nWidth) && (nStyle & TEXT_DRAW_ELLIPSIS) )
    1929             :         {
    1930           2 :             if ( pInfo )
    1931           0 :                 pInfo->mbEllipsis = true;
    1932           2 :             nMaxWidth = nWidth;
    1933             :         }
    1934             :     }
    1935             : 
    1936       26303 :     if ( nStyle & TEXT_DRAW_RIGHT )
    1937           0 :         aRect.Left() = aRect.Right()-nMaxWidth+1;
    1938       26303 :     else if ( nStyle & TEXT_DRAW_CENTER )
    1939             :     {
    1940         405 :         aRect.Left() += (nWidth-nMaxWidth)/2;
    1941         405 :         aRect.Right() = aRect.Left()+nMaxWidth-1;
    1942             :     }
    1943             :     else
    1944       25898 :         aRect.Right() = aRect.Left()+nMaxWidth-1;
    1945             : 
    1946       26303 :     if ( nStyle & TEXT_DRAW_BOTTOM )
    1947           0 :         aRect.Top() = aRect.Bottom()-(nTextHeight*nLines)+1;
    1948       26303 :     else if ( nStyle & TEXT_DRAW_VCENTER )
    1949             :     {
    1950       18902 :         aRect.Top()   += (aRect.GetHeight()-(nTextHeight*nLines))/2;
    1951       18902 :         aRect.Bottom() = aRect.Top()+(nTextHeight*nLines)-1;
    1952             :     }
    1953             :     else
    1954        7401 :         aRect.Bottom() = aRect.Top()+(nTextHeight*nLines)-1;
    1955             : 
    1956             :     // #99188# get rid of rounding problems when using this rect later
    1957       26303 :     if (nStyle & TEXT_DRAW_RIGHT)
    1958           0 :         aRect.Left()--;
    1959             :     else
    1960       26303 :         aRect.Right()++;
    1961       26303 :     return aRect;
    1962             : }
    1963             : 
    1964           0 : static bool ImplIsCharIn( sal_Unicode c, const sal_Char* pStr )
    1965             : {
    1966           0 :     while ( *pStr )
    1967             :     {
    1968           0 :         if ( *pStr == c )
    1969           0 :             return true;
    1970           0 :         pStr++;
    1971             :     }
    1972             : 
    1973           0 :     return false;
    1974             : }
    1975             : 
    1976       15305 : OUString OutputDevice::GetEllipsisString( const OUString& rOrigStr, long nMaxWidth,
    1977             :                                         sal_uInt16 nStyle ) const
    1978             : {
    1979       15305 :     vcl::DefaultTextLayout aTextLayout( *const_cast< OutputDevice* >( this ) );
    1980       15305 :     return ImplGetEllipsisString( *this, rOrigStr, nMaxWidth, nStyle, aTextLayout );
    1981             : }
    1982             : 
    1983       15305 : OUString OutputDevice::ImplGetEllipsisString( const OutputDevice& rTargetDevice, const OUString& rOrigStr, long nMaxWidth,
    1984             :                                                sal_uInt16 nStyle, const ::vcl::ITextLayout& _rLayout )
    1985             : {
    1986       15305 :     OUString aStr = rOrigStr;
    1987       15305 :     sal_Int32 nIndex = _rLayout.GetTextBreak( aStr, nMaxWidth, 0, aStr.getLength() );
    1988             : 
    1989       15305 :     if ( nIndex != -1 )
    1990             :     {
    1991           0 :         if( (nStyle & TEXT_DRAW_CENTERELLIPSIS) == TEXT_DRAW_CENTERELLIPSIS )
    1992             :         {
    1993           0 :             OUStringBuffer aTmpStr( aStr );
    1994           0 :             sal_Int32 nEraseChars = 4;
    1995           0 :             while( nEraseChars < aStr.getLength() && _rLayout.GetTextWidth( aTmpStr.toString(), 0, aTmpStr.getLength() ) > nMaxWidth )
    1996             :             {
    1997           0 :                 aTmpStr = OUStringBuffer(aStr);
    1998           0 :                 sal_Int32 i = (aTmpStr.getLength() - nEraseChars)/2;
    1999           0 :                 aTmpStr.remove(i, nEraseChars++);
    2000           0 :                 aTmpStr.insert(i, "...");
    2001             :             }
    2002           0 :             aStr = aTmpStr.makeStringAndClear();
    2003             :         }
    2004           0 :         else if ( nStyle & TEXT_DRAW_ENDELLIPSIS )
    2005             :         {
    2006           0 :             aStr = aStr.copy(0, nIndex);
    2007           0 :             if ( nIndex > 1 )
    2008             :             {
    2009           0 :                 aStr += "...";
    2010           0 :                 while ( !aStr.isEmpty() && (_rLayout.GetTextWidth( aStr, 0, aStr.getLength() ) > nMaxWidth) )
    2011             :                 {
    2012           0 :                     if ( (nIndex > 1) || (nIndex == aStr.getLength()) )
    2013           0 :                         nIndex--;
    2014           0 :                     aStr = aStr.replaceAt( nIndex, 1, "");
    2015             :                 }
    2016             :             }
    2017             : 
    2018           0 :             if ( aStr.isEmpty() && (nStyle & TEXT_DRAW_CLIP) )
    2019           0 :                 aStr += OUString(rOrigStr[ 0 ]);
    2020             :         }
    2021           0 :         else if ( nStyle & TEXT_DRAW_PATHELLIPSIS )
    2022             :         {
    2023           0 :             OUString aPath( rOrigStr );
    2024           0 :             OUString aAbbreviatedPath;
    2025           0 :             osl_abbreviateSystemPath( aPath.pData, &aAbbreviatedPath.pData, nIndex, NULL );
    2026           0 :             aStr = aAbbreviatedPath;
    2027             :         }
    2028           0 :         else if ( nStyle & TEXT_DRAW_NEWSELLIPSIS )
    2029             :         {
    2030             :             static sal_Char const   pSepChars[] = ".";
    2031             :             // Determine last section
    2032           0 :             sal_Int32 nLastContent = aStr.getLength();
    2033           0 :             while ( nLastContent )
    2034             :             {
    2035           0 :                 nLastContent--;
    2036           0 :                 if ( ImplIsCharIn( aStr[ nLastContent ], pSepChars ) )
    2037           0 :                     break;
    2038             :             }
    2039           0 :             while ( nLastContent &&
    2040           0 :                     ImplIsCharIn( aStr[ nLastContent-1 ], pSepChars ) )
    2041           0 :                 nLastContent--;
    2042             : 
    2043           0 :             OUString aLastStr = aStr.copy(nLastContent);
    2044           0 :             OUString aTempLastStr1( "..." );
    2045           0 :             aTempLastStr1 += aLastStr;
    2046           0 :             if ( _rLayout.GetTextWidth( aTempLastStr1, 0, aTempLastStr1.getLength() ) > nMaxWidth )
    2047           0 :                 aStr = OutputDevice::ImplGetEllipsisString( rTargetDevice, aStr, nMaxWidth, nStyle | TEXT_DRAW_ENDELLIPSIS, _rLayout );
    2048             :             else
    2049             :             {
    2050           0 :                 sal_Int32 nFirstContent = 0;
    2051           0 :                 while ( nFirstContent < nLastContent )
    2052             :                 {
    2053           0 :                     nFirstContent++;
    2054           0 :                     if ( ImplIsCharIn( aStr[ nFirstContent ], pSepChars ) )
    2055           0 :                         break;
    2056             :                 }
    2057           0 :                 while ( (nFirstContent < nLastContent) &&
    2058           0 :                         ImplIsCharIn( aStr[ nFirstContent ], pSepChars ) )
    2059           0 :                     nFirstContent++;
    2060             :                 // MEM continue here
    2061           0 :                 if ( nFirstContent >= nLastContent )
    2062           0 :                     aStr = OutputDevice::ImplGetEllipsisString( rTargetDevice, aStr, nMaxWidth, nStyle | TEXT_DRAW_ENDELLIPSIS, _rLayout );
    2063             :                 else
    2064             :                 {
    2065           0 :                     if ( nFirstContent > 4 )
    2066           0 :                         nFirstContent = 4;
    2067           0 :                     OUString aFirstStr = aStr.copy( 0, nFirstContent );
    2068           0 :                     aFirstStr += "...";
    2069           0 :                     OUString aTempStr = aFirstStr + aLastStr;
    2070           0 :                     if ( _rLayout.GetTextWidth( aTempStr, 0, aTempStr.getLength() ) > nMaxWidth )
    2071           0 :                         aStr = OutputDevice::ImplGetEllipsisString( rTargetDevice, aStr, nMaxWidth, nStyle | TEXT_DRAW_ENDELLIPSIS, _rLayout );
    2072             :                     else
    2073             :                     {
    2074           0 :                         do
    2075             :                         {
    2076           0 :                             aStr = aTempStr;
    2077           0 :                             if( nLastContent > aStr.getLength() )
    2078           0 :                                 nLastContent = aStr.getLength();
    2079           0 :                             while ( nFirstContent < nLastContent )
    2080             :                             {
    2081           0 :                                 nLastContent--;
    2082           0 :                                 if ( ImplIsCharIn( aStr[ nLastContent ], pSepChars ) )
    2083           0 :                                     break;
    2084             : 
    2085             :                             }
    2086           0 :                             while ( (nFirstContent < nLastContent) &&
    2087           0 :                                     ImplIsCharIn( aStr[ nLastContent-1 ], pSepChars ) )
    2088           0 :                                 nLastContent--;
    2089             : 
    2090           0 :                             if ( nFirstContent < nLastContent )
    2091             :                             {
    2092           0 :                                 OUString aTempLastStr = aStr.copy( nLastContent );
    2093           0 :                                 aTempStr = aFirstStr + aTempLastStr;
    2094             : 
    2095           0 :                                 if ( _rLayout.GetTextWidth( aTempStr, 0, aTempStr.getLength() ) > nMaxWidth )
    2096           0 :                                     break;
    2097             :                             }
    2098             :                         }
    2099             :                         while ( nFirstContent < nLastContent );
    2100           0 :                     }
    2101             :                 }
    2102           0 :             }
    2103             :         }
    2104             :     }
    2105             : 
    2106       15305 :     return aStr;
    2107             : }
    2108             : 
    2109       15537 : void OutputDevice::DrawCtrlText( const Point& rPos, const OUString& rStr,
    2110             :                                  sal_Int32 nIndex, sal_Int32 nLen,
    2111             :                                  sal_uInt16 nStyle, MetricVector* pVector, OUString* pDisplayText )
    2112             : {
    2113             : 
    2114       15537 :     if(nLen == 0x0FFFF)
    2115             :     {
    2116             :         SAL_INFO("sal.rtl.xub",
    2117             :                  "DrawCtrlText Suspicious arguments nLen:" << nLen);
    2118             :     }
    2119       15537 :     if( (nLen < 0) || (nIndex + nLen >= rStr.getLength()))
    2120             :     {
    2121       15537 :         nLen = rStr.getLength() - nIndex;
    2122             :     }
    2123             : 
    2124       15537 :     if ( !IsDeviceOutputNecessary() || (nIndex >= rStr.getLength()) )
    2125           0 :         return;
    2126             : 
    2127             :     // better get graphics here because ImplDrawMnemonicLine() will not
    2128             :     // we need a graphics
    2129       15537 :     if( !mpGraphics && !AcquireGraphics() )
    2130           0 :         return;
    2131       15537 :     if( mbInitClipRegion )
    2132        1813 :         InitClipRegion();
    2133       15537 :     if ( mbOutputClipped )
    2134           0 :         return;
    2135             : 
    2136       15537 :     if( nIndex >= rStr.getLength() )
    2137           0 :         return;
    2138             : 
    2139       15537 :     if( (nLen < 0) || (nIndex + nLen >= rStr.getLength()))
    2140             :     {
    2141       15537 :         nLen = rStr.getLength() - nIndex;
    2142             :     }
    2143       15537 :     OUString   aStr = rStr;
    2144       15537 :     sal_Int32  nMnemonicPos = -1;
    2145             : 
    2146       15537 :     long        nMnemonicX = 0;
    2147       15537 :     long        nMnemonicY = 0;
    2148       15537 :     long        nMnemonicWidth = 0;
    2149       15537 :     if ( (nStyle & TEXT_DRAW_MNEMONIC) && nLen > 1 )
    2150             :     {
    2151       15430 :         aStr = GetNonMnemonicString( aStr, nMnemonicPos );
    2152       15430 :         if ( nMnemonicPos != -1 )
    2153             :         {
    2154       15280 :             if( nMnemonicPos < nIndex )
    2155             :             {
    2156           0 :                 --nIndex;
    2157             :             }
    2158             :             else
    2159             :             {
    2160       15280 :                 if( nMnemonicPos < (nIndex+nLen) )
    2161       15280 :                     --nLen;
    2162             :                 DBG_ASSERT( nMnemonicPos < (nIndex+nLen), "Mnemonic underline marker after last character" );
    2163             :             }
    2164       15280 :             bool bInvalidPos = false;
    2165             : 
    2166       15280 :             if( nMnemonicPos >= nLen )
    2167             :             {
    2168             :                 // #106952#
    2169             :                 // may occur in BiDi-Strings: the '~' is sometimes found behind the last char
    2170             :                 // due to some strange BiDi text editors
    2171             :                 // -> place the underline behind the string to indicate a failure
    2172           0 :                 bInvalidPos = true;
    2173           0 :                 nMnemonicPos = nLen-1;
    2174             :             }
    2175             : 
    2176       15280 :             long* pCaretXArray = (long*)alloca( 2 * sizeof(long) * nLen );
    2177       15280 :             /*sal_Bool bRet =*/ GetCaretPositions( aStr, pCaretXArray, nIndex, nLen );
    2178       15280 :             long lc_x1 = pCaretXArray[ 2*(nMnemonicPos - nIndex) ];
    2179       15280 :             long lc_x2 = pCaretXArray[ 2*(nMnemonicPos - nIndex)+1 ];
    2180       15280 :             nMnemonicWidth = ::abs((int)(lc_x1 - lc_x2));
    2181             : 
    2182       15280 :             Point aTempPos( std::min(lc_x1,lc_x2), GetFontMetric().GetAscent() );
    2183       15280 :             if( bInvalidPos )  // #106952#, place behind the (last) character
    2184           0 :                 aTempPos = Point( std::max(lc_x1,lc_x2), GetFontMetric().GetAscent() );
    2185             : 
    2186       15280 :             aTempPos += rPos;
    2187       15280 :             aTempPos = LogicToPixel( aTempPos );
    2188       15280 :             nMnemonicX = mnOutOffX + aTempPos.X();
    2189       15280 :             nMnemonicY = mnOutOffY + aTempPos.Y();
    2190             :         }
    2191             :     }
    2192             : 
    2193       15537 :     if ( nStyle & TEXT_DRAW_DISABLE && ! pVector )
    2194             :     {
    2195         190 :         Color aOldTextColor;
    2196         190 :         Color aOldTextFillColor;
    2197             :         bool  bRestoreFillColor;
    2198         190 :         bool  bHighContrastBlack = false;
    2199         190 :         bool  bHighContrastWhite = false;
    2200         190 :         const StyleSettings& rStyleSettings( GetSettings().GetStyleSettings() );
    2201         190 :         if( rStyleSettings.GetHighContrastMode() )
    2202             :         {
    2203           0 :             if( IsBackground() )
    2204             :             {
    2205           0 :                 Wallpaper aWall = GetBackground();
    2206           0 :                 Color aCol = aWall.GetColor();
    2207           0 :                 bHighContrastBlack = aCol.IsDark();
    2208           0 :                 bHighContrastWhite = aCol.IsBright();
    2209             :             }
    2210             :         }
    2211             : 
    2212         190 :         aOldTextColor = GetTextColor();
    2213         190 :         if ( IsTextFillColor() )
    2214             :         {
    2215           0 :             bRestoreFillColor = true;
    2216           0 :             aOldTextFillColor = GetTextFillColor();
    2217             :         }
    2218             :         else
    2219         190 :             bRestoreFillColor = false;
    2220             : 
    2221         190 :         if( bHighContrastBlack )
    2222           0 :             SetTextColor( COL_GREEN );
    2223         190 :         else if( bHighContrastWhite )
    2224           0 :             SetTextColor( COL_LIGHTGREEN );
    2225             :         else
    2226         190 :             SetTextColor( GetSettings().GetStyleSettings().GetDisableColor() );
    2227             : 
    2228         190 :         DrawText( rPos, aStr, nIndex, nLen, pVector, pDisplayText );
    2229         190 :         if ( !(GetSettings().GetStyleSettings().GetOptions() & STYLE_OPTION_NOMNEMONICS) && !pVector )
    2230             :         {
    2231         190 :             if ( nMnemonicPos != -1 )
    2232         158 :                 ImplDrawMnemonicLine( nMnemonicX, nMnemonicY, nMnemonicWidth );
    2233             :         }
    2234         190 :         SetTextColor( aOldTextColor );
    2235         190 :         if ( bRestoreFillColor )
    2236           0 :             SetTextFillColor( aOldTextFillColor );
    2237             :     }
    2238             :     else
    2239             :     {
    2240       15347 :         DrawText( rPos, aStr, nIndex, nLen, pVector, pDisplayText );
    2241       15347 :         if ( !(GetSettings().GetStyleSettings().GetOptions() & STYLE_OPTION_NOMNEMONICS) && !pVector )
    2242             :         {
    2243       15295 :             if ( nMnemonicPos != -1 )
    2244       15070 :                 ImplDrawMnemonicLine( nMnemonicX, nMnemonicY, nMnemonicWidth );
    2245             :         }
    2246             :     }
    2247             : 
    2248       15537 :     if( mpAlphaVDev )
    2249           0 :         mpAlphaVDev->DrawCtrlText( rPos, rStr, nIndex, nLen, nStyle, pVector, pDisplayText );
    2250             : }
    2251             : 
    2252       67098 : long OutputDevice::GetCtrlTextWidth( const OUString& rStr,
    2253             :                                      sal_Int32 nIndex, sal_Int32 nLen,
    2254             :                                      sal_uInt16 nStyle ) const
    2255             : {
    2256       67098 :     if(nLen == 0x0FFFF)
    2257             :     {
    2258             :         SAL_INFO("sal.rtl.xub",
    2259             :                  "GetCtrlTextWidth Suspicious arguments nLen:" << nLen);
    2260             :     }
    2261             :     /* defensive code */
    2262       67098 :     if( (nLen < 0) || (nIndex + nLen >= rStr.getLength()))
    2263             :     {
    2264       67098 :         nLen = rStr.getLength() - nIndex;
    2265             :     }
    2266             : 
    2267       67098 :     if ( nStyle & TEXT_DRAW_MNEMONIC )
    2268             :     {
    2269             :         sal_Int32  nMnemonicPos;
    2270       67098 :         OUString   aStr = GetNonMnemonicString( rStr, nMnemonicPos );
    2271       67098 :         if ( nMnemonicPos != -1 )
    2272             :         {
    2273       14468 :             if ( nMnemonicPos < nIndex )
    2274           0 :                 nIndex--;
    2275       14468 :             else if ( (nMnemonicPos >= nIndex) && ((sal_uLong)nMnemonicPos < (sal_uLong)(nIndex+nLen)) )
    2276       14468 :                 nLen--;
    2277             :         }
    2278       67098 :         return GetTextWidth( aStr, nIndex, nLen );
    2279             :     }
    2280             :     else
    2281           0 :         return GetTextWidth( rStr, nIndex, nLen );
    2282             : }
    2283             : 
    2284      144639 : OUString OutputDevice::GetNonMnemonicString( const OUString& rStr, sal_Int32& rMnemonicPos )
    2285             : {
    2286      144639 :     OUString   aStr    = rStr;
    2287      144639 :     sal_Int32  nLen    = aStr.getLength();
    2288      144639 :     sal_Int32  i       = 0;
    2289             : 
    2290      144639 :     rMnemonicPos = -1;
    2291     3352128 :     while ( i < nLen )
    2292             :     {
    2293     3062850 :         if ( aStr[ i ] == '~' )
    2294             :         {
    2295       52680 :             if ( nLen <= i+1 )
    2296           0 :                 break;
    2297             : 
    2298       52680 :             if ( aStr[ i+1 ] != '~' )
    2299             :             {
    2300       52680 :                 if ( rMnemonicPos == -1 )
    2301       52680 :                     rMnemonicPos = i;
    2302       52680 :                 aStr = aStr.replaceAt( i, 1, "" );
    2303       52680 :                 nLen--;
    2304             :             }
    2305             :             else
    2306             :             {
    2307           0 :                 aStr = aStr.replaceAt( i, 1, "" );
    2308           0 :                 nLen--;
    2309           0 :                 i++;
    2310             :             }
    2311             :         }
    2312             :         else
    2313     3010170 :             i++;
    2314             :     }
    2315             : 
    2316      144639 :     return aStr;
    2317             : }
    2318             : 
    2319             : /** OutputDevice::GetSysTextLayoutData
    2320             :  *
    2321             :  * @param rStartPt Start point of the text
    2322             :  * @param rStr Text string that will be transformed into layout of glyphs
    2323             :  * @param nIndex Position in the string from where layout will be done
    2324             :  * @param nLen Length of the string
    2325             :  * @param pDXAry Custom layout adjustment data
    2326             :  *
    2327             :  * Export finalized glyph layout data as platform independent SystemTextLayoutData
    2328             :  * (see vcl/inc/vcl/sysdata.hxx)
    2329             :  *
    2330             :  * Only parameters rStartPt and rStr are mandatory, the rest is optional
    2331             :  * (default values will be used)
    2332             :  *
    2333             :  * @return SystemTextLayoutData
    2334             :  **/
    2335           0 : SystemTextLayoutData OutputDevice::GetSysTextLayoutData(const Point& rStartPt, const OUString& rStr, sal_Int32 nIndex, sal_Int32 nLen,
    2336             :                                                         const long* pDXAry) const
    2337             : {
    2338           0 :     if(nLen == 0x0FFFF)
    2339             :     {
    2340             :         SAL_INFO("sal.rtl.xub",
    2341             :                  "GetSysTextLayoutData Suspicious arguments nLen:" << nLen);
    2342             :     }
    2343           0 :     if( (nLen < 0) || (nIndex + nLen >= rStr.getLength()))
    2344             :     {
    2345           0 :         nLen = rStr.getLength() - nIndex;
    2346             :     }
    2347             : 
    2348           0 :     SystemTextLayoutData aSysLayoutData;
    2349           0 :     aSysLayoutData.nSize = sizeof(aSysLayoutData);
    2350           0 :     aSysLayoutData.rGlyphData.reserve( 256 );
    2351           0 :     aSysLayoutData.orientation = 0;
    2352             : 
    2353           0 :     if ( mpMetaFile )
    2354             :     {
    2355           0 :         if (pDXAry)
    2356           0 :             mpMetaFile->AddAction( new MetaTextArrayAction( rStartPt, rStr, pDXAry, nIndex, nLen ) );
    2357             :         else
    2358           0 :             mpMetaFile->AddAction( new MetaTextAction( rStartPt, rStr, nIndex, nLen ) );
    2359             :     }
    2360             : 
    2361           0 :     if ( !IsDeviceOutputNecessary() ) return aSysLayoutData;
    2362             : 
    2363           0 :     SalLayout* pLayout = ImplLayout(rStr, nIndex, nLen, rStartPt, 0, pDXAry);
    2364             : 
    2365           0 :     if ( !pLayout ) return aSysLayoutData;
    2366             : 
    2367             :     // setup glyphs
    2368           0 :     Point aPos;
    2369             :     sal_GlyphId aGlyphId;
    2370           0 :     for( int nStart = 0; pLayout->GetNextGlyphs( 1, &aGlyphId, aPos, nStart ); )
    2371             :     {
    2372             :         // NOTE: Windows backend is producing unicode chars (ucs4), so on windows,
    2373             :         //       ETO_GLYPH_INDEX is unusable, unless extra glyph conversion is made.
    2374             : 
    2375             :         SystemGlyphData aGlyph;
    2376           0 :         aGlyph.index = static_cast<unsigned long> (aGlyphId & GF_IDXMASK);
    2377           0 :         aGlyph.x = aPos.X();
    2378           0 :         aGlyph.y = aPos.Y();
    2379           0 :         int nLevel = (aGlyphId & GF_FONTMASK) >> GF_FONTSHIFT;
    2380           0 :         aGlyph.fallbacklevel = nLevel < MAX_FALLBACK ? nLevel : 0;
    2381           0 :         aSysLayoutData.rGlyphData.push_back(aGlyph);
    2382             :     }
    2383             : 
    2384             :     // Get font data
    2385           0 :     aSysLayoutData.orientation = pLayout->GetOrientation();
    2386             : 
    2387           0 :     pLayout->Release();
    2388             : 
    2389           0 :     return aSysLayoutData;
    2390             : }
    2391             : 
    2392      385302 : bool OutputDevice::GetTextBoundRect( Rectangle& rRect,
    2393             :                                          const OUString& rStr, sal_Int32 nBase,
    2394             :                                          sal_Int32 nIndex, sal_Int32 nLen,
    2395             :                                          sal_uLong nLayoutWidth, const long* pDXAry ) const
    2396             : {
    2397      385302 :     if(nLen == 0x0FFFF)
    2398             :     {
    2399             :         SAL_INFO("sal.rtl.xub",
    2400             :                  "GetTextBoundRect Suspicious arguments nLen:" << nLen);
    2401             :     }
    2402             : 
    2403      385302 :     bool bRet = false;
    2404      385302 :     rRect.SetEmpty();
    2405             : 
    2406      385302 :     SalLayout* pSalLayout = NULL;
    2407      385302 :     const Point aPoint;
    2408             :     // calculate offset when nBase!=nIndex
    2409      385302 :     long nXOffset = 0;
    2410      385302 :     if( nBase != nIndex )
    2411             :     {
    2412       23810 :         sal_Int32 nStart = std::min( nBase, nIndex );
    2413       23810 :         sal_Int32 nOfsLen = std::max( nBase, nIndex ) - nStart;
    2414       23810 :         pSalLayout = ImplLayout( rStr, nStart, nOfsLen, aPoint, nLayoutWidth, pDXAry );
    2415       23810 :         if( pSalLayout )
    2416             :         {
    2417       23810 :             nXOffset = pSalLayout->GetTextWidth();
    2418       23810 :             nXOffset /= pSalLayout->GetUnitsPerPixel();
    2419       23810 :             pSalLayout->Release();
    2420             :             // TODO: fix offset calculation for Bidi case
    2421       23810 :             if( nBase < nIndex)
    2422       23810 :                 nXOffset = -nXOffset;
    2423             :         }
    2424             :     }
    2425             : 
    2426      385302 :     pSalLayout = ImplLayout( rStr, nIndex, nLen, aPoint, nLayoutWidth, pDXAry );
    2427      385302 :     Rectangle aPixelRect;
    2428      385302 :     if( pSalLayout )
    2429             :     {
    2430      385302 :         bRet = pSalLayout->GetBoundRect( *mpGraphics, aPixelRect );
    2431             : 
    2432      385302 :         if( bRet )
    2433             :         {
    2434      385302 :             int nWidthFactor = pSalLayout->GetUnitsPerPixel();
    2435             : 
    2436      385302 :             if( nWidthFactor > 1 )
    2437             :             {
    2438           0 :                 double fFactor = 1.0 / nWidthFactor;
    2439           0 :                 aPixelRect.Left()
    2440           0 :                     = static_cast< long >(aPixelRect.Left() * fFactor);
    2441           0 :                 aPixelRect.Right()
    2442           0 :                     = static_cast< long >(aPixelRect.Right() * fFactor);
    2443           0 :                 aPixelRect.Top()
    2444           0 :                     = static_cast< long >(aPixelRect.Top() * fFactor);
    2445           0 :                 aPixelRect.Bottom()
    2446           0 :                     = static_cast< long >(aPixelRect.Bottom() * fFactor);
    2447             :             }
    2448             : 
    2449      385302 :             Point aRotatedOfs( mnTextOffX, mnTextOffY );
    2450      385302 :             aRotatedOfs -= pSalLayout->GetDrawPosition( Point( nXOffset, 0 ) );
    2451      385302 :             aPixelRect += aRotatedOfs;
    2452      385302 :             rRect = PixelToLogic( aPixelRect );
    2453      385302 :             if( mbMap )
    2454       18742 :                 rRect += Point( maMapRes.mnMapOfsX, maMapRes.mnMapOfsY );
    2455             :         }
    2456             : 
    2457      385302 :         pSalLayout->Release();
    2458             :     }
    2459             : 
    2460      385302 :     if( bRet || (OUTDEV_PRINTER == meOutDevType) || !mpFontEntry )
    2461      385302 :         return bRet;
    2462             : 
    2463             :     // fall back to bitmap method to get the bounding rectangle,
    2464             :     // so we need a monochrome virtual device with matching font
    2465           0 :     VirtualDevice aVDev( 1 );
    2466           0 :     vcl::Font aFont( GetFont() );
    2467           0 :     aFont.SetShadow( false );
    2468           0 :     aFont.SetOutline( false );
    2469           0 :     aFont.SetRelief( RELIEF_NONE );
    2470           0 :     aFont.SetOrientation( 0 );
    2471           0 :     aFont.SetSize( Size( mpFontEntry->maFontSelData.mnWidth, mpFontEntry->maFontSelData.mnHeight ) );
    2472           0 :     aVDev.SetFont( aFont );
    2473           0 :     aVDev.SetTextAlign( ALIGN_TOP );
    2474             : 
    2475             :     // layout the text on the virtual device
    2476           0 :     pSalLayout = aVDev.ImplLayout( rStr, nIndex, nLen, aPoint, nLayoutWidth, pDXAry );
    2477           0 :     if( !pSalLayout )
    2478           0 :         return false;
    2479             : 
    2480             :     // make the bitmap big enough
    2481             :     // TODO: use factors when it would get too big
    2482           0 :     long nWidth = pSalLayout->GetTextWidth();
    2483           0 :     long nHeight = mpFontEntry->mnLineHeight + mnEmphasisAscent + mnEmphasisDescent;
    2484           0 :     Point aOffset( nWidth/2, 8 );
    2485           0 :     Size aOutSize( nWidth + 2*aOffset.X(), nHeight + 2*aOffset.Y() );
    2486           0 :     if( !nWidth || !aVDev.SetOutputSizePixel( aOutSize ) )
    2487             :     {
    2488           0 :         pSalLayout->Release();
    2489           0 :         return false;
    2490             :     }
    2491             : 
    2492             :     // draw text in black
    2493           0 :     pSalLayout->DrawBase() = aOffset;
    2494           0 :     aVDev.SetTextColor( Color( COL_BLACK ) );
    2495           0 :     aVDev.SetTextFillColor();
    2496           0 :     aVDev.ImplInitTextColor();
    2497           0 :     aVDev.ImplDrawText( *pSalLayout );
    2498           0 :     pSalLayout->Release();
    2499             : 
    2500             :     // find extents using the bitmap
    2501           0 :     Bitmap aBmp = aVDev.GetBitmap( Point(), aOutSize );
    2502           0 :     BitmapReadAccess* pAcc = aBmp.AcquireReadAccess();
    2503           0 :     if( !pAcc )
    2504           0 :         return false;
    2505           0 :     const BitmapColor aBlack( pAcc->GetBestMatchingColor( Color( COL_BLACK ) ) );
    2506           0 :     const long nW = pAcc->Width();
    2507           0 :     const long nH = pAcc->Height();
    2508           0 :     long nLeft = 0;
    2509           0 :     long nRight = 0;
    2510             : 
    2511             :     // find top left point
    2512           0 :     long nTop = 0;
    2513           0 :     for(; nTop < nH; ++nTop )
    2514             :     {
    2515           0 :         for( nLeft = 0; nLeft < nW; ++nLeft )
    2516           0 :             if( pAcc->GetPixel( nTop, nLeft ) == aBlack )
    2517           0 :                 break;
    2518           0 :         if( nLeft < nW )
    2519           0 :             break;
    2520             :     }
    2521             : 
    2522             :     // find bottom right point
    2523           0 :     long nBottom = nH;
    2524           0 :     while( --nBottom >= nTop )
    2525             :     {
    2526           0 :         for( nRight = nW; --nRight >= 0; )
    2527           0 :             if( pAcc->GetPixel( nBottom, nRight ) == aBlack )
    2528           0 :                 break;
    2529           0 :         if( nRight >= 0 )
    2530           0 :             break;
    2531             :     }
    2532           0 :     if( nRight < nLeft )
    2533             :     {
    2534           0 :         long nX = nRight;
    2535           0 :         nRight = nLeft;
    2536           0 :         nLeft  = nX;
    2537             :     }
    2538             : 
    2539           0 :     for( long nY = nTop; nY <= nBottom; ++nY )
    2540             :     {
    2541             :         // find leftmost point
    2542             :         long nX;
    2543           0 :         for( nX = 0; nX < nLeft; ++nX )
    2544           0 :             if( pAcc->GetPixel( nY, nX ) == aBlack )
    2545           0 :                 break;
    2546           0 :         nLeft = nX;
    2547             : 
    2548             :         // find rightmost point
    2549           0 :         for( nX = nW; --nX > nRight; )
    2550           0 :             if( pAcc->GetPixel( nY, nX ) == aBlack )
    2551           0 :                 break;
    2552           0 :         nRight = nX;
    2553             :     }
    2554             : 
    2555           0 :     aBmp.ReleaseAccess( pAcc );
    2556             : 
    2557           0 :     if( nTop <= nBottom )
    2558             :     {
    2559           0 :         Size aSize( nRight - nLeft + 1, nBottom - nTop + 1 );
    2560           0 :         Point aTopLeft( nLeft, nTop );
    2561           0 :         aTopLeft -= aOffset;
    2562             :         // adjust to text alignment
    2563           0 :         aTopLeft.Y()+= mnTextOffY - (mpFontEntry->maMetric.mnAscent + mnEmphasisAscent);
    2564             :         // convert to logical coordinates
    2565           0 :         aSize = PixelToLogic( aSize );
    2566           0 :         aTopLeft.X() = ImplDevicePixelToLogicWidth( aTopLeft.X() );
    2567           0 :         aTopLeft.Y() = ImplDevicePixelToLogicHeight( aTopLeft.Y() );
    2568           0 :         rRect = Rectangle( aTopLeft, aSize );
    2569           0 :         return true;
    2570             :     }
    2571             : 
    2572           0 :     return false;
    2573             : }
    2574             : 
    2575         601 : bool OutputDevice::GetTextOutlines( ::basegfx::B2DPolyPolygonVector& rVector,
    2576             :                                         const OUString& rStr, sal_Int32 nBase,
    2577             :                                         sal_Int32 nIndex, sal_Int32 nLen,
    2578             :                                         bool bOptimize, sal_uLong nLayoutWidth, const long* pDXArray ) const
    2579             : {
    2580         601 :     if(nLen == 0x0FFFF)
    2581             :     {
    2582             :         SAL_INFO("sal.rtl.xub",
    2583             :                  "GetTextOutlines Suspicious arguments nLen:" << nLen);
    2584             :     }
    2585             :     // the fonts need to be initialized
    2586         601 :     if( mbNewFont )
    2587         385 :         ImplNewFont();
    2588         601 :     if( mbInitFont )
    2589         180 :         InitFont();
    2590         601 :     if( !mpFontEntry )
    2591           0 :         return false;
    2592             : 
    2593         601 :     bool bRet = false;
    2594         601 :     rVector.clear();
    2595         601 :     if( nLen < 0 )
    2596             :     {
    2597         392 :         nLen = rStr.getLength() - nIndex;
    2598             :     }
    2599         601 :     rVector.reserve( nLen );
    2600             : 
    2601             :     // we want to get the Rectangle in logical units, so to
    2602             :     // avoid rounding errors we just size the font in logical units
    2603         601 :     bool bOldMap = mbMap;
    2604         601 :     if( bOldMap )
    2605             :     {
    2606         392 :         const_cast<OutputDevice&>(*this).mbMap = false;
    2607         392 :         const_cast<OutputDevice&>(*this).mbNewFont = true;
    2608             :     }
    2609             : 
    2610         601 :     SalLayout* pSalLayout = NULL;
    2611             : 
    2612             :     // calculate offset when nBase!=nIndex
    2613         601 :     long nXOffset = 0;
    2614         601 :     if( nBase != nIndex )
    2615             :     {
    2616           0 :         sal_Int32 nStart = std::min( nBase, nIndex );
    2617           0 :         sal_Int32 nOfsLen = std::max( nBase, nIndex ) - nStart;
    2618           0 :         pSalLayout = ImplLayout( rStr, nStart, nOfsLen, Point(0,0), nLayoutWidth, pDXArray );
    2619           0 :         if( pSalLayout )
    2620             :         {
    2621           0 :             nXOffset = pSalLayout->GetTextWidth();
    2622           0 :             pSalLayout->Release();
    2623             :             // TODO: fix offset calculation for Bidi case
    2624           0 :             if( nBase > nIndex)
    2625           0 :                 nXOffset = -nXOffset;
    2626             :         }
    2627             :     }
    2628             : 
    2629         601 :     pSalLayout = ImplLayout( rStr, nIndex, nLen, Point(0,0), nLayoutWidth, pDXArray );
    2630         601 :     if( pSalLayout )
    2631             :     {
    2632         601 :         bRet = pSalLayout->GetOutline( *mpGraphics, rVector );
    2633         601 :         if( bRet )
    2634             :         {
    2635             :             // transform polygon to pixel units
    2636         601 :             ::basegfx::B2DHomMatrix aMatrix;
    2637             : 
    2638         601 :             int nWidthFactor = pSalLayout->GetUnitsPerPixel();
    2639         601 :             if( nXOffset | mnTextOffX | mnTextOffY )
    2640             :             {
    2641         148 :                 Point aRotatedOfs( mnTextOffX*nWidthFactor, mnTextOffY*nWidthFactor );
    2642         148 :                 aRotatedOfs -= pSalLayout->GetDrawPosition( Point( nXOffset, 0 ) );
    2643         148 :                 aMatrix.translate( aRotatedOfs.X(), aRotatedOfs.Y() );
    2644             :             }
    2645             : 
    2646         601 :             if( nWidthFactor > 1 )
    2647             :             {
    2648           0 :                 double fFactor = 1.0 / nWidthFactor;
    2649           0 :                 aMatrix.scale( fFactor, fFactor );
    2650             :             }
    2651             : 
    2652         601 :             if( !aMatrix.isIdentity() )
    2653             :             {
    2654         148 :                 ::basegfx::B2DPolyPolygonVector::iterator aIt = rVector.begin();
    2655        1800 :                 for(; aIt != rVector.end(); ++aIt )
    2656        1652 :                     (*aIt).transform( aMatrix );
    2657         601 :             }
    2658             :         }
    2659             : 
    2660         601 :         pSalLayout->Release();
    2661             :     }
    2662             : 
    2663         601 :     if( bOldMap )
    2664             :     {
    2665             :         // restore original font size and map mode
    2666         392 :         const_cast<OutputDevice&>(*this).mbMap = bOldMap;
    2667         392 :         const_cast<OutputDevice&>(*this).mbNewFont = true;
    2668             :     }
    2669             : 
    2670         601 :     if( bRet || (OUTDEV_PRINTER == meOutDevType) || !mpFontEntry )
    2671         601 :         return bRet;
    2672             : 
    2673             :     // fall back to bitmap conversion
    2674             :     // Here, we can savely assume that the mapping between characters and glyphs
    2675             :     // is one-to-one. This is most probably valid for the old bitmap fonts.
    2676             :     // fall back to bitmap method to get the bounding rectangle,
    2677             :     // so we need a monochrome virtual device with matching font
    2678           0 :     pSalLayout = ImplLayout( rStr, nIndex, nLen, Point(0,0), nLayoutWidth, pDXArray );
    2679           0 :     if (pSalLayout == 0)
    2680           0 :         return false;
    2681           0 :     long nOrgWidth = pSalLayout->GetTextWidth();
    2682           0 :     long nOrgHeight = mpFontEntry->mnLineHeight + mnEmphasisAscent
    2683           0 :         + mnEmphasisDescent;
    2684           0 :     pSalLayout->Release();
    2685             : 
    2686           0 :     VirtualDevice aVDev(1);
    2687             : 
    2688           0 :     vcl::Font aFont(GetFont());
    2689           0 :     aFont.SetShadow(false);
    2690           0 :     aFont.SetOutline(false);
    2691           0 :     aFont.SetRelief(RELIEF_NONE);
    2692           0 :     aFont.SetOrientation(0);
    2693           0 :     if( bOptimize )
    2694             :     {
    2695           0 :         aFont.SetSize( Size( 0, GLYPH_FONT_HEIGHT ) );
    2696           0 :         aVDev.SetMapMode( MAP_PIXEL );
    2697             :     }
    2698           0 :     aVDev.SetFont( aFont );
    2699           0 :     aVDev.SetTextAlign( ALIGN_TOP );
    2700           0 :     aVDev.SetTextColor( Color(COL_BLACK) );
    2701           0 :     aVDev.SetTextFillColor();
    2702             : 
    2703           0 :     pSalLayout = aVDev.ImplLayout( rStr, nIndex, nLen, Point(0,0), nLayoutWidth, pDXArray );
    2704           0 :     if (pSalLayout == 0)
    2705           0 :         return false;
    2706           0 :     long nWidth = pSalLayout->GetTextWidth();
    2707           0 :     long nHeight = ((OutputDevice*)&aVDev)->mpFontEntry->mnLineHeight + ((OutputDevice*)&aVDev)->mnEmphasisAscent
    2708           0 :         + ((OutputDevice*)&aVDev)->mnEmphasisDescent;
    2709           0 :     pSalLayout->Release();
    2710             : 
    2711           0 :     if( !nWidth || !nHeight )
    2712           0 :         return true;
    2713           0 :     double fScaleX = static_cast< double >(nOrgWidth) / nWidth;
    2714           0 :     double fScaleY = static_cast< double >(nOrgHeight) / nHeight;
    2715             : 
    2716             :     // calculate offset when nBase!=nIndex
    2717             :     // TODO: fix offset calculation for Bidi case
    2718           0 :     nXOffset = 0;
    2719           0 :     if( nBase != nIndex )
    2720             :     {
    2721           0 :         sal_Int32 nStart  = ((nBase < nIndex) ? nBase : nIndex);
    2722           0 :         sal_Int32 nLength = ((nBase > nIndex) ? nBase : nIndex) - nStart;
    2723           0 :         pSalLayout = aVDev.ImplLayout( rStr, nStart, nLength, Point(0,0), nLayoutWidth, pDXArray );
    2724           0 :         if( pSalLayout )
    2725             :         {
    2726           0 :             nXOffset = pSalLayout->GetTextWidth();
    2727           0 :             pSalLayout->Release();
    2728           0 :             if( nBase > nIndex)
    2729           0 :                 nXOffset = -nXOffset;
    2730             :         }
    2731             :     }
    2732             : 
    2733           0 :     bRet = true;
    2734           0 :     bool bRTL = false;
    2735           0 :     OUString aStr( rStr ); // prepare for e.g. localized digits
    2736           0 :     sal_Int32 nIndex2 = nIndex; // only needed until nIndex is sal_Int32
    2737           0 :     sal_Int32 nLen2 = nLen; // only needed until nLen is sal_Int32
    2738           0 :     ImplLayoutArgs aLayoutArgs = ImplPrepareLayoutArgs( aStr, nIndex2, nLen2, 0, NULL );
    2739           0 :     for( int nCharPos = -1; aLayoutArgs.GetNextPos( &nCharPos, &bRTL);)
    2740             :     {
    2741           0 :         bool bSuccess = false;
    2742             : 
    2743             :         // draw character into virtual device
    2744           0 :         pSalLayout = aVDev.ImplLayout( rStr, nCharPos, 1, Point(0,0), nLayoutWidth, pDXArray );
    2745           0 :         if (pSalLayout == 0)
    2746           0 :             return false;
    2747           0 :         long nCharWidth = pSalLayout->GetTextWidth();
    2748             : 
    2749           0 :         Point aOffset(nCharWidth / 2, 8);
    2750           0 :         Size aSize(nCharWidth + 2 * aOffset.X(), nHeight + 2 * aOffset.Y());
    2751           0 :         bSuccess = (bool)aVDev.SetOutputSizePixel(aSize);
    2752           0 :         if( bSuccess )
    2753             :         {
    2754             :             // draw glyph into virtual device
    2755           0 :             aVDev.Erase();
    2756           0 :             pSalLayout->DrawBase() += aOffset;
    2757           0 :             pSalLayout->DrawBase() += Point( ((OutputDevice*)&aVDev)->mnTextOffX, ((OutputDevice*)&aVDev)->mnTextOffY );
    2758           0 :             pSalLayout->DrawText( *((OutputDevice*)&aVDev)->mpGraphics );
    2759           0 :             pSalLayout->Release();
    2760             : 
    2761             :             // convert character image into outline
    2762           0 :             Bitmap aBmp( aVDev.GetBitmap(Point(0, 0), aSize));
    2763             : 
    2764           0 :             tools::PolyPolygon aPolyPoly;
    2765           0 :             bool bVectorized = aBmp.Vectorize(aPolyPoly, BMP_VECTORIZE_OUTER | BMP_VECTORIZE_REDUCE_EDGES);
    2766           0 :             if( !bVectorized )
    2767           0 :                 bSuccess = false;
    2768             :             else
    2769             :             {
    2770             :                 // convert units to logical width
    2771           0 :                 for (sal_uInt16 j = 0; j < aPolyPoly.Count(); ++j)
    2772             :                 {
    2773           0 :                     Polygon& rPoly = aPolyPoly[j];
    2774           0 :                     for (sal_uInt16 k = 0; k < rPoly.GetSize(); ++k)
    2775             :                     {
    2776           0 :                         Point& rPt = rPoly[k];
    2777           0 :                         rPt -= aOffset;
    2778           0 :                         int nPixelX = rPt.X() - ((OutputDevice&)aVDev).mnTextOffX + nXOffset;
    2779           0 :                         int nPixelY = rPt.Y() - ((OutputDevice&)aVDev).mnTextOffY;
    2780           0 :                         rPt.X() = ImplDevicePixelToLogicWidth( nPixelX );
    2781           0 :                         rPt.Y() = ImplDevicePixelToLogicHeight( nPixelY );
    2782             :                     }
    2783             :                 }
    2784             : 
    2785             :                 // ignore "empty" glyphs:
    2786           0 :                 if( aPolyPoly.Count() > 0 )
    2787             :                 {
    2788             :                     // convert  to B2DPolyPolygon
    2789             :                     // TODO: get rid of intermediate tool's PolyPolygon
    2790           0 :                     ::basegfx::B2DPolyPolygon aB2DPolyPoly = aPolyPoly.getB2DPolyPolygon();
    2791           0 :                     ::basegfx::B2DHomMatrix aMatrix;
    2792           0 :                     aMatrix.scale( fScaleX, fScaleY );
    2793           0 :                     int nAngle = GetFont().GetOrientation();
    2794           0 :                     if( nAngle )
    2795           0 :                         aMatrix.rotate( nAngle * F_PI1800 );
    2796           0 :                     aB2DPolyPoly.transform( aMatrix );
    2797           0 :                     rVector.push_back( aB2DPolyPoly );
    2798             :                 }
    2799           0 :             }
    2800             :         }
    2801             : 
    2802           0 :         nXOffset += nCharWidth;
    2803           0 :         bRet = bRet && bSuccess;
    2804             :     }
    2805             : 
    2806           0 :     return bRet;
    2807             : }
    2808             : 
    2809         392 : bool OutputDevice::GetTextOutlines( PolyPolyVector& rResultVector,
    2810             :                                         const OUString& rStr, sal_Int32 nBase,
    2811             :                                         sal_Int32 nIndex, sal_Int32 nLen, bool bOptimize,
    2812             :                                         sal_uLong nTWidth, const long* pDXArray ) const
    2813             : {
    2814         392 :     if(nLen == 0x0FFFF)
    2815             :     {
    2816             :         SAL_INFO("sal.rtl.xub",
    2817             :                  "GetTextOutlines Suspicious arguments  nLen:" << nLen);
    2818             :     }
    2819             : 
    2820         392 :     rResultVector.clear();
    2821             : 
    2822             :     // get the basegfx polypolygon vector
    2823         392 :     ::basegfx::B2DPolyPolygonVector aB2DPolyPolyVector;
    2824         392 :     if( !GetTextOutlines( aB2DPolyPolyVector, rStr, nBase, nIndex, nLen,
    2825         392 :                          bOptimize, nTWidth, pDXArray ) )
    2826           0 :         return false;
    2827             : 
    2828             :     // convert to a tool polypolygon vector
    2829         392 :     rResultVector.reserve( aB2DPolyPolyVector.size() );
    2830         392 :     ::basegfx::B2DPolyPolygonVector::const_iterator aIt = aB2DPolyPolyVector.begin();
    2831        2288 :     for(; aIt != aB2DPolyPolyVector.end(); ++aIt )
    2832        1896 :         rResultVector.push_back(tools::PolyPolygon(*aIt)); // #i76339#
    2833             : 
    2834         392 :     return true;
    2835             : }
    2836             : 
    2837           0 : bool OutputDevice::GetTextOutline( tools::PolyPolygon& rPolyPoly, const OUString& rStr,
    2838             :                                        sal_Int32 nBase, sal_Int32 nIndex, sal_Int32 nLen,
    2839             :                                        bool bOptimize, sal_uLong nTWidth, const long* pDXArray ) const
    2840             : {
    2841           0 :     if(nLen == 0x0FFFF)
    2842             :     {
    2843             :         SAL_INFO("sal.rtl.xub",
    2844             :                  "GetTextOutline Suspicious arguments nLen:" << nLen);
    2845             :     }
    2846           0 :     rPolyPoly.Clear();
    2847             : 
    2848             :     // get the basegfx polypolygon vector
    2849           0 :     ::basegfx::B2DPolyPolygonVector aB2DPolyPolyVector;
    2850           0 :     if( !GetTextOutlines( aB2DPolyPolyVector, rStr, nBase, nIndex, nLen,
    2851           0 :                          bOptimize, nTWidth, pDXArray ) )
    2852           0 :         return false;
    2853             : 
    2854             :     // convert and merge into a tool polypolygon
    2855           0 :     ::basegfx::B2DPolyPolygonVector::const_iterator aIt = aB2DPolyPolyVector.begin();
    2856           0 :     for(; aIt != aB2DPolyPolyVector.end(); ++aIt )
    2857           0 :         for( unsigned int i = 0; i < aIt->count(); ++i )
    2858           0 :             rPolyPoly.Insert(Polygon((*aIt).getB2DPolygon( i ))); // #i76339#
    2859             : 
    2860           0 :     return true;
    2861        1233 : }
    2862             : 
    2863             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10