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