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