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