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