Branch libreoffice-5-0-4
[LibreOffice.git] / canvas / source / directx / dx_textlayout_drawhelper.cxx
blobc46a49ffda255d0572deffb54bfd3b2de1f59a09
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
21 #include <tools/poly.hxx>
23 #include <vcl/metric.hxx>
24 #include <vcl/virdev.hxx>
25 #include <vcl/canvastools.hxx>
26 #include <tools/diagnose_ex.h>
28 #include <boost/scoped_array.hpp>
29 #include <boost/bind.hpp>
30 #include <com/sun/star/rendering/FontRequest.hpp>
31 #include <com/sun/star/rendering/PanoseProportion.hpp>
32 #include <com/sun/star/rendering/XCanvasFont.hpp>
33 #include <comphelper/sequence.hxx>
34 #include <comphelper/scopeguard.hxx>
35 #include <tools/color.hxx>
36 #include <basegfx/polygon/b2dpolypolygon.hxx>
37 #include <basegfx/tools/canvastools.hxx>
38 #include <canvas/canvastools.hxx>
39 #include <canvas/debug.hxx>
40 #include "dx_impltools.hxx"
41 #include <vcl/sysdata.hxx>
42 #include <i18nlangtag/languagetag.hxx>
43 #include "dx_textlayout_drawhelper.hxx"
44 #include "dx_bitmap.hxx"
45 #include "dx_canvasfont.hxx"
47 class ::com::sun::star::rendering::XCanvasFont;
49 using namespace ::com::sun::star;
54 namespace dxcanvas
56 TextLayoutDrawHelper::TextLayoutDrawHelper(
57 const uno::Reference< rendering::XGraphicDevice >& xGraphicDevice ) :
58 mxGraphicDevice(xGraphicDevice)
62 TextLayoutDrawHelper::~TextLayoutDrawHelper()
66 void TextLayoutDrawHelper::drawText(
67 const GraphicsSharedPtr& rGraphics,
68 const ::com::sun::star::rendering::ViewState& rViewState,
69 const ::com::sun::star::rendering::RenderState& rRenderState,
70 const ::basegfx::B2ISize& rOutputOffset,
71 const ::com::sun::star::rendering::StringContext& rText,
72 const ::com::sun::star::uno::Sequence< double >& rLogicalAdvancements,
73 const ::com::sun::star::uno::Reference<
74 ::com::sun::star::rendering::XCanvasFont >& rCanvasFont,
75 const ::com::sun::star::geometry::Matrix2D& rFontMatrix,
76 bool bAlphaSurface )
78 HDC hdc = rGraphics->GetHDC();
80 // issue an ReleaseHDC() when leaving the scope
81 const ::comphelper::ScopeGuard aGuard(
82 boost::bind( &Gdiplus::Graphics::ReleaseHDC,
83 rGraphics.get(),
84 hdc ));
86 SystemGraphicsData aSystemGraphicsData;
87 aSystemGraphicsData.nSize = sizeof(SystemGraphicsData);
88 aSystemGraphicsData.hDC = reinterpret_cast< ::HDC >(hdc);
89 VirtualDevice aVirtualDevice(&aSystemGraphicsData, Size(1, 1), 0);
91 // disable font antialiasing - GDI does not handle alpha
92 // surfaces properly.
93 if( bAlphaSurface )
94 aVirtualDevice.SetAntialiasing(AntialiasingFlags::DisableText);
96 if(rText.Length)
98 sal_Bool test = mxGraphicDevice.is();
99 ENSURE_OR_THROW( test,
100 "TextLayoutDrawHelper::drawText(): Invalid GraphicDevice" );
102 // set text color. Make sure to remove transparence part first.
103 Color aColor( COL_WHITE );
105 if( rRenderState.DeviceColor.getLength() > 2 )
106 aColor = vcl::unotools::doubleSequenceToColor(
107 rRenderState.DeviceColor,
108 mxGraphicDevice->getDeviceColorSpace());
109 aColor.SetTransparency(0);
110 aVirtualDevice.SetTextColor(aColor);
112 // create the font
113 const ::com::sun::star::rendering::FontRequest& rFontRequest = rCanvasFont->getFontRequest();
114 vcl::Font aFont(
115 rFontRequest.FontDescription.FamilyName,
116 rFontRequest.FontDescription.StyleName,
117 Size( 0, ::basegfx::fround(rFontRequest.CellSize)));
119 aFont.SetAlign( ALIGN_BASELINE );
120 aFont.SetCharSet( (rFontRequest.FontDescription.IsSymbolFont==com::sun::star::util::TriState_YES) ? RTL_TEXTENCODING_SYMBOL : RTL_TEXTENCODING_UNICODE );
121 aFont.SetVertical( (rFontRequest.FontDescription.IsVertical==com::sun::star::util::TriState_YES) ? sal_True : sal_False );
122 aFont.SetWeight( static_cast<FontWeight>(rFontRequest.FontDescription.FontDescription.Weight) );
123 aFont.SetItalic( (rFontRequest.FontDescription.FontDescription.Letterform<=8) ? ITALIC_NONE : ITALIC_NORMAL );
124 aFont.SetPitch(
125 rFontRequest.FontDescription.FontDescription.Proportion == rendering::PanoseProportion::MONO_SPACED
126 ? PITCH_FIXED : PITCH_VARIABLE);
128 aFont.SetLanguage(LanguageTag::convertToLanguageType(rFontRequest.Locale));
130 // setup font color
131 aFont.SetColor( aColor );
132 aFont.SetFillColor( aColor );
134 // adjust to stretched font
135 if(!::rtl::math::approxEqual(rFontMatrix.m00, rFontMatrix.m11))
137 const Size aSize = aVirtualDevice.GetFontMetric( aFont ).GetSize();
138 const double fDividend( rFontMatrix.m10 + rFontMatrix.m11 );
139 double fStretch = (rFontMatrix.m00 + rFontMatrix.m01);
141 if( !::basegfx::fTools::equalZero( fDividend) )
142 fStretch /= fDividend;
144 const sal_Int32 nNewWidth = ::basegfx::fround( aSize.Width() * fStretch );
146 aFont.SetWidth( nNewWidth );
149 // set font
150 aVirtualDevice.SetFont(aFont);
152 // create world transformation matrix
153 ::basegfx::B2DHomMatrix aWorldTransform;
154 ::canvas::tools::mergeViewAndRenderTransform(aWorldTransform, rViewState, rRenderState);
156 if(!rOutputOffset.equalZero())
158 aWorldTransform.translate(rOutputOffset.getX(), rOutputOffset.getY());
161 // set ViewState clipping
162 if(rViewState.Clip.is())
164 ::basegfx::B2DPolyPolygon aClipPoly(dxcanvas::tools::polyPolygonFromXPolyPolygon2D(rViewState.Clip));
165 ::basegfx::B2DHomMatrix aMatrix;
166 ::basegfx::unotools::homMatrixFromAffineMatrix(aMatrix, rViewState.AffineTransform );
168 if(!rOutputOffset.equalZero())
170 aMatrix.translate(rOutputOffset.getX(), rOutputOffset.getY());
173 aClipPoly.transform(aMatrix);
174 const vcl::Region& rClipRegion = vcl::Region(::tools::PolyPolygon(aClipPoly));
175 aVirtualDevice.IntersectClipRegion(rClipRegion);
178 if(rRenderState.Clip.is())
180 ::basegfx::B2DPolyPolygon aClipPoly(dxcanvas::tools::polyPolygonFromXPolyPolygon2D(rRenderState.Clip));
181 aClipPoly.transform(aWorldTransform);
182 const vcl::Region& rClipRegion = vcl::Region(::tools::PolyPolygon(aClipPoly));
183 aVirtualDevice.IntersectClipRegion(rClipRegion);
186 // set world transform
187 XFORM aXForm;
188 aXForm.eM11 = (FLOAT)aWorldTransform.get(0, 0);
189 aXForm.eM12 = (FLOAT)aWorldTransform.get(1, 0);
190 aXForm.eM21 = (FLOAT)aWorldTransform.get(0, 1);
191 aXForm.eM22 = (FLOAT)aWorldTransform.get(1, 1);
192 aXForm.eDx = (FLOAT)aWorldTransform.get(0, 2);
193 aXForm.eDy = (FLOAT)aWorldTransform.get(1, 2);
195 // TODO(F3): This is NOT supported on 95/98/ME!
196 SetGraphicsMode(hdc, GM_ADVANCED);
197 SetTextAlign(hdc, TA_BASELINE);
198 SetWorldTransform(hdc, &aXForm);
200 // use a empty StartPosition for text rendering
201 const Point aEmptyPoint(0, 0);
203 // create the String
204 const OUString aText(rText.Text);
206 if( rLogicalAdvancements.getLength() )
208 // create the DXArray
209 const sal_Int32 nLen( rLogicalAdvancements.getLength() );
210 ::boost::scoped_array<sal_Int32> pDXArray( new sal_Int32[nLen] );
211 for( sal_Int32 i=0; i<nLen; ++i )
212 pDXArray[i] = basegfx::fround( rLogicalAdvancements[i] );
214 // draw the String
215 aVirtualDevice.DrawTextArray( aEmptyPoint,
216 aText,
217 pDXArray.get(),
218 rText.StartPosition,
219 rText.Length );
221 else
223 // draw the String
224 aVirtualDevice.DrawText( aEmptyPoint,
225 aText,
226 rText.StartPosition,
227 rText.Length );
232 geometry::RealRectangle2D TextLayoutDrawHelper::queryTextBounds( const rendering::StringContext& rText,
233 const uno::Sequence< double >& rLogicalAdvancements,
234 const uno::Reference< rendering::XCanvasFont >& rCanvasFont,
235 const geometry::Matrix2D& rFontMatrix )
237 if(!(rText.Length))
238 return geometry::RealRectangle2D();
240 // TODO(F1): Fetching default screen DC here, will yield wrong
241 // metrics when e.g. formatting for a printer!
242 SystemGraphicsData aSystemGraphicsData;
243 aSystemGraphicsData.nSize = sizeof(SystemGraphicsData);
244 aSystemGraphicsData.hDC = reinterpret_cast< ::HDC >(GetDC( NULL ));
245 VirtualDevice aVirtualDevice(&aSystemGraphicsData, Size(1, 1), 0);
247 // create the font
248 const ::com::sun::star::rendering::FontRequest& rFontRequest = rCanvasFont->getFontRequest();
249 vcl::Font aFont(
250 rFontRequest.FontDescription.FamilyName,
251 rFontRequest.FontDescription.StyleName,
252 Size( 0, ::basegfx::fround(rFontRequest.CellSize)));
254 aFont.SetAlign( ALIGN_BASELINE );
255 aFont.SetCharSet( (rFontRequest.FontDescription.IsSymbolFont==com::sun::star::util::TriState_YES) ? RTL_TEXTENCODING_SYMBOL : RTL_TEXTENCODING_UNICODE );
256 aFont.SetVertical( (rFontRequest.FontDescription.IsVertical==com::sun::star::util::TriState_YES) ? sal_True : sal_False );
257 aFont.SetWeight( static_cast<FontWeight>(rFontRequest.FontDescription.FontDescription.Weight) );
258 aFont.SetItalic( (rFontRequest.FontDescription.FontDescription.Letterform<=8) ? ITALIC_NONE : ITALIC_NORMAL );
259 aFont.SetPitch(
260 rFontRequest.FontDescription.FontDescription.Proportion == rendering::PanoseProportion::MONO_SPACED
261 ? PITCH_FIXED : PITCH_VARIABLE);
263 // adjust to stretched font
264 if(!::rtl::math::approxEqual(rFontMatrix.m00, rFontMatrix.m11))
266 const Size aSize = aVirtualDevice.GetFontMetric( aFont ).GetSize();
267 const double fDividend( rFontMatrix.m10 + rFontMatrix.m11 );
268 double fStretch = (rFontMatrix.m00 + rFontMatrix.m01);
270 if( !::basegfx::fTools::equalZero( fDividend) )
271 fStretch /= fDividend;
273 const sal_Int32 nNewWidth = ::basegfx::fround( aSize.Width() * fStretch );
275 aFont.SetWidth( nNewWidth );
278 // set font
279 aVirtualDevice.SetFont(aFont);
281 // need metrics for Y offset, the XCanvas always renders
282 // relative to baseline
283 const ::FontMetric& aMetric( aVirtualDevice.GetFontMetric() );
285 const sal_Int32 nAboveBaseline( -aMetric.GetIntLeading() - aMetric.GetAscent() );
286 const sal_Int32 nBelowBaseline( aMetric.GetDescent() );
288 if( rLogicalAdvancements.getLength() )
290 return geometry::RealRectangle2D( 0, nAboveBaseline,
291 rLogicalAdvancements[ rLogicalAdvancements.getLength()-1 ],
292 nBelowBaseline );
294 else
296 return geometry::RealRectangle2D( 0, nAboveBaseline,
297 aVirtualDevice.GetTextWidth(
298 rText.Text,
299 ::canvas::tools::numeric_cast<sal_uInt16>(rText.StartPosition),
300 ::canvas::tools::numeric_cast<sal_uInt16>(rText.Length) ),
301 nBelowBaseline );
306 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */