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 <ctype.h> // don't ask. msdev breaks otherwise... 28 #include <basegfx/numeric/ftools.hxx> 29 30 #include <canvas/debug.hxx> 31 #include <canvas/verbosetrace.hxx> 32 #include <tools/diagnose_ex.h> 33 34 #include <com/sun/star/lang/XServiceInfo.hpp> 35 #include <com/sun/star/lang/XUnoTunnel.hpp> 36 #include <com/sun/star/geometry/RealPoint2D.hpp> 37 #include <com/sun/star/geometry/IntegerRectangle2D.hpp> 38 39 #include <basegfx/matrix/b2dhommatrix.hxx> 40 #include <basegfx/range/b2irectangle.hxx> 41 #include <basegfx/range/b2drectangle.hxx> 42 #include <basegfx/polygon/b2dpolygon.hxx> 43 #include <basegfx/polygon/b2dpolypolygon.hxx> 44 #include <basegfx/tools/canvastools.hxx> 45 46 #include <canvas/canvastools.hxx> 47 #include <canvas/verifyinput.hxx> 48 49 #include "dx_impltools.hxx" 50 #include "dx_vcltools.hxx" 51 #include "dx_linepolypolygon.hxx" 52 #include "dx_canvasbitmap.hxx" 53 #include "dx_canvasfont.hxx" 54 #include "dx_canvas.hxx" 55 #include "dx_spritecanvas.hxx" 56 57 #include <boost/scoped_array.hpp> 58 59 #include <vector> 60 #include <algorithm> 61 62 63 using namespace ::com::sun::star; 64 65 66 namespace dxcanvas 67 { 68 namespace tools 69 { polyPolygonFromXPolyPolygon2D(const uno::Reference<rendering::XPolyPolygon2D> & xPoly)70 ::basegfx::B2DPolyPolygon polyPolygonFromXPolyPolygon2D( const uno::Reference< rendering::XPolyPolygon2D >& xPoly ) 71 { 72 LinePolyPolygon* pPolyImpl = dynamic_cast< LinePolyPolygon* >( xPoly.get() ); 73 74 if( pPolyImpl ) 75 { 76 return pPolyImpl->getPolyPolygon(); 77 } 78 else 79 { 80 const sal_Int32 nPolys( xPoly->getNumberOfPolygons() ); 81 82 // not a known implementation object - try data source 83 // interfaces 84 uno::Reference< rendering::XBezierPolyPolygon2D > xBezierPoly( 85 xPoly, 86 uno::UNO_QUERY ); 87 88 if( xBezierPoly.is() ) 89 { 90 return ::basegfx::unotools::polyPolygonFromBezier2DSequenceSequence( 91 xBezierPoly->getBezierSegments( 0, 92 nPolys, 93 0, 94 -1 ) ); 95 } 96 else 97 { 98 uno::Reference< rendering::XLinePolyPolygon2D > xLinePoly( 99 xPoly, 100 uno::UNO_QUERY ); 101 102 // no implementation class and no data provider 103 // found - contract violation. 104 ENSURE_ARG_OR_THROW( xLinePoly.is(), 105 "VCLCanvas::polyPolygonFromXPolyPolygon2D(): Invalid input " 106 "poly-polygon, cannot retrieve vertex data" ); 107 108 return ::basegfx::unotools::polyPolygonFromPoint2DSequenceSequence( 109 xLinePoly->getPoints( 0, 110 nPolys, 111 0, 112 -1 ) ); 113 } 114 } 115 } 116 setupGraphics(Gdiplus::Graphics & rGraphics)117 void setupGraphics( Gdiplus::Graphics& rGraphics ) 118 { 119 // setup graphics with (somewhat arbitrary) defaults 120 //rGraphics.SetCompositingQuality( Gdiplus::CompositingQualityHighQuality ); 121 rGraphics.SetCompositingQuality( Gdiplus::CompositingQualityHighSpeed ); 122 //rGraphics.SetInterpolationMode( Gdiplus::InterpolationModeHighQualityBilinear ); // with prefiltering for shrinks 123 rGraphics.SetInterpolationMode( Gdiplus::InterpolationModeBilinear ); 124 125 // #122683# Switched precedence of pixel offset 126 // mode. Seemingly, polygon stroking needs 127 // PixelOffsetModeNone to achieve visually pleasing 128 // results, whereas all other operations (e.g. polygon 129 // fills, bitmaps) look better with PixelOffsetModeHalf. 130 rGraphics.SetPixelOffsetMode( Gdiplus::PixelOffsetModeHalf ); // Pixel center at (0.5, 0.5) etc. 131 //rGraphics.SetPixelOffsetMode( Gdiplus::PixelOffsetModeNone ); 132 133 //rGraphics.SetSmoothingMode( Gdiplus::SmoothingModeHighSpeed ); // no line/curve antialiasing 134 //rGraphics.SetSmoothingMode( Gdiplus::SmoothingModeHighQuality ); 135 rGraphics.SetSmoothingMode( Gdiplus::SmoothingModeAntiAlias ); 136 //rGraphics.SetTextRenderingHint( Gdiplus::TextRenderingHintAntiAlias ); 137 rGraphics.SetTextRenderingHint( Gdiplus::TextRenderingHintSystemDefault ); 138 rGraphics.SetPageUnit(Gdiplus::UnitPixel); 139 } 140 createGraphicsFromHDC(HDC aHDC)141 Gdiplus::Graphics* createGraphicsFromHDC(HDC aHDC) 142 { 143 Gdiplus::Graphics* pRet = new Gdiplus::Graphics(aHDC); 144 if( pRet ) 145 setupGraphics( *pRet ); 146 return pRet; 147 } 148 createGraphicsFromBitmap(const BitmapSharedPtr & rBitmap)149 Gdiplus::Graphics* createGraphicsFromBitmap(const BitmapSharedPtr& rBitmap) 150 { 151 Gdiplus::Graphics* pRet = Gdiplus::Graphics::FromImage(rBitmap.get()); 152 if( pRet ) 153 setupGraphics( *pRet ); 154 return pRet; 155 } 156 gdiPlusMatrixFromB2DHomMatrix(Gdiplus::Matrix & rGdiplusMatrix,const::basegfx::B2DHomMatrix & rMatrix)157 void gdiPlusMatrixFromB2DHomMatrix( Gdiplus::Matrix& rGdiplusMatrix, const ::basegfx::B2DHomMatrix& rMatrix ) 158 { 159 rGdiplusMatrix.SetElements( static_cast<Gdiplus::REAL>(rMatrix.get(0,0)), 160 static_cast<Gdiplus::REAL>(rMatrix.get(1,0)), 161 static_cast<Gdiplus::REAL>(rMatrix.get(0,1)), 162 static_cast<Gdiplus::REAL>(rMatrix.get(1,1)), 163 static_cast<Gdiplus::REAL>(rMatrix.get(0,2)), 164 static_cast<Gdiplus::REAL>(rMatrix.get(1,2)) ); 165 } 166 gdiPlusMatrixFromAffineMatrix2D(Gdiplus::Matrix & rGdiplusMatrix,const geometry::AffineMatrix2D & rMatrix)167 void gdiPlusMatrixFromAffineMatrix2D( Gdiplus::Matrix& rGdiplusMatrix, 168 const geometry::AffineMatrix2D& rMatrix ) 169 { 170 rGdiplusMatrix.SetElements( static_cast<Gdiplus::REAL>(rMatrix.m00), 171 static_cast<Gdiplus::REAL>(rMatrix.m10), 172 static_cast<Gdiplus::REAL>(rMatrix.m01), 173 static_cast<Gdiplus::REAL>(rMatrix.m11), 174 static_cast<Gdiplus::REAL>(rMatrix.m02), 175 static_cast<Gdiplus::REAL>(rMatrix.m12) ); 176 } 177 178 namespace 179 { 180 // TODO(P2): Check whether this gets inlined. If not, make functor 181 // out of it implGdiPlusPointFromRealPoint2D(const::com::sun::star::geometry::RealPoint2D & rPoint)182 inline Gdiplus::PointF implGdiPlusPointFromRealPoint2D( const ::com::sun::star::geometry::RealPoint2D& rPoint ) 183 { 184 return Gdiplus::PointF( static_cast<Gdiplus::REAL>(rPoint.X), 185 static_cast<Gdiplus::REAL>(rPoint.Y) ); 186 } 187 graphicsPathFromB2DPolygon(GraphicsPathSharedPtr & rOutput,::std::vector<Gdiplus::PointF> & rPoints,const::basegfx::B2DPolygon & rPoly,bool bNoLineJoin)188 void graphicsPathFromB2DPolygon( GraphicsPathSharedPtr& rOutput, 189 ::std::vector< Gdiplus::PointF >& rPoints, 190 const ::basegfx::B2DPolygon& rPoly, 191 bool bNoLineJoin) 192 { 193 const sal_uInt32 nPoints( rPoly.count() ); 194 195 if( nPoints < 2 ) 196 return; 197 198 rOutput->StartFigure(); 199 200 const bool bClosedPolygon( rPoly.isClosed() ); 201 202 if( rPoly.areControlPointsUsed() ) 203 { 204 // control points used -> for now, add all 205 // segments as curves to GraphicsPath 206 207 // If the polygon is closed, we need to add the 208 // first point, thus, one more (can't simply 209 // GraphicsPath::CloseFigure() it, since the last 210 // point cannot have any control points for GDI+) 211 rPoints.resize( 3*nPoints + bClosedPolygon ); 212 213 sal_uInt32 nCurrOutput=0; 214 for( sal_uInt32 nCurrPoint=0; nCurrPoint<nPoints; ++nCurrPoint ) 215 { 216 const ::basegfx::B2DPoint& rPoint( rPoly.getB2DPoint( nCurrPoint ) ); 217 rPoints[nCurrOutput++] = Gdiplus::PointF( static_cast<Gdiplus::REAL>(rPoint.getX()), 218 static_cast<Gdiplus::REAL>(rPoint.getY()) ); 219 220 const ::basegfx::B2DPoint& rControlPointA( rPoly.getNextControlPoint( nCurrPoint ) ); 221 rPoints[nCurrOutput++] = Gdiplus::PointF( static_cast<Gdiplus::REAL>(rControlPointA.getX()), 222 static_cast<Gdiplus::REAL>(rControlPointA.getY()) ); 223 224 const ::basegfx::B2DPoint& rControlPointB( rPoly.getPrevControlPoint( (nCurrPoint + 1) % nPoints) ); 225 rPoints[nCurrOutput++] = Gdiplus::PointF( static_cast<Gdiplus::REAL>(rControlPointB.getX()), 226 static_cast<Gdiplus::REAL>(rControlPointB.getY()) ); 227 } 228 229 if( bClosedPolygon ) 230 { 231 // add first point again (to be able to pass 232 // control points for the last point, see 233 // above) 234 const ::basegfx::B2DPoint& rPoint( rPoly.getB2DPoint(0) ); 235 rPoints[nCurrOutput++] = Gdiplus::PointF( static_cast<Gdiplus::REAL>(rPoint.getX()), 236 static_cast<Gdiplus::REAL>(rPoint.getY()) ); 237 238 if(bNoLineJoin && nCurrOutput > 7) 239 { 240 for(sal_uInt32 a(3); a < nCurrOutput; a+=3) 241 { 242 rOutput->StartFigure(); 243 rOutput->AddBezier(rPoints[a - 3], rPoints[a - 2], rPoints[a - 1], rPoints[a]); 244 } 245 } 246 else 247 { 248 rOutput->AddBeziers( &rPoints[0], nCurrOutput ); 249 } 250 } 251 else 252 { 253 // GraphicsPath expects 3(n-1)+1 points (i.e. the 254 // last point must not have any trailing control 255 // points after it). 256 // Therefore, simply don't pass the last two 257 // points here. 258 if( nCurrOutput > 3 ) 259 { 260 if(bNoLineJoin && nCurrOutput > 7) 261 { 262 for(sal_uInt32 a(3); a < nCurrOutput; a+=3) 263 { 264 rOutput->StartFigure(); 265 rOutput->AddBezier(rPoints[a - 3], rPoints[a - 2], rPoints[a - 1], rPoints[a]); 266 } 267 } 268 else 269 { 270 rOutput->AddBeziers( &rPoints[0], nCurrOutput-2 ); 271 } 272 } 273 } 274 } 275 else 276 { 277 // no control points -> no curves, simply add 278 // straigt lines to GraphicsPath 279 rPoints.resize( nPoints ); 280 281 for( sal_uInt32 nCurrPoint=0; nCurrPoint<nPoints; ++nCurrPoint ) 282 { 283 const ::basegfx::B2DPoint& rPoint( rPoly.getB2DPoint( nCurrPoint ) ); 284 rPoints[nCurrPoint] = Gdiplus::PointF( static_cast<Gdiplus::REAL>(rPoint.getX()), 285 static_cast<Gdiplus::REAL>(rPoint.getY()) ); 286 } 287 288 if(bNoLineJoin && nPoints > 2) 289 { 290 for(sal_uInt32 a(1); a < nPoints; a++) 291 { 292 rOutput->StartFigure(); 293 rOutput->AddLine(rPoints[a - 1], rPoints[a]); 294 } 295 296 if(bClosedPolygon) 297 { 298 rOutput->StartFigure(); 299 rOutput->AddLine(rPoints[nPoints - 1], rPoints[0]); 300 } 301 } 302 else 303 { 304 rOutput->AddLines( &rPoints[0], nPoints ); 305 } 306 } 307 308 if( bClosedPolygon && !bNoLineJoin ) 309 rOutput->CloseFigure(); 310 } 311 } 312 gdiPlusPointFromRealPoint2D(const::com::sun::star::geometry::RealPoint2D & rPoint)313 Gdiplus::PointF gdiPlusPointFromRealPoint2D( const ::com::sun::star::geometry::RealPoint2D& rPoint ) 314 { 315 return implGdiPlusPointFromRealPoint2D( rPoint ); 316 } 317 gdiPlusRectFromIntegerRectangle2D(const geometry::IntegerRectangle2D & rRect)318 Gdiplus::Rect gdiPlusRectFromIntegerRectangle2D( const geometry::IntegerRectangle2D& rRect ) 319 { 320 return Gdiplus::Rect( rRect.X1, 321 rRect.Y1, 322 rRect.X2 - rRect.X1, 323 rRect.Y2 - rRect.Y1 ); 324 } 325 gdiPlusRectFFromRectangle2D(const geometry::RealRectangle2D & rRect)326 Gdiplus::RectF gdiPlusRectFFromRectangle2D( const geometry::RealRectangle2D& rRect ) 327 { 328 return Gdiplus::RectF( static_cast<Gdiplus::REAL>(rRect.X1), 329 static_cast<Gdiplus::REAL>(rRect.Y1), 330 static_cast<Gdiplus::REAL>(rRect.X2 - rRect.X1), 331 static_cast<Gdiplus::REAL>(rRect.Y2 - rRect.Y1) ); 332 } 333 gdiRectFromB2IRect(const::basegfx::B2IRange & rRect)334 RECT gdiRectFromB2IRect( const ::basegfx::B2IRange& rRect ) 335 { 336 RECT aRect = {rRect.getMinX(), 337 rRect.getMinY(), 338 rRect.getMaxX(), 339 rRect.getMaxY()}; 340 341 return aRect; 342 } 343 realPoint2DFromGdiPlusPointF(const Gdiplus::PointF & rPoint)344 geometry::RealPoint2D realPoint2DFromGdiPlusPointF( const Gdiplus::PointF& rPoint ) 345 { 346 return geometry::RealPoint2D( rPoint.X, rPoint.Y ); 347 } 348 realRectangle2DFromGdiPlusRectF(const Gdiplus::RectF & rRect)349 geometry::RealRectangle2D realRectangle2DFromGdiPlusRectF( const Gdiplus::RectF& rRect ) 350 { 351 return geometry::RealRectangle2D( rRect.X, rRect.Y, 352 rRect.X + rRect.Width, 353 rRect.Y + rRect.Height ); 354 } 355 b2dPointFromGdiPlusPointF(const Gdiplus::PointF & rPoint)356 ::basegfx::B2DPoint b2dPointFromGdiPlusPointF( const Gdiplus::PointF& rPoint ) 357 { 358 return ::basegfx::B2DPoint( rPoint.X, rPoint.Y ); 359 } 360 b2dRangeFromGdiPlusRectF(const Gdiplus::RectF & rRect)361 ::basegfx::B2DRange b2dRangeFromGdiPlusRectF( const Gdiplus::RectF& rRect ) 362 { 363 return ::basegfx::B2DRange( rRect.X, rRect.Y, 364 rRect.X + rRect.Width, 365 rRect.Y + rRect.Height ); 366 } 367 argbToDoubleSequence(const Gdiplus::ARGB & rColor)368 uno::Sequence< double > argbToDoubleSequence( const Gdiplus::ARGB& rColor ) 369 { 370 // TODO(F1): handle color space conversions, when defined on canvas/graphicDevice 371 uno::Sequence< double > aRet(4); 372 373 aRet[0] = ((rColor >> 16) & 0xFF) / 255.0; // red 374 aRet[1] = ((rColor >> 8) & 0xFF) / 255.0; // green 375 aRet[2] = (rColor & 0xFF) / 255.0; // blue 376 aRet[3] = ((rColor >> 24) & 0xFF) / 255.0; // alpha 377 378 return aRet; 379 } 380 argbToIntSequence(const Gdiplus::ARGB & rColor)381 uno::Sequence< sal_Int8 > argbToIntSequence( const Gdiplus::ARGB& rColor ) 382 { 383 // TODO(F1): handle color space conversions, when defined on canvas/graphicDevice 384 uno::Sequence< sal_Int8 > aRet(4); 385 386 aRet[0] = static_cast<sal_Int8>((rColor >> 16) & 0xFF); // red 387 aRet[1] = static_cast<sal_Int8>((rColor >> 8) & 0xFF); // green 388 aRet[2] = static_cast<sal_Int8>(rColor & 0xFF); // blue 389 aRet[3] = static_cast<sal_Int8>((rColor >> 24) & 0xFF); // alpha 390 391 return aRet; 392 } 393 sequenceToArgb(const uno::Sequence<sal_Int8> & rColor)394 Gdiplus::ARGB sequenceToArgb( const uno::Sequence< sal_Int8 >& rColor ) 395 { 396 ENSURE_OR_THROW( rColor.getLength() > 2, 397 "sequenceToArgb: need at least three channels" ); 398 399 // TODO(F1): handle color space conversions, when defined on canvas/graphicDevice 400 Gdiplus::ARGB aColor; 401 402 aColor = (static_cast<sal_uInt8>(rColor[0]) << 16) | (static_cast<sal_uInt8>(rColor[1]) << 8) | static_cast<sal_uInt8>(rColor[2]); 403 404 if( rColor.getLength() > 3 ) 405 aColor |= static_cast<sal_uInt8>(rColor[3]) << 24; 406 407 return aColor; 408 } 409 sequenceToArgb(const uno::Sequence<double> & rColor)410 Gdiplus::ARGB sequenceToArgb( const uno::Sequence< double >& rColor ) 411 { 412 ENSURE_OR_THROW( rColor.getLength() > 2, 413 "sequenceToColor: need at least three channels" ); 414 415 // TODO(F1): handle color space conversions, when defined on canvas/graphicDevice 416 Gdiplus::ARGB aColor; 417 418 ::canvas::tools::verifyRange(rColor[0],0.0,1.0); 419 ::canvas::tools::verifyRange(rColor[1],0.0,1.0); 420 ::canvas::tools::verifyRange(rColor[2],0.0,1.0); 421 422 aColor = 423 (static_cast<sal_uInt8>( ::basegfx::fround( 255*rColor[0] ) ) << 16) | 424 (static_cast<sal_uInt8>( ::basegfx::fround( 255*rColor[1] ) ) << 8) | 425 static_cast<sal_uInt8>( ::basegfx::fround( 255*rColor[2] ) ); 426 427 if( rColor.getLength() > 3 ) 428 { 429 ::canvas::tools::verifyRange(rColor[3],0.0,1.0); 430 aColor |= static_cast<sal_uInt8>( ::basegfx::fround( 255*rColor[3] ) ) << 24; 431 } 432 433 return aColor; 434 } 435 graphicsPathFromRealPoint2DSequence(const uno::Sequence<uno::Sequence<geometry::RealPoint2D>> & points)436 GraphicsPathSharedPtr graphicsPathFromRealPoint2DSequence( const uno::Sequence< uno::Sequence< geometry::RealPoint2D > >& points ) 437 { 438 GraphicsPathSharedPtr pRes( new Gdiplus::GraphicsPath() ); 439 ::std::vector< Gdiplus::PointF > aPoints; 440 441 sal_Int32 nCurrPoly; 442 for( nCurrPoly=0; nCurrPoly<points.getLength(); ++nCurrPoly ) 443 { 444 const sal_Int32 nCurrSize( points[nCurrPoly].getLength() ); 445 if( nCurrSize ) 446 { 447 aPoints.resize( nCurrSize ); 448 449 // TODO(F1): Closed/open polygons 450 451 // convert from RealPoint2D array to Gdiplus::PointF array 452 ::std::transform( const_cast< uno::Sequence< geometry::RealPoint2D >& >(points[nCurrPoly]).getArray(), 453 const_cast< uno::Sequence< geometry::RealPoint2D >& >(points[nCurrPoly]).getArray()+nCurrSize, 454 aPoints.begin(), 455 implGdiPlusPointFromRealPoint2D ); 456 457 pRes->AddLines( &aPoints[0], nCurrSize ); 458 } 459 } 460 461 return pRes; 462 } 463 graphicsPathFromB2DPolygon(const::basegfx::B2DPolygon & rPoly,bool bNoLineJoin)464 GraphicsPathSharedPtr graphicsPathFromB2DPolygon( const ::basegfx::B2DPolygon& rPoly, bool bNoLineJoin ) 465 { 466 GraphicsPathSharedPtr pRes( new Gdiplus::GraphicsPath() ); 467 ::std::vector< Gdiplus::PointF > aPoints; 468 469 graphicsPathFromB2DPolygon( pRes, aPoints, rPoly, bNoLineJoin ); 470 471 return pRes; 472 } 473 graphicsPathFromB2DPolyPolygon(const::basegfx::B2DPolyPolygon & rPoly,bool bNoLineJoin)474 GraphicsPathSharedPtr graphicsPathFromB2DPolyPolygon( const ::basegfx::B2DPolyPolygon& rPoly, bool bNoLineJoin ) 475 { 476 GraphicsPathSharedPtr pRes( new Gdiplus::GraphicsPath() ); 477 ::std::vector< Gdiplus::PointF > aPoints; 478 479 const sal_uInt32 nPolies( rPoly.count() ); 480 for( sal_uInt32 nCurrPoly=0; nCurrPoly<nPolies; ++nCurrPoly ) 481 { 482 graphicsPathFromB2DPolygon( pRes, 483 aPoints, 484 rPoly.getB2DPolygon( nCurrPoly ), 485 bNoLineJoin); 486 } 487 488 return pRes; 489 } 490 graphicsPathFromXPolyPolygon2D(const uno::Reference<rendering::XPolyPolygon2D> & xPoly,bool bNoLineJoin)491 GraphicsPathSharedPtr graphicsPathFromXPolyPolygon2D( const uno::Reference< rendering::XPolyPolygon2D >& xPoly, bool bNoLineJoin ) 492 { 493 LinePolyPolygon* pPolyImpl = dynamic_cast< LinePolyPolygon* >( xPoly.get() ); 494 495 if( pPolyImpl ) 496 { 497 return pPolyImpl->getGraphicsPath( bNoLineJoin ); 498 } 499 else 500 { 501 return tools::graphicsPathFromB2DPolyPolygon( 502 polyPolygonFromXPolyPolygon2D( xPoly ), bNoLineJoin ); 503 } 504 } 505 drawGdiPlusBitmap(const GraphicsSharedPtr & rGraphics,const BitmapSharedPtr & rBitmap)506 bool drawGdiPlusBitmap( const GraphicsSharedPtr& rGraphics, 507 const BitmapSharedPtr& rBitmap ) 508 { 509 Gdiplus::PointF aPoint; 510 return (Gdiplus::Ok == rGraphics->DrawImage( rBitmap.get(), 511 aPoint ) ); 512 } 513 drawDIBits(const GraphicsSharedPtr & rGraphics,const BITMAPINFO & rBI,const void * pBits)514 bool drawDIBits( const GraphicsSharedPtr& rGraphics, 515 const BITMAPINFO& rBI, 516 const void* pBits ) 517 { 518 BitmapSharedPtr pBitmap( 519 Gdiplus::Bitmap::FromBITMAPINFO( &rBI, 520 (void*)pBits ) ); 521 522 return drawGdiPlusBitmap( rGraphics, 523 pBitmap ); 524 } 525 drawRGBABits(const GraphicsSharedPtr & rGraphics,const RawRGBABitmap & rRawRGBAData)526 bool drawRGBABits( const GraphicsSharedPtr& rGraphics, 527 const RawRGBABitmap& rRawRGBAData ) 528 { 529 BitmapSharedPtr pBitmap( new Gdiplus::Bitmap( rRawRGBAData.mnWidth, 530 rRawRGBAData.mnHeight, 531 PixelFormat32bppARGB ) ); 532 533 Gdiplus::BitmapData aBmpData; 534 aBmpData.Width = rRawRGBAData.mnWidth; 535 aBmpData.Height = rRawRGBAData.mnHeight; 536 aBmpData.Stride = 4*aBmpData.Width; // bottom-up format 537 aBmpData.PixelFormat = PixelFormat32bppARGB; 538 aBmpData.Scan0 = rRawRGBAData.mpBitmapData.get(); 539 540 const Gdiplus::Rect aRect( 0,0,aBmpData.Width,aBmpData.Height ); 541 if( Gdiplus::Ok != pBitmap->LockBits( &aRect, 542 Gdiplus::ImageLockModeWrite | Gdiplus::ImageLockModeUserInputBuf, 543 PixelFormat32bppARGB, 544 &aBmpData ) ) 545 { 546 return false; 547 } 548 549 // commit data to bitmap 550 pBitmap->UnlockBits( &aBmpData ); 551 552 return drawGdiPlusBitmap( rGraphics, 553 pBitmap ); 554 } 555 bitmapFromXBitmap(const uno::Reference<rendering::XBitmap> & xBitmap)556 BitmapSharedPtr bitmapFromXBitmap( const uno::Reference< rendering::XBitmap >& xBitmap ) 557 { 558 BitmapProvider* pBitmapProvider = dynamic_cast< BitmapProvider* >(xBitmap.get()); 559 560 if( pBitmapProvider ) 561 { 562 IBitmapSharedPtr pBitmap( pBitmapProvider->getBitmap() ); 563 return pBitmap->getBitmap(); 564 } 565 else 566 { 567 // not a native CanvasBitmap, extract VCL bitmap and 568 // render into GDI+ bitmap of similar size 569 // ================================================= 570 571 const geometry::IntegerSize2D aBmpSize( xBitmap->getSize() ); 572 BitmapSharedPtr pBitmap; 573 574 if( xBitmap->hasAlpha() ) 575 { 576 // TODO(P2): At least for the alpha bitmap case, it 577 // would be possible to generate the corresponding 578 // bitmap directly 579 pBitmap.reset( new Gdiplus::Bitmap( aBmpSize.Width, 580 aBmpSize.Height, 581 PixelFormat32bppARGB ) ); 582 } 583 else 584 { 585 // TODO(F2): Might be wise to create bitmap compatible 586 // to the VCL bitmap. Also, check whether the VCL 587 // bitmap's system handles can be used to create the 588 // GDI+ bitmap (currently, it does not seem so). 589 pBitmap.reset( new Gdiplus::Bitmap( aBmpSize.Width, 590 aBmpSize.Height, 591 PixelFormat24bppRGB ) ); 592 } 593 594 GraphicsSharedPtr pGraphics(createGraphicsFromBitmap(pBitmap)); 595 tools::setupGraphics(*pGraphics); 596 if( !drawVCLBitmapFromXBitmap( 597 pGraphics, 598 xBitmap) ) 599 { 600 pBitmap.reset(); 601 } 602 603 return pBitmap; 604 } 605 } 606 canvasFontFromXFont(const uno::Reference<rendering::XCanvasFont> & xFont)607 CanvasFont::ImplRef canvasFontFromXFont( const uno::Reference< rendering::XCanvasFont >& xFont ) 608 { 609 CanvasFont* pCanvasFont = dynamic_cast< CanvasFont* >(xFont.get()); 610 611 ENSURE_ARG_OR_THROW( pCanvasFont, 612 "canvasFontFromXFont(): Invalid XFont (or incompatible font for this XCanvas)" ); 613 614 return CanvasFont::ImplRef( pCanvasFont ); 615 } 616 setModulateImageAttributes(Gdiplus::ImageAttributes & o_rAttr,double nRedModulation,double nGreenModulation,double nBlueModulation,double nAlphaModulation)617 void setModulateImageAttributes( Gdiplus::ImageAttributes& o_rAttr, 618 double nRedModulation, 619 double nGreenModulation, 620 double nBlueModulation, 621 double nAlphaModulation ) 622 { 623 // This gets rather verbose, but we have to setup a color 624 // transformation matrix, in order to incorporate the global 625 // alpha value mfAlpha into the bitmap rendering. 626 Gdiplus::ColorMatrix aColorMatrix; 627 628 aColorMatrix.m[0][0] = static_cast<Gdiplus::REAL>(nRedModulation); 629 aColorMatrix.m[0][1] = 0.0; 630 aColorMatrix.m[0][2] = 0.0; 631 aColorMatrix.m[0][3] = 0.0; 632 aColorMatrix.m[0][4] = 0.0; 633 634 aColorMatrix.m[1][0] = 0.0; 635 aColorMatrix.m[1][1] = static_cast<Gdiplus::REAL>(nGreenModulation); 636 aColorMatrix.m[1][2] = 0.0; 637 aColorMatrix.m[1][3] = 0.0; 638 aColorMatrix.m[1][4] = 0.0; 639 640 aColorMatrix.m[2][0] = 0.0; 641 aColorMatrix.m[2][1] = 0.0; 642 aColorMatrix.m[2][2] = static_cast<Gdiplus::REAL>(nBlueModulation); 643 aColorMatrix.m[2][3] = 0.0; 644 aColorMatrix.m[2][4] = 0.0; 645 646 aColorMatrix.m[3][0] = 0.0; 647 aColorMatrix.m[3][1] = 0.0; 648 aColorMatrix.m[3][2] = 0.0; 649 aColorMatrix.m[3][3] = static_cast<Gdiplus::REAL>(nAlphaModulation); 650 aColorMatrix.m[3][4] = 0.0; 651 652 aColorMatrix.m[4][0] = 0.0; 653 aColorMatrix.m[4][1] = 0.0; 654 aColorMatrix.m[4][2] = 0.0; 655 aColorMatrix.m[4][3] = 0.0; 656 aColorMatrix.m[4][4] = 1.0; 657 658 o_rAttr.SetColorMatrix( &aColorMatrix, 659 Gdiplus::ColorMatrixFlagsDefault, 660 Gdiplus::ColorAdjustTypeDefault ); 661 } 662 663 } // namespace tools 664 } // namespace dxcanvas 665