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