1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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
;
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
,
78 HDC hdc
= rGraphics
->GetHDC();
80 // issue an ReleaseHDC() when leaving the scope
81 const ::comphelper::ScopeGuard
aGuard(
82 boost::bind( &Gdiplus::Graphics::ReleaseHDC
,
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
94 aVirtualDevice
.SetAntialiasing(AntialiasingFlags::DisableText
);
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
);
113 const ::com::sun::star::rendering::FontRequest
& rFontRequest
= rCanvasFont
->getFontRequest();
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
);
125 rFontRequest
.FontDescription
.FontDescription
.Proportion
== rendering::PanoseProportion::MONO_SPACED
126 ? PITCH_FIXED
: PITCH_VARIABLE
);
128 aFont
.SetLanguage(LanguageTag::convertToLanguageType(rFontRequest
.Locale
));
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
);
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
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);
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
] );
215 aVirtualDevice
.DrawTextArray( aEmptyPoint
,
224 aVirtualDevice
.DrawText( aEmptyPoint
,
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
)
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);
248 const ::com::sun::star::rendering::FontRequest
& rFontRequest
= rCanvasFont
->getFontRequest();
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
);
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
);
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 ],
296 return geometry::RealRectangle2D( 0, nAboveBaseline
,
297 aVirtualDevice
.GetTextWidth(
299 ::canvas::tools::numeric_cast
<sal_uInt16
>(rText
.StartPosition
),
300 ::canvas::tools::numeric_cast
<sal_uInt16
>(rText
.Length
) ),
306 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */