125ea7f45SAndrew Rist /************************************************************** 2cdf0e10cSrcweir * 325ea7f45SAndrew Rist * Licensed to the Apache Software Foundation (ASF) under one 425ea7f45SAndrew Rist * or more contributor license agreements. See the NOTICE file 525ea7f45SAndrew Rist * distributed with this work for additional information 625ea7f45SAndrew Rist * regarding copyright ownership. The ASF licenses this file 725ea7f45SAndrew Rist * to you under the Apache License, Version 2.0 (the 825ea7f45SAndrew Rist * "License"); you may not use this file except in compliance 925ea7f45SAndrew Rist * with the License. You may obtain a copy of the License at 1025ea7f45SAndrew Rist * 1125ea7f45SAndrew Rist * http://www.apache.org/licenses/LICENSE-2.0 1225ea7f45SAndrew Rist * 1325ea7f45SAndrew Rist * Unless required by applicable law or agreed to in writing, 1425ea7f45SAndrew Rist * software distributed under the License is distributed on an 1525ea7f45SAndrew Rist * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 1625ea7f45SAndrew Rist * KIND, either express or implied. See the License for the 1725ea7f45SAndrew Rist * specific language governing permissions and limitations 1825ea7f45SAndrew Rist * under the License. 1925ea7f45SAndrew Rist * 2025ea7f45SAndrew Rist *************************************************************/ 2125ea7f45SAndrew Rist 2225ea7f45SAndrew Rist 23cdf0e10cSrcweir 24cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove 25cdf0e10cSrcweir #include "precompiled_canvas.hxx" 26cdf0e10cSrcweir 27cdf0e10cSrcweir #include <tools/poly.hxx> 28cdf0e10cSrcweir 29cdf0e10cSrcweir #include <vcl/metric.hxx> 30cdf0e10cSrcweir #include <vcl/virdev.hxx> 31cdf0e10cSrcweir #include <vcl/metric.hxx> 32cdf0e10cSrcweir #include <vcl/canvastools.hxx> 33cdf0e10cSrcweir #include <tools/diagnose_ex.h> 34cdf0e10cSrcweir 35cdf0e10cSrcweir #include <boost/scoped_array.hpp> 36cdf0e10cSrcweir #include <boost/bind.hpp> 37cdf0e10cSrcweir #include <com/sun/star/rendering/FontRequest.hpp> 38cdf0e10cSrcweir #include <com/sun/star/rendering/PanoseProportion.hpp> 39cdf0e10cSrcweir #include <com/sun/star/rendering/XCanvasFont.hpp> 40*324ab1fcSHerbert Dürr #include <com/sun/star/rendering/TextDirection.hpp> 41cdf0e10cSrcweir #include <comphelper/sequence.hxx> 42cdf0e10cSrcweir #include <comphelper/scopeguard.hxx> 43cdf0e10cSrcweir #include <tools/color.hxx> 44cdf0e10cSrcweir #include <basegfx/polygon/b2dpolypolygon.hxx> 45cdf0e10cSrcweir #include <basegfx/tools/canvastools.hxx> 46cdf0e10cSrcweir #include <canvas/canvastools.hxx> 47cdf0e10cSrcweir #include <canvas/debug.hxx> 48cdf0e10cSrcweir #include "dx_impltools.hxx" 49cdf0e10cSrcweir #include <vcl/sysdata.hxx> 50cdf0e10cSrcweir #include <i18npool/mslangid.hxx> 51cdf0e10cSrcweir #include "dx_textlayout_drawhelper.hxx" 52cdf0e10cSrcweir #include "dx_bitmap.hxx" 53cdf0e10cSrcweir #include "dx_canvasfont.hxx" 54cdf0e10cSrcweir 55cdf0e10cSrcweir class ::com::sun::star::rendering::XCanvasFont; 56cdf0e10cSrcweir 57cdf0e10cSrcweir using namespace ::com::sun::star; 58cdf0e10cSrcweir 59cdf0e10cSrcweir 60cdf0e10cSrcweir ////////////////////////////////////////////////////////////////////////////// 61cdf0e10cSrcweir 62cdf0e10cSrcweir namespace dxcanvas 63cdf0e10cSrcweir { 64cdf0e10cSrcweir class DXBitmap; TextLayoutDrawHelper(const uno::Reference<rendering::XGraphicDevice> & xGraphicDevice)65cdf0e10cSrcweir TextLayoutDrawHelper::TextLayoutDrawHelper( 66cdf0e10cSrcweir const uno::Reference< rendering::XGraphicDevice >& xGraphicDevice ) : 67cdf0e10cSrcweir mxGraphicDevice(xGraphicDevice) 68cdf0e10cSrcweir { 69cdf0e10cSrcweir } 70cdf0e10cSrcweir ~TextLayoutDrawHelper()71cdf0e10cSrcweir TextLayoutDrawHelper::~TextLayoutDrawHelper() 72cdf0e10cSrcweir { 73cdf0e10cSrcweir } 74cdf0e10cSrcweir setupLayoutMode(VirtualDevice & rVirDev,sal_Int8 nTextDirection)75*324ab1fcSHerbert Dürr void setupLayoutMode( VirtualDevice& rVirDev, 76*324ab1fcSHerbert Dürr sal_Int8 nTextDirection ) 77*324ab1fcSHerbert Dürr { 78*324ab1fcSHerbert Dürr // TODO(P3): avoid if already correctly set 79*324ab1fcSHerbert Dürr ULONG nLayoutMode; 80*324ab1fcSHerbert Dürr switch( nTextDirection ) 81*324ab1fcSHerbert Dürr { 82*324ab1fcSHerbert Dürr default: 83*324ab1fcSHerbert Dürr nLayoutMode = 0; 84*324ab1fcSHerbert Dürr break; 85*324ab1fcSHerbert Dürr case rendering::TextDirection::WEAK_LEFT_TO_RIGHT: 86*324ab1fcSHerbert Dürr nLayoutMode = TEXT_LAYOUT_BIDI_LTR; 87*324ab1fcSHerbert Dürr break; 88*324ab1fcSHerbert Dürr case rendering::TextDirection::STRONG_LEFT_TO_RIGHT: 89*324ab1fcSHerbert Dürr nLayoutMode = TEXT_LAYOUT_BIDI_LTR | TEXT_LAYOUT_BIDI_STRONG; 90*324ab1fcSHerbert Dürr break; 91*324ab1fcSHerbert Dürr case rendering::TextDirection::WEAK_RIGHT_TO_LEFT: 92*324ab1fcSHerbert Dürr nLayoutMode = TEXT_LAYOUT_BIDI_RTL; 93*324ab1fcSHerbert Dürr break; 94*324ab1fcSHerbert Dürr case rendering::TextDirection::STRONG_RIGHT_TO_LEFT: 95*324ab1fcSHerbert Dürr nLayoutMode = TEXT_LAYOUT_BIDI_RTL | TEXT_LAYOUT_BIDI_STRONG; 96*324ab1fcSHerbert Dürr break; 97*324ab1fcSHerbert Dürr } 98*324ab1fcSHerbert Dürr 99*324ab1fcSHerbert Dürr // set calculated layout mode. Origin is always the left edge, 100*324ab1fcSHerbert Dürr // as required at the API spec 101*324ab1fcSHerbert Dürr rVirDev.SetLayoutMode( nLayoutMode | TEXT_LAYOUT_TEXTORIGIN_LEFT ); 102*324ab1fcSHerbert Dürr } 103*324ab1fcSHerbert Dürr drawText(const GraphicsSharedPtr & rGraphics,const::com::sun::star::rendering::ViewState & rViewState,const::com::sun::star::rendering::RenderState & rRenderState,const::basegfx::B2ISize & rOutputOffset,const::com::sun::star::rendering::StringContext & rText,const::com::sun::star::uno::Sequence<double> & rLogicalAdvancements,const::com::sun::star::uno::Reference<::com::sun::star::rendering::XCanvasFont> & rCanvasFont,const::com::sun::star::geometry::Matrix2D & rFontMatrix,bool bAlphaSurface,sal_Int8 nTextDirection)104cdf0e10cSrcweir void TextLayoutDrawHelper::drawText( 105cdf0e10cSrcweir const GraphicsSharedPtr& rGraphics, 106cdf0e10cSrcweir const ::com::sun::star::rendering::ViewState& rViewState, 107cdf0e10cSrcweir const ::com::sun::star::rendering::RenderState& rRenderState, 108cdf0e10cSrcweir const ::basegfx::B2ISize& rOutputOffset, 109cdf0e10cSrcweir const ::com::sun::star::rendering::StringContext& rText, 110cdf0e10cSrcweir const ::com::sun::star::uno::Sequence< double >& rLogicalAdvancements, 111cdf0e10cSrcweir const ::com::sun::star::uno::Reference< 112cdf0e10cSrcweir ::com::sun::star::rendering::XCanvasFont >& rCanvasFont, 113cdf0e10cSrcweir const ::com::sun::star::geometry::Matrix2D& rFontMatrix, 114*324ab1fcSHerbert Dürr bool bAlphaSurface, 115*324ab1fcSHerbert Dürr sal_Int8 nTextDirection) 116cdf0e10cSrcweir { 117cdf0e10cSrcweir HDC hdc = rGraphics->GetHDC(); 118cdf0e10cSrcweir 119cdf0e10cSrcweir // issue an ReleaseHDC() when leaving the scope 120cdf0e10cSrcweir const ::comphelper::ScopeGuard aGuard( 121cdf0e10cSrcweir boost::bind( &Gdiplus::Graphics::ReleaseHDC, 122cdf0e10cSrcweir rGraphics.get(), 123cdf0e10cSrcweir hdc )); 124cdf0e10cSrcweir 125cdf0e10cSrcweir SystemGraphicsData aSystemGraphicsData; 126cdf0e10cSrcweir aSystemGraphicsData.nSize = sizeof(SystemGraphicsData); 127cdf0e10cSrcweir aSystemGraphicsData.hDC = reinterpret_cast< ::HDC >(hdc); 128cdf0e10cSrcweir VirtualDevice aVirtualDevice(&aSystemGraphicsData, 0); 129cdf0e10cSrcweir 130cdf0e10cSrcweir // disable font antialiasing - GDI does not handle alpha 131cdf0e10cSrcweir // surfaces properly. 132cdf0e10cSrcweir if( bAlphaSurface ) 133cdf0e10cSrcweir aVirtualDevice.SetAntialiasing(ANTIALIASING_DISABLE_TEXT); 134cdf0e10cSrcweir 135cdf0e10cSrcweir if(rText.Length) 136cdf0e10cSrcweir { 137cdf0e10cSrcweir sal_Bool test = mxGraphicDevice.is(); 138cdf0e10cSrcweir ENSURE_OR_THROW( test, 139cdf0e10cSrcweir "TextLayoutDrawHelper::drawText(): Invalid GraphicDevice" ); 140cdf0e10cSrcweir 141cdf0e10cSrcweir // set text color. Make sure to remove transparence part first. 142cdf0e10cSrcweir Color aColor( COL_WHITE ); 143cdf0e10cSrcweir 144cdf0e10cSrcweir if( rRenderState.DeviceColor.getLength() > 2 ) 145cdf0e10cSrcweir aColor = ::vcl::unotools::doubleSequenceToColor( 146cdf0e10cSrcweir rRenderState.DeviceColor, 147cdf0e10cSrcweir mxGraphicDevice->getDeviceColorSpace()); 148cdf0e10cSrcweir aColor.SetTransparency(0); 149cdf0e10cSrcweir aVirtualDevice.SetTextColor(aColor); 150cdf0e10cSrcweir 151cdf0e10cSrcweir // create the font 152cdf0e10cSrcweir const ::com::sun::star::rendering::FontRequest& rFontRequest = rCanvasFont->getFontRequest(); 153cdf0e10cSrcweir Font aFont( 154cdf0e10cSrcweir rFontRequest.FontDescription.FamilyName, 155cdf0e10cSrcweir rFontRequest.FontDescription.StyleName, 156cdf0e10cSrcweir Size( 0, ::basegfx::fround(rFontRequest.CellSize))); 157cdf0e10cSrcweir 158cdf0e10cSrcweir aFont.SetAlign( ALIGN_BASELINE ); 159cdf0e10cSrcweir aFont.SetCharSet( (rFontRequest.FontDescription.IsSymbolFont==com::sun::star::util::TriState_YES) ? RTL_TEXTENCODING_SYMBOL : RTL_TEXTENCODING_UNICODE ); 160cdf0e10cSrcweir aFont.SetVertical( (rFontRequest.FontDescription.IsVertical==com::sun::star::util::TriState_YES) ? sal_True : sal_False ); 161cdf0e10cSrcweir aFont.SetWeight( static_cast<FontWeight>(rFontRequest.FontDescription.FontDescription.Weight) ); 162cdf0e10cSrcweir aFont.SetItalic( (rFontRequest.FontDescription.FontDescription.Letterform<=8) ? ITALIC_NONE : ITALIC_NORMAL ); 163cdf0e10cSrcweir aFont.SetPitch( 164cdf0e10cSrcweir rFontRequest.FontDescription.FontDescription.Proportion == rendering::PanoseProportion::MONO_SPACED 165cdf0e10cSrcweir ? PITCH_FIXED : PITCH_VARIABLE); 166cdf0e10cSrcweir 167cdf0e10cSrcweir aFont.SetLanguage(MsLangId::convertLocaleToLanguage(rFontRequest.Locale)); 168cdf0e10cSrcweir 169cdf0e10cSrcweir // setup font color 170cdf0e10cSrcweir aFont.SetColor( aColor ); 171cdf0e10cSrcweir aFont.SetFillColor( aColor ); 172cdf0e10cSrcweir 173cdf0e10cSrcweir // adjust to stretched font 174cdf0e10cSrcweir if(!::rtl::math::approxEqual(rFontMatrix.m00, rFontMatrix.m11)) 175cdf0e10cSrcweir { 176cdf0e10cSrcweir const Size aSize = aVirtualDevice.GetFontMetric( aFont ).GetSize(); 177cdf0e10cSrcweir const double fDividend( rFontMatrix.m10 + rFontMatrix.m11 ); 178cdf0e10cSrcweir double fStretch = (rFontMatrix.m00 + rFontMatrix.m01); 179cdf0e10cSrcweir 180cdf0e10cSrcweir if( !::basegfx::fTools::equalZero( fDividend) ) 181cdf0e10cSrcweir fStretch /= fDividend; 182cdf0e10cSrcweir 183cdf0e10cSrcweir const sal_Int32 nNewWidth = ::basegfx::fround( aSize.Width() * fStretch ); 184cdf0e10cSrcweir 185cdf0e10cSrcweir aFont.SetWidth( nNewWidth ); 186cdf0e10cSrcweir } 187cdf0e10cSrcweir 188cdf0e10cSrcweir // set font 189cdf0e10cSrcweir aVirtualDevice.SetFont(aFont); 190cdf0e10cSrcweir 191*324ab1fcSHerbert Dürr setupLayoutMode( aVirtualDevice, nTextDirection ); 192*324ab1fcSHerbert Dürr 193cdf0e10cSrcweir // create world transformation matrix 194cdf0e10cSrcweir ::basegfx::B2DHomMatrix aWorldTransform; 195cdf0e10cSrcweir ::canvas::tools::mergeViewAndRenderTransform(aWorldTransform, rViewState, rRenderState); 196cdf0e10cSrcweir 197cdf0e10cSrcweir if(!rOutputOffset.equalZero()) 198cdf0e10cSrcweir { 199cdf0e10cSrcweir aWorldTransform.translate(rOutputOffset.getX(), rOutputOffset.getY()); 200cdf0e10cSrcweir } 201cdf0e10cSrcweir 202cdf0e10cSrcweir // set ViewState clipping 203cdf0e10cSrcweir if(rViewState.Clip.is()) 204cdf0e10cSrcweir { 205cdf0e10cSrcweir ::basegfx::B2DPolyPolygon aClipPoly(dxcanvas::tools::polyPolygonFromXPolyPolygon2D(rViewState.Clip)); 206cdf0e10cSrcweir ::basegfx::B2DHomMatrix aMatrix; 207cdf0e10cSrcweir ::basegfx::unotools::homMatrixFromAffineMatrix(aMatrix, rViewState.AffineTransform ); 208cdf0e10cSrcweir 209cdf0e10cSrcweir if(!rOutputOffset.equalZero()) 210cdf0e10cSrcweir { 211cdf0e10cSrcweir aMatrix.translate(rOutputOffset.getX(), rOutputOffset.getY()); 212cdf0e10cSrcweir } 213cdf0e10cSrcweir 214cdf0e10cSrcweir aClipPoly.transform(aMatrix); 215cdf0e10cSrcweir const Region& rClipRegion = Region(PolyPolygon(aClipPoly)); 216cdf0e10cSrcweir aVirtualDevice.IntersectClipRegion(rClipRegion); 217cdf0e10cSrcweir } 218cdf0e10cSrcweir 219cdf0e10cSrcweir if(rRenderState.Clip.is()) 220cdf0e10cSrcweir { 221cdf0e10cSrcweir ::basegfx::B2DPolyPolygon aClipPoly(dxcanvas::tools::polyPolygonFromXPolyPolygon2D(rRenderState.Clip)); 222cdf0e10cSrcweir aClipPoly.transform(aWorldTransform); 223cdf0e10cSrcweir const Region& rClipRegion = Region(PolyPolygon(aClipPoly)); 224cdf0e10cSrcweir aVirtualDevice.IntersectClipRegion(rClipRegion); 225cdf0e10cSrcweir } 226cdf0e10cSrcweir 227cdf0e10cSrcweir // set world transform 228cdf0e10cSrcweir XFORM aXForm; 229cdf0e10cSrcweir aXForm.eM11 = (FLOAT)aWorldTransform.get(0, 0); 230cdf0e10cSrcweir aXForm.eM12 = (FLOAT)aWorldTransform.get(1, 0); 231cdf0e10cSrcweir aXForm.eM21 = (FLOAT)aWorldTransform.get(0, 1); 232cdf0e10cSrcweir aXForm.eM22 = (FLOAT)aWorldTransform.get(1, 1); 233cdf0e10cSrcweir aXForm.eDx = (FLOAT)aWorldTransform.get(0, 2); 234cdf0e10cSrcweir aXForm.eDy = (FLOAT)aWorldTransform.get(1, 2); 235cdf0e10cSrcweir 236cdf0e10cSrcweir // TODO(F3): This is NOT supported on 95/98/ME! 237cdf0e10cSrcweir SetGraphicsMode(hdc, GM_ADVANCED); 238cdf0e10cSrcweir SetTextAlign(hdc, TA_BASELINE); 239cdf0e10cSrcweir SetWorldTransform(hdc, &aXForm); 240cdf0e10cSrcweir 241cdf0e10cSrcweir // use a empty StartPosition for text rendering 242cdf0e10cSrcweir const Point aEmptyPoint(0, 0); 243cdf0e10cSrcweir 244cdf0e10cSrcweir // create the String 245cdf0e10cSrcweir const String aText(rText.Text.getStr()); 246cdf0e10cSrcweir 247cdf0e10cSrcweir if( rLogicalAdvancements.getLength() ) 248cdf0e10cSrcweir { 249cdf0e10cSrcweir // create the DXArray 250cdf0e10cSrcweir const sal_Int32 nLen( rLogicalAdvancements.getLength() ); 251cdf0e10cSrcweir ::boost::scoped_array<sal_Int32> pDXArray( new sal_Int32[nLen] ); 252cdf0e10cSrcweir for( sal_Int32 i=0; i<nLen; ++i ) 253cdf0e10cSrcweir pDXArray[i] = basegfx::fround( rLogicalAdvancements[i] ); 254cdf0e10cSrcweir 255cdf0e10cSrcweir // draw the String 256cdf0e10cSrcweir aVirtualDevice.DrawTextArray( aEmptyPoint, 257cdf0e10cSrcweir aText, 258cdf0e10cSrcweir pDXArray.get(), 259cdf0e10cSrcweir (xub_StrLen)rText.StartPosition, 260cdf0e10cSrcweir (xub_StrLen)rText.Length ); 261cdf0e10cSrcweir } 262cdf0e10cSrcweir else 263cdf0e10cSrcweir { 264cdf0e10cSrcweir // draw the String 265cdf0e10cSrcweir aVirtualDevice.DrawText( aEmptyPoint, 266cdf0e10cSrcweir aText, 267cdf0e10cSrcweir (xub_StrLen)rText.StartPosition, 268cdf0e10cSrcweir (xub_StrLen)rText.Length ); 269cdf0e10cSrcweir } 270cdf0e10cSrcweir } 271cdf0e10cSrcweir } 272cdf0e10cSrcweir queryTextBounds(const rendering::StringContext & rText,const uno::Sequence<double> & rLogicalAdvancements,const uno::Reference<rendering::XCanvasFont> & rCanvasFont,const geometry::Matrix2D & rFontMatrix,sal_Int8 nTextDirection)273cdf0e10cSrcweir geometry::RealRectangle2D TextLayoutDrawHelper::queryTextBounds( const rendering::StringContext& rText, 274cdf0e10cSrcweir const uno::Sequence< double >& rLogicalAdvancements, 275cdf0e10cSrcweir const uno::Reference< rendering::XCanvasFont >& rCanvasFont, 276*324ab1fcSHerbert Dürr const geometry::Matrix2D& rFontMatrix, 277*324ab1fcSHerbert Dürr sal_Int8 nTextDirection ) 278cdf0e10cSrcweir { 279cdf0e10cSrcweir if(!(rText.Length)) 280cdf0e10cSrcweir return geometry::RealRectangle2D(); 281cdf0e10cSrcweir 282cdf0e10cSrcweir // TODO(F1): Fetching default screen DC here, will yield wrong 283cdf0e10cSrcweir // metrics when e.g. formatting for a printer! 284cdf0e10cSrcweir SystemGraphicsData aSystemGraphicsData; 285cdf0e10cSrcweir aSystemGraphicsData.nSize = sizeof(SystemGraphicsData); 286cdf0e10cSrcweir aSystemGraphicsData.hDC = reinterpret_cast< ::HDC >(GetDC( NULL )); 287cdf0e10cSrcweir VirtualDevice aVirtualDevice(&aSystemGraphicsData, 0); 288cdf0e10cSrcweir 289cdf0e10cSrcweir // create the font 290cdf0e10cSrcweir const ::com::sun::star::rendering::FontRequest& rFontRequest = rCanvasFont->getFontRequest(); 291cdf0e10cSrcweir Font aFont( 292cdf0e10cSrcweir rFontRequest.FontDescription.FamilyName, 293cdf0e10cSrcweir rFontRequest.FontDescription.StyleName, 294cdf0e10cSrcweir Size( 0, ::basegfx::fround(rFontRequest.CellSize))); 295cdf0e10cSrcweir 296cdf0e10cSrcweir aFont.SetAlign( ALIGN_BASELINE ); 297cdf0e10cSrcweir aFont.SetCharSet( (rFontRequest.FontDescription.IsSymbolFont==com::sun::star::util::TriState_YES) ? RTL_TEXTENCODING_SYMBOL : RTL_TEXTENCODING_UNICODE ); 298cdf0e10cSrcweir aFont.SetVertical( (rFontRequest.FontDescription.IsVertical==com::sun::star::util::TriState_YES) ? sal_True : sal_False ); 299cdf0e10cSrcweir aFont.SetWeight( static_cast<FontWeight>(rFontRequest.FontDescription.FontDescription.Weight) ); 300cdf0e10cSrcweir aFont.SetItalic( (rFontRequest.FontDescription.FontDescription.Letterform<=8) ? ITALIC_NONE : ITALIC_NORMAL ); 301cdf0e10cSrcweir aFont.SetPitch( 302cdf0e10cSrcweir rFontRequest.FontDescription.FontDescription.Proportion == rendering::PanoseProportion::MONO_SPACED 303cdf0e10cSrcweir ? PITCH_FIXED : PITCH_VARIABLE); 304cdf0e10cSrcweir 305cdf0e10cSrcweir // adjust to stretched font 306cdf0e10cSrcweir if(!::rtl::math::approxEqual(rFontMatrix.m00, rFontMatrix.m11)) 307cdf0e10cSrcweir { 308cdf0e10cSrcweir const Size aSize = aVirtualDevice.GetFontMetric( aFont ).GetSize(); 309cdf0e10cSrcweir const double fDividend( rFontMatrix.m10 + rFontMatrix.m11 ); 310cdf0e10cSrcweir double fStretch = (rFontMatrix.m00 + rFontMatrix.m01); 311cdf0e10cSrcweir 312cdf0e10cSrcweir if( !::basegfx::fTools::equalZero( fDividend) ) 313cdf0e10cSrcweir fStretch /= fDividend; 314cdf0e10cSrcweir 315cdf0e10cSrcweir const sal_Int32 nNewWidth = ::basegfx::fround( aSize.Width() * fStretch ); 316cdf0e10cSrcweir 317cdf0e10cSrcweir aFont.SetWidth( nNewWidth ); 318cdf0e10cSrcweir } 319cdf0e10cSrcweir 320cdf0e10cSrcweir // set font 321cdf0e10cSrcweir aVirtualDevice.SetFont(aFont); 322cdf0e10cSrcweir 323*324ab1fcSHerbert Dürr setupLayoutMode( aVirtualDevice, nTextDirection ); 324*324ab1fcSHerbert Dürr 325cdf0e10cSrcweir // need metrics for Y offset, the XCanvas always renders 326cdf0e10cSrcweir // relative to baseline 327cdf0e10cSrcweir const ::FontMetric& aMetric( aVirtualDevice.GetFontMetric() ); 328cdf0e10cSrcweir 329cdf0e10cSrcweir const sal_Int32 nAboveBaseline( -aMetric.GetIntLeading() - aMetric.GetAscent() ); 330cdf0e10cSrcweir const sal_Int32 nBelowBaseline( aMetric.GetDescent() ); 331cdf0e10cSrcweir 332cdf0e10cSrcweir if( rLogicalAdvancements.getLength() ) 333cdf0e10cSrcweir { 334cdf0e10cSrcweir return geometry::RealRectangle2D( 0, nAboveBaseline, 335cdf0e10cSrcweir rLogicalAdvancements[ rLogicalAdvancements.getLength()-1 ], 336cdf0e10cSrcweir nBelowBaseline ); 337cdf0e10cSrcweir } 338cdf0e10cSrcweir else 339cdf0e10cSrcweir { 340cdf0e10cSrcweir return geometry::RealRectangle2D( 0, nAboveBaseline, 341cdf0e10cSrcweir aVirtualDevice.GetTextWidth( 342cdf0e10cSrcweir rText.Text, 343cdf0e10cSrcweir ::canvas::tools::numeric_cast<sal_uInt16>(rText.StartPosition), 344cdf0e10cSrcweir ::canvas::tools::numeric_cast<sal_uInt16>(rText.Length) ), 345cdf0e10cSrcweir nBelowBaseline ); 346cdf0e10cSrcweir } 347cdf0e10cSrcweir } 348cdf0e10cSrcweir } 349cdf0e10cSrcweir 350cdf0e10cSrcweir 351cdf0e10cSrcweir // eof 352