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