1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: dx_textlayout_drawhelper.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_canvas.hxx"
34 #include <tools/poly.hxx>
36 #include <vcl/metric.hxx>
37 #include <vcl/virdev.hxx>
38 #include <vcl/metric.hxx>
39 #include <vcl/canvastools.hxx>
40 #include <tools/diagnose_ex.h>
42 #include <boost/scoped_array.hpp>
43 #include <boost/bind.hpp>
44 #include <com/sun/star/rendering/FontRequest.hpp>
45 #include <com/sun/star/rendering/XCanvasFont.hpp>
46 #include <comphelper/sequence.hxx>
47 #include <comphelper/scopeguard.hxx>
48 #include <tools/color.hxx>
49 #include <basegfx/polygon/b2dpolypolygon.hxx>
50 #include <basegfx/tools/canvastools.hxx>
51 #include <canvas/canvastools.hxx>
52 #include <canvas/debug.hxx>
53 #include "dx_impltools.hxx"
54 #include <vcl/sysdata.hxx>
55 #include <i18npool/mslangid.hxx>
56 #include "dx_textlayout_drawhelper.hxx"
57 #include "dx_bitmap.hxx"
58 #include "dx_canvasfont.hxx"
60 class ::com::sun::star::rendering::XCanvasFont
;
62 using namespace ::com::sun::star
;
65 //////////////////////////////////////////////////////////////////////////////
70 TextLayoutDrawHelper::TextLayoutDrawHelper(
71 const uno::Reference
< rendering::XGraphicDevice
>& xGraphicDevice
) :
72 mxGraphicDevice(xGraphicDevice
)
76 TextLayoutDrawHelper::~TextLayoutDrawHelper()
80 void TextLayoutDrawHelper::drawText(
81 const GraphicsSharedPtr
& rGraphics
,
82 const ::com::sun::star::rendering::ViewState
& rViewState
,
83 const ::com::sun::star::rendering::RenderState
& rRenderState
,
84 const ::basegfx::B2ISize
& rOutputOffset
,
85 const ::com::sun::star::rendering::StringContext
& rText
,
86 const ::com::sun::star::uno::Sequence
< double >& rLogicalAdvancements
,
87 const ::com::sun::star::uno::Reference
<
88 ::com::sun::star::rendering::XCanvasFont
>& rCanvasFont
,
89 const ::com::sun::star::geometry::Matrix2D
& rFontMatrix
,
92 HDC hdc
= rGraphics
->GetHDC();
94 // issue an ReleaseHDC() when leaving the scope
95 const ::comphelper::ScopeGuard
aGuard(
96 boost::bind( &Gdiplus::Graphics::ReleaseHDC
,
100 SystemGraphicsData aSystemGraphicsData
;
101 aSystemGraphicsData
.nSize
= sizeof(SystemGraphicsData
);
102 aSystemGraphicsData
.hDC
= reinterpret_cast< ::HDC
>(hdc
);
103 VirtualDevice
aVirtualDevice(&aSystemGraphicsData
, 0);
105 // disable font antialiasing - GDI does not handle alpha
106 // surfaces properly.
108 aVirtualDevice
.SetAntialiasing(ANTIALIASING_DISABLE_TEXT
);
112 sal_Bool test
= mxGraphicDevice
.is();
113 ENSURE_OR_THROW( test
,
114 "TextLayoutDrawHelper::drawText(): Invalid GraphicDevice" );
116 // set text color. Make sure to remove transparence part first.
117 Color
aColor( COL_WHITE
);
119 if( rRenderState
.DeviceColor
.getLength() > 2 )
120 aColor
= ::vcl::unotools::doubleSequenceToColor(
121 rRenderState
.DeviceColor
,
122 mxGraphicDevice
->getDeviceColorSpace());
123 aColor
.SetTransparency(0);
124 aVirtualDevice
.SetTextColor(aColor
);
127 const ::com::sun::star::rendering::FontRequest
& rFontRequest
= rCanvasFont
->getFontRequest();
129 rFontRequest
.FontDescription
.FamilyName
,
130 rFontRequest
.FontDescription
.StyleName
,
131 Size( 0, ::basegfx::fround(rFontRequest
.CellSize
)));
133 aFont
.SetAlign( ALIGN_BASELINE
);
134 aFont
.SetCharSet( (rFontRequest
.FontDescription
.IsSymbolFont
==com::sun::star::util::TriState_YES
) ? RTL_TEXTENCODING_SYMBOL
: RTL_TEXTENCODING_UNICODE
);
135 aFont
.SetVertical( (rFontRequest
.FontDescription
.IsVertical
==com::sun::star::util::TriState_YES
) ? TRUE
: FALSE
);
136 aFont
.SetWeight( static_cast<FontWeight
>(rFontRequest
.FontDescription
.FontDescription
.Weight
) );
137 aFont
.SetItalic( (rFontRequest
.FontDescription
.FontDescription
.Letterform
<=8) ? ITALIC_NONE
: ITALIC_NORMAL
);
139 aFont
.SetLanguage(MsLangId::convertLocaleToLanguage(rFontRequest
.Locale
));
142 aFont
.SetColor( aColor
);
143 aFont
.SetFillColor( aColor
);
145 // adjust to stretched font
146 if(!::rtl::math::approxEqual(rFontMatrix
.m00
, rFontMatrix
.m11
))
148 const Size aSize
= aVirtualDevice
.GetFontMetric( aFont
).GetSize();
149 const double fDividend( rFontMatrix
.m10
+ rFontMatrix
.m11
);
150 double fStretch
= (rFontMatrix
.m00
+ rFontMatrix
.m01
);
152 if( !::basegfx::fTools::equalZero( fDividend
) )
153 fStretch
/= fDividend
;
155 const sal_Int32 nNewWidth
= ::basegfx::fround( aSize
.Width() * fStretch
);
157 aFont
.SetWidth( nNewWidth
);
161 aVirtualDevice
.SetFont(aFont
);
163 // create world transformation matrix
164 ::basegfx::B2DHomMatrix aWorldTransform
;
165 ::canvas::tools::mergeViewAndRenderTransform(aWorldTransform
, rViewState
, rRenderState
);
167 if(!rOutputOffset
.equalZero())
169 aWorldTransform
.translate(rOutputOffset
.getX(), rOutputOffset
.getY());
172 // set ViewState clipping
173 if(rViewState
.Clip
.is())
175 ::basegfx::B2DPolyPolygon
aClipPoly(dxcanvas::tools::polyPolygonFromXPolyPolygon2D(rViewState
.Clip
));
176 ::basegfx::B2DHomMatrix aMatrix
;
177 ::basegfx::unotools::homMatrixFromAffineMatrix(aMatrix
, rViewState
.AffineTransform
);
179 if(!rOutputOffset
.equalZero())
181 aMatrix
.translate(rOutputOffset
.getX(), rOutputOffset
.getY());
184 aClipPoly
.transform(aMatrix
);
185 const Region
& rClipRegion
= Region(PolyPolygon(aClipPoly
));
186 aVirtualDevice
.IntersectClipRegion(rClipRegion
);
189 if(rRenderState
.Clip
.is())
191 ::basegfx::B2DPolyPolygon
aClipPoly(dxcanvas::tools::polyPolygonFromXPolyPolygon2D(rRenderState
.Clip
));
192 aClipPoly
.transform(aWorldTransform
);
193 const Region
& rClipRegion
= Region(PolyPolygon(aClipPoly
));
194 aVirtualDevice
.IntersectClipRegion(rClipRegion
);
197 // set world transform
199 aXForm
.eM11
= (FLOAT
)aWorldTransform
.get(0, 0);
200 aXForm
.eM12
= (FLOAT
)aWorldTransform
.get(1, 0);
201 aXForm
.eM21
= (FLOAT
)aWorldTransform
.get(0, 1);
202 aXForm
.eM22
= (FLOAT
)aWorldTransform
.get(1, 1);
203 aXForm
.eDx
= (FLOAT
)aWorldTransform
.get(0, 2);
204 aXForm
.eDy
= (FLOAT
)aWorldTransform
.get(1, 2);
206 // TODO(F3): This is NOT supported on 95/98/ME!
207 SetGraphicsMode(hdc
, GM_ADVANCED
);
208 SetTextAlign(hdc
, TA_BASELINE
);
209 SetWorldTransform(hdc
, &aXForm
);
211 // use a empty StartPosition for text rendering
212 const Point
aEmptyPoint(0, 0);
215 const String
aText(rText
.Text
.getStr());
217 if( rLogicalAdvancements
.getLength() )
219 // create the DXArray
220 const sal_Int32
nLen( rLogicalAdvancements
.getLength() );
221 ::boost::scoped_array
<sal_Int32
> pDXArray( new sal_Int32
[nLen
] );
222 for( sal_Int32 i
=0; i
<nLen
; ++i
)
223 pDXArray
[i
] = basegfx::fround( rLogicalAdvancements
[i
] );
226 aVirtualDevice
.DrawTextArray( aEmptyPoint
,
229 (xub_StrLen
)rText
.StartPosition
,
230 (xub_StrLen
)rText
.Length
);
235 aVirtualDevice
.DrawText( aEmptyPoint
,
237 (xub_StrLen
)rText
.StartPosition
,
238 (xub_StrLen
)rText
.Length
);
243 geometry::RealRectangle2D
TextLayoutDrawHelper::queryTextBounds( const rendering::StringContext
& rText
,
244 const uno::Sequence
< double >& rLogicalAdvancements
,
245 const uno::Reference
< rendering::XCanvasFont
>& rCanvasFont
,
246 const geometry::Matrix2D
& rFontMatrix
)
249 return geometry::RealRectangle2D();
251 // TODO(F1): Fetching default screen DC here, will yield wrong
252 // metrics when e.g. formatting for a printer!
253 SystemGraphicsData aSystemGraphicsData
;
254 aSystemGraphicsData
.nSize
= sizeof(SystemGraphicsData
);
255 aSystemGraphicsData
.hDC
= reinterpret_cast< ::HDC
>(GetDC( NULL
));
256 VirtualDevice
aVirtualDevice(&aSystemGraphicsData
, 0);
259 const ::com::sun::star::rendering::FontRequest
& rFontRequest
= rCanvasFont
->getFontRequest();
261 rFontRequest
.FontDescription
.FamilyName
,
262 rFontRequest
.FontDescription
.StyleName
,
263 Size( 0, ::basegfx::fround(rFontRequest
.CellSize
)));
265 aFont
.SetAlign( ALIGN_BASELINE
);
266 aFont
.SetCharSet( (rFontRequest
.FontDescription
.IsSymbolFont
==com::sun::star::util::TriState_YES
) ? RTL_TEXTENCODING_SYMBOL
: RTL_TEXTENCODING_UNICODE
);
267 aFont
.SetVertical( (rFontRequest
.FontDescription
.IsVertical
==com::sun::star::util::TriState_YES
) ? TRUE
: FALSE
);
268 aFont
.SetWeight( static_cast<FontWeight
>(rFontRequest
.FontDescription
.FontDescription
.Weight
) );
269 aFont
.SetItalic( (rFontRequest
.FontDescription
.FontDescription
.Letterform
<=8) ? ITALIC_NONE
: ITALIC_NORMAL
);
271 // adjust to stretched font
272 if(!::rtl::math::approxEqual(rFontMatrix
.m00
, rFontMatrix
.m11
))
274 const Size aSize
= aVirtualDevice
.GetFontMetric( aFont
).GetSize();
275 const double fDividend( rFontMatrix
.m10
+ rFontMatrix
.m11
);
276 double fStretch
= (rFontMatrix
.m00
+ rFontMatrix
.m01
);
278 if( !::basegfx::fTools::equalZero( fDividend
) )
279 fStretch
/= fDividend
;
281 const sal_Int32 nNewWidth
= ::basegfx::fround( aSize
.Width() * fStretch
);
283 aFont
.SetWidth( nNewWidth
);
287 aVirtualDevice
.SetFont(aFont
);
289 // need metrics for Y offset, the XCanvas always renders
290 // relative to baseline
291 const ::FontMetric
& aMetric( aVirtualDevice
.GetFontMetric() );
293 const sal_Int32
nAboveBaseline( -aMetric
.GetIntLeading() - aMetric
.GetAscent() );
294 const sal_Int32
nBelowBaseline( aMetric
.GetDescent() );
296 if( rLogicalAdvancements
.getLength() )
298 return geometry::RealRectangle2D( 0, nAboveBaseline
,
299 rLogicalAdvancements
[ rLogicalAdvancements
.getLength()-1 ],
304 return geometry::RealRectangle2D( 0, nAboveBaseline
,
305 aVirtualDevice
.GetTextWidth(
307 ::canvas::tools::numeric_cast
<USHORT
>(rText
.StartPosition
),
308 ::canvas::tools::numeric_cast
<USHORT
>(rText
.Length
) ),