xref: /AOO41X/main/canvas/source/directx/dx_textlayout_drawhelper.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_canvas.hxx"
30 
31 #include <tools/poly.hxx>
32 
33 #include <vcl/metric.hxx>
34 #include <vcl/virdev.hxx>
35 #include <vcl/metric.hxx>
36 #include <vcl/canvastools.hxx>
37 #include <tools/diagnose_ex.h>
38 
39 #include <boost/scoped_array.hpp>
40 #include <boost/bind.hpp>
41 #include <com/sun/star/rendering/FontRequest.hpp>
42 #include <com/sun/star/rendering/PanoseProportion.hpp>
43 #include <com/sun/star/rendering/XCanvasFont.hpp>
44 #include <comphelper/sequence.hxx>
45 #include <comphelper/scopeguard.hxx>
46 #include <tools/color.hxx>
47 #include <basegfx/polygon/b2dpolypolygon.hxx>
48 #include <basegfx/tools/canvastools.hxx>
49 #include <canvas/canvastools.hxx>
50 #include <canvas/debug.hxx>
51 #include "dx_impltools.hxx"
52 #include <vcl/sysdata.hxx>
53 #include <i18npool/mslangid.hxx>
54 #include "dx_textlayout_drawhelper.hxx"
55 #include "dx_bitmap.hxx"
56 #include "dx_canvasfont.hxx"
57 
58 class ::com::sun::star::rendering::XCanvasFont;
59 
60 using namespace ::com::sun::star;
61 
62 
63 //////////////////////////////////////////////////////////////////////////////
64 
65 namespace dxcanvas
66 {
67 	class DXBitmap;
68 	TextLayoutDrawHelper::TextLayoutDrawHelper(
69 		const uno::Reference< rendering::XGraphicDevice >& xGraphicDevice ) :
70 			mxGraphicDevice(xGraphicDevice)
71 	{
72 	}
73 
74 	TextLayoutDrawHelper::~TextLayoutDrawHelper()
75 	{
76 	}
77 
78 	void TextLayoutDrawHelper::drawText(
79         const GraphicsSharedPtr&                            rGraphics,
80         const ::com::sun::star::rendering::ViewState& 		rViewState,
81         const ::com::sun::star::rendering::RenderState& 	rRenderState,
82         const ::basegfx::B2ISize& 							rOutputOffset,
83         const ::com::sun::star::rendering::StringContext& 	rText,
84         const ::com::sun::star::uno::Sequence< double >& 	rLogicalAdvancements,
85         const ::com::sun::star::uno::Reference<
86             ::com::sun::star::rendering::XCanvasFont >& 	rCanvasFont,
87         const ::com::sun::star::geometry::Matrix2D& 		rFontMatrix,
88         bool                                                bAlphaSurface )
89 	{
90         HDC hdc = rGraphics->GetHDC();
91 
92         // issue an ReleaseHDC() when leaving the scope
93         const ::comphelper::ScopeGuard aGuard(
94             boost::bind( &Gdiplus::Graphics::ReleaseHDC,
95                          rGraphics.get(),
96                          hdc ));
97 
98         SystemGraphicsData aSystemGraphicsData;
99         aSystemGraphicsData.nSize = sizeof(SystemGraphicsData);
100         aSystemGraphicsData.hDC = reinterpret_cast< ::HDC >(hdc);
101         VirtualDevice aVirtualDevice(&aSystemGraphicsData, 0);
102 
103         // disable font antialiasing - GDI does not handle alpha
104         // surfaces properly.
105         if( bAlphaSurface )
106 			aVirtualDevice.SetAntialiasing(ANTIALIASING_DISABLE_TEXT);
107 
108         if(rText.Length)
109         {
110 			sal_Bool test = mxGraphicDevice.is();
111             ENSURE_OR_THROW( test,
112                               "TextLayoutDrawHelper::drawText(): Invalid GraphicDevice" );
113 
114             // set text color. Make sure to remove transparence part first.
115             Color aColor( COL_WHITE );
116 
117             if( rRenderState.DeviceColor.getLength() > 2 )
118                 aColor = ::vcl::unotools::doubleSequenceToColor(
119                     rRenderState.DeviceColor,
120                     mxGraphicDevice->getDeviceColorSpace());
121             aColor.SetTransparency(0);
122             aVirtualDevice.SetTextColor(aColor);
123 
124             // create the font
125             const ::com::sun::star::rendering::FontRequest& rFontRequest = rCanvasFont->getFontRequest();
126             Font aFont(
127                 rFontRequest.FontDescription.FamilyName,
128                 rFontRequest.FontDescription.StyleName,
129                 Size( 0, ::basegfx::fround(rFontRequest.CellSize)));
130 
131             aFont.SetAlign( ALIGN_BASELINE );
132             aFont.SetCharSet( (rFontRequest.FontDescription.IsSymbolFont==com::sun::star::util::TriState_YES) ? RTL_TEXTENCODING_SYMBOL : RTL_TEXTENCODING_UNICODE );
133             aFont.SetVertical( (rFontRequest.FontDescription.IsVertical==com::sun::star::util::TriState_YES) ? sal_True : sal_False );
134             aFont.SetWeight( static_cast<FontWeight>(rFontRequest.FontDescription.FontDescription.Weight) );
135             aFont.SetItalic( (rFontRequest.FontDescription.FontDescription.Letterform<=8) ? ITALIC_NONE : ITALIC_NORMAL );
136             aFont.SetPitch(
137                     rFontRequest.FontDescription.FontDescription.Proportion == rendering::PanoseProportion::MONO_SPACED
138                     ? PITCH_FIXED : PITCH_VARIABLE);
139 
140             aFont.SetLanguage(MsLangId::convertLocaleToLanguage(rFontRequest.Locale));
141 
142             // setup font color
143             aFont.SetColor( aColor );
144             aFont.SetFillColor( aColor );
145 
146             // adjust to stretched font
147             if(!::rtl::math::approxEqual(rFontMatrix.m00, rFontMatrix.m11))
148             {
149                 const Size aSize = aVirtualDevice.GetFontMetric( aFont ).GetSize();
150                 const double fDividend( rFontMatrix.m10 + rFontMatrix.m11 );
151                 double fStretch = (rFontMatrix.m00 + rFontMatrix.m01);
152 
153                 if( !::basegfx::fTools::equalZero( fDividend) )
154                     fStretch /= fDividend;
155 
156                 const sal_Int32 nNewWidth = ::basegfx::fround( aSize.Width() * fStretch );
157 
158                 aFont.SetWidth( nNewWidth );
159             }
160 
161             // set font
162             aVirtualDevice.SetFont(aFont);
163 
164             // create world transformation matrix
165             ::basegfx::B2DHomMatrix aWorldTransform;
166             ::canvas::tools::mergeViewAndRenderTransform(aWorldTransform, rViewState, rRenderState);
167 
168             if(!rOutputOffset.equalZero())
169             {
170                 aWorldTransform.translate(rOutputOffset.getX(), rOutputOffset.getY());
171             }
172 
173             // set ViewState clipping
174             if(rViewState.Clip.is())
175             {
176                 ::basegfx::B2DPolyPolygon aClipPoly(dxcanvas::tools::polyPolygonFromXPolyPolygon2D(rViewState.Clip));
177                 ::basegfx::B2DHomMatrix aMatrix;
178                 ::basegfx::unotools::homMatrixFromAffineMatrix(aMatrix, rViewState.AffineTransform );
179 
180                 if(!rOutputOffset.equalZero())
181                 {
182                     aMatrix.translate(rOutputOffset.getX(), rOutputOffset.getY());
183                 }
184 
185                 aClipPoly.transform(aMatrix);
186                 const Region& rClipRegion = Region(PolyPolygon(aClipPoly));
187                 aVirtualDevice.IntersectClipRegion(rClipRegion);
188             }
189 
190             if(rRenderState.Clip.is())
191             {
192                 ::basegfx::B2DPolyPolygon aClipPoly(dxcanvas::tools::polyPolygonFromXPolyPolygon2D(rRenderState.Clip));
193                 aClipPoly.transform(aWorldTransform);
194                 const Region& rClipRegion = Region(PolyPolygon(aClipPoly));
195                 aVirtualDevice.IntersectClipRegion(rClipRegion);
196             }
197 
198             // set world transform
199             XFORM aXForm;
200             aXForm.eM11 = (FLOAT)aWorldTransform.get(0, 0);
201             aXForm.eM12 = (FLOAT)aWorldTransform.get(1, 0);
202             aXForm.eM21 = (FLOAT)aWorldTransform.get(0, 1);
203             aXForm.eM22 = (FLOAT)aWorldTransform.get(1, 1);
204             aXForm.eDx = (FLOAT)aWorldTransform.get(0, 2);
205             aXForm.eDy = (FLOAT)aWorldTransform.get(1, 2);
206 
207             // TODO(F3): This is NOT supported on 95/98/ME!
208             SetGraphicsMode(hdc, GM_ADVANCED);
209             SetTextAlign(hdc, TA_BASELINE);
210             SetWorldTransform(hdc, &aXForm);
211 
212             // use a empty StartPosition for text rendering
213             const Point aEmptyPoint(0, 0);
214 
215             // create the String
216             const String aText(rText.Text.getStr());
217 
218             if( rLogicalAdvancements.getLength() )
219             {
220                 // create the DXArray
221                 const sal_Int32 nLen( rLogicalAdvancements.getLength() );
222                 ::boost::scoped_array<sal_Int32> pDXArray( new sal_Int32[nLen] );
223                 for( sal_Int32 i=0; i<nLen; ++i )
224                     pDXArray[i] = basegfx::fround( rLogicalAdvancements[i] );
225 
226                 // draw the String
227                 aVirtualDevice.DrawTextArray( aEmptyPoint,
228                                               aText,
229                                               pDXArray.get(),
230                                               (xub_StrLen)rText.StartPosition,
231                                               (xub_StrLen)rText.Length );
232             }
233             else
234             {
235                 // draw the String
236                 aVirtualDevice.DrawText( aEmptyPoint,
237                                          aText,
238                                          (xub_StrLen)rText.StartPosition,
239                                          (xub_StrLen)rText.Length );
240             }
241         }
242 	}
243 
244 	geometry::RealRectangle2D TextLayoutDrawHelper::queryTextBounds( const rendering::StringContext& 					rText,
245                                                                      const uno::Sequence< double >& 					rLogicalAdvancements,
246                                                                      const uno::Reference< rendering::XCanvasFont >&	rCanvasFont,
247                                                                      const geometry::Matrix2D& 							rFontMatrix )
248 	{
249 		if(!(rText.Length))
250             return geometry::RealRectangle2D();
251 
252         // TODO(F1): Fetching default screen DC here, will yield wrong
253         // metrics when e.g. formatting for a printer!
254 		SystemGraphicsData aSystemGraphicsData;
255 		aSystemGraphicsData.nSize = sizeof(SystemGraphicsData);
256 		aSystemGraphicsData.hDC = reinterpret_cast< ::HDC >(GetDC( NULL ));
257 		VirtualDevice aVirtualDevice(&aSystemGraphicsData, 0);
258 
259         // create the font
260         const ::com::sun::star::rendering::FontRequest& rFontRequest = rCanvasFont->getFontRequest();
261         Font aFont(
262             rFontRequest.FontDescription.FamilyName,
263             rFontRequest.FontDescription.StyleName,
264             Size( 0, ::basegfx::fround(rFontRequest.CellSize)));
265 
266         aFont.SetAlign( ALIGN_BASELINE );
267         aFont.SetCharSet( (rFontRequest.FontDescription.IsSymbolFont==com::sun::star::util::TriState_YES) ? RTL_TEXTENCODING_SYMBOL : RTL_TEXTENCODING_UNICODE );
268         aFont.SetVertical( (rFontRequest.FontDescription.IsVertical==com::sun::star::util::TriState_YES) ? sal_True : sal_False );
269         aFont.SetWeight( static_cast<FontWeight>(rFontRequest.FontDescription.FontDescription.Weight) );
270         aFont.SetItalic( (rFontRequest.FontDescription.FontDescription.Letterform<=8) ? ITALIC_NONE : ITALIC_NORMAL );
271         aFont.SetPitch(
272                 rFontRequest.FontDescription.FontDescription.Proportion == rendering::PanoseProportion::MONO_SPACED
273                 ? PITCH_FIXED : PITCH_VARIABLE);
274 
275         // adjust to stretched font
276         if(!::rtl::math::approxEqual(rFontMatrix.m00, rFontMatrix.m11))
277         {
278             const Size aSize = aVirtualDevice.GetFontMetric( aFont ).GetSize();
279             const double fDividend( rFontMatrix.m10 + rFontMatrix.m11 );
280             double fStretch = (rFontMatrix.m00 + rFontMatrix.m01);
281 
282             if( !::basegfx::fTools::equalZero( fDividend) )
283                 fStretch /= fDividend;
284 
285             const sal_Int32 nNewWidth = ::basegfx::fround( aSize.Width() * fStretch );
286 
287             aFont.SetWidth( nNewWidth );
288         }
289 
290         // set font
291         aVirtualDevice.SetFont(aFont);
292 
293         // need metrics for Y offset, the XCanvas always renders
294         // relative to baseline
295         const ::FontMetric& aMetric( aVirtualDevice.GetFontMetric() );
296 
297         const sal_Int32 nAboveBaseline( -aMetric.GetIntLeading() - aMetric.GetAscent() );
298         const sal_Int32 nBelowBaseline( aMetric.GetDescent() );
299 
300         if( rLogicalAdvancements.getLength() )
301         {
302             return geometry::RealRectangle2D( 0, nAboveBaseline,
303                                               rLogicalAdvancements[ rLogicalAdvancements.getLength()-1 ],
304                                               nBelowBaseline );
305         }
306         else
307         {
308             return geometry::RealRectangle2D( 0, nAboveBaseline,
309                                               aVirtualDevice.GetTextWidth(
310                                                   rText.Text,
311                                                   ::canvas::tools::numeric_cast<sal_uInt16>(rText.StartPosition),
312                                                   ::canvas::tools::numeric_cast<sal_uInt16>(rText.Length) ),
313                                               nBelowBaseline );
314         }
315 	}
316 }
317 
318 
319 // eof
320