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 // MARKER(update_precomp.py): autogen include statement, do not remove 23 #include "precompiled_vcl.hxx" 24 25 #include <stdio.h> 26 #include <string.h> 27 #include <tools/svwin.h> 28 #include <tools/debug.hxx> 29 #include <win/wincomp.hxx> 30 #include <win/saldata.hxx> 31 #include <win/salgdi.h> 32 #include <win/salbmp.h> 33 34 #ifndef min 35 #define min(a,b) (((a) < (b)) ? (a) : (b)) 36 #endif 37 #ifndef max 38 #define max(a,b) (((a) > (b)) ? (a) : (b)) 39 #endif 40 41 #if defined _MSC_VER 42 #pragma warning(push, 1) 43 #endif 44 45 #include <GdiPlus.h> 46 #include <GdiPlusEnums.h> 47 #include <GdiPlusColor.h> 48 49 #if defined _MSC_VER 50 #pragma warning(pop) 51 #endif 52 53 #include <basegfx/polygon/b2dpolygon.hxx> 54 55 // ----------------------------------------------------------------------- 56 57 void impAddB2DPolygonToGDIPlusGraphicsPathReal(Gdiplus::GraphicsPath& rPath, const basegfx::B2DPolygon& rPolygon, bool bNoLineJoin) 58 { 59 sal_uInt32 nCount(rPolygon.count()); 60 61 if(nCount) 62 { 63 const sal_uInt32 nEdgeCount(rPolygon.isClosed() ? nCount : nCount - 1); 64 const bool bControls(rPolygon.areControlPointsUsed()); 65 basegfx::B2DPoint aCurr(rPolygon.getB2DPoint(0)); 66 Gdiplus::PointF aFCurr(Gdiplus::REAL(aCurr.getX()), Gdiplus::REAL(aCurr.getY())); 67 68 for(sal_uInt32 a(0); a < nEdgeCount; a++) 69 { 70 const sal_uInt32 nNextIndex((a + 1) % nCount); 71 const basegfx::B2DPoint aNext(rPolygon.getB2DPoint(nNextIndex)); 72 const Gdiplus::PointF aFNext(Gdiplus::REAL(aNext.getX()), Gdiplus::REAL(aNext.getY())); 73 74 if(bControls && (rPolygon.isNextControlPointUsed(a) || rPolygon.isPrevControlPointUsed(nNextIndex))) 75 { 76 const basegfx::B2DPoint aCa(rPolygon.getNextControlPoint(a)); 77 const basegfx::B2DPoint aCb(rPolygon.getPrevControlPoint(nNextIndex)); 78 79 rPath.AddBezier( 80 aFCurr, 81 Gdiplus::PointF(Gdiplus::REAL(aCa.getX()), Gdiplus::REAL(aCa.getY())), 82 Gdiplus::PointF(Gdiplus::REAL(aCb.getX()), Gdiplus::REAL(aCb.getY())), 83 aFNext); 84 } 85 else 86 { 87 rPath.AddLine(aFCurr, aFNext); 88 } 89 90 if(a + 1 < nEdgeCount) 91 { 92 aFCurr = aFNext; 93 94 if(bNoLineJoin) 95 { 96 rPath.StartFigure(); 97 } 98 } 99 } 100 } 101 } 102 103 void impAddB2DPolygonToGDIPlusGraphicsPathInteger(Gdiplus::GraphicsPath& rPath, const basegfx::B2DPolygon& rPolygon, bool bNoLineJoin) 104 { 105 sal_uInt32 nCount(rPolygon.count()); 106 107 if(nCount) 108 { 109 const sal_uInt32 nEdgeCount(rPolygon.isClosed() ? nCount : nCount - 1); 110 const bool bControls(rPolygon.areControlPointsUsed()); 111 basegfx::B2DPoint aCurr(rPolygon.getB2DPoint(0)); 112 Gdiplus::Point aICurr(INT(aCurr.getX()), INT(aCurr.getY())); 113 114 for(sal_uInt32 a(0); a < nEdgeCount; a++) 115 { 116 const sal_uInt32 nNextIndex((a + 1) % nCount); 117 const basegfx::B2DPoint aNext(rPolygon.getB2DPoint(nNextIndex)); 118 const Gdiplus::Point aINext(INT(aNext.getX()), INT(aNext.getY())); 119 120 if(bControls && (rPolygon.isNextControlPointUsed(a) || rPolygon.isPrevControlPointUsed(nNextIndex))) 121 { 122 const basegfx::B2DPoint aCa(rPolygon.getNextControlPoint(a)); 123 const basegfx::B2DPoint aCb(rPolygon.getPrevControlPoint(nNextIndex)); 124 125 rPath.AddBezier( 126 aICurr, 127 Gdiplus::Point(INT(aCa.getX()), INT(aCa.getY())), 128 Gdiplus::Point(INT(aCb.getX()), INT(aCb.getY())), 129 aINext); 130 } 131 else 132 { 133 rPath.AddLine(aICurr, aINext); 134 } 135 136 if(a + 1 < nEdgeCount) 137 { 138 aICurr = aINext; 139 140 if(bNoLineJoin) 141 { 142 rPath.StartFigure(); 143 } 144 } 145 } 146 } 147 } 148 149 bool WinSalGraphics::drawPolyPolygon( const ::basegfx::B2DPolyPolygon& rPolyPolygon, double fTransparency) 150 { 151 const sal_uInt32 nCount(rPolyPolygon.count()); 152 153 if(mbBrush && nCount && (fTransparency >= 0.0 && fTransparency < 1.0)) 154 { 155 Gdiplus::Graphics aGraphics(getHDC()); 156 const sal_uInt8 aTrans((sal_uInt8)255 - (sal_uInt8)basegfx::fround(fTransparency * 255.0)); 157 Gdiplus::Color aTestColor(aTrans, SALCOLOR_RED(maFillColor), SALCOLOR_GREEN(maFillColor), SALCOLOR_BLUE(maFillColor)); 158 Gdiplus::SolidBrush aTestBrush(aTestColor); 159 Gdiplus::GraphicsPath aPath; 160 161 for(sal_uInt32 a(0); a < nCount; a++) 162 { 163 if(0 != a) 164 { 165 aPath.StartFigure(); // #i101491# not needed for first run 166 } 167 168 impAddB2DPolygonToGDIPlusGraphicsPathReal(aPath, rPolyPolygon.getB2DPolygon(a), false); 169 aPath.CloseFigure(); 170 } 171 172 if(getAntiAliasB2DDraw()) 173 { 174 aGraphics.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias); 175 } 176 else 177 { 178 aGraphics.SetSmoothingMode(Gdiplus::SmoothingModeNone); 179 } 180 181 aGraphics.FillPath(&aTestBrush, &aPath); 182 } 183 184 return true; 185 } 186 187 bool WinSalGraphics::drawPolyLine( 188 const basegfx::B2DPolygon& rPolygon, 189 double fTransparency, 190 const basegfx::B2DVector& rLineWidths, 191 basegfx::B2DLineJoin eLineJoin, 192 com::sun::star::drawing::LineCap eLineCap) 193 { 194 const sal_uInt32 nCount(rPolygon.count()); 195 196 if(mbPen && nCount) 197 { 198 Gdiplus::Graphics aGraphics(getHDC()); 199 const sal_uInt8 aTrans = (sal_uInt8)basegfx::fround( 255 * (1.0 - fTransparency) ); 200 Gdiplus::Color aTestColor(aTrans, SALCOLOR_RED(maLineColor), SALCOLOR_GREEN(maLineColor), SALCOLOR_BLUE(maLineColor)); 201 Gdiplus::Pen aTestPen(aTestColor, Gdiplus::REAL(rLineWidths.getX())); 202 Gdiplus::GraphicsPath aPath; 203 bool bNoLineJoin(false); 204 205 switch(eLineJoin) 206 { 207 default : // basegfx::B2DLINEJOIN_NONE : 208 { 209 if(basegfx::fTools::more(rLineWidths.getX(), 0.0)) 210 { 211 bNoLineJoin = true; 212 } 213 break; 214 } 215 case basegfx::B2DLINEJOIN_BEVEL : 216 { 217 aTestPen.SetLineJoin(Gdiplus::LineJoinBevel); 218 break; 219 } 220 case basegfx::B2DLINEJOIN_MIDDLE : 221 case basegfx::B2DLINEJOIN_MITER : 222 { 223 const Gdiplus::REAL aMiterLimit(15.0); 224 aTestPen.SetMiterLimit(aMiterLimit); 225 aTestPen.SetLineJoin(Gdiplus::LineJoinMiter); 226 break; 227 } 228 case basegfx::B2DLINEJOIN_ROUND : 229 { 230 aTestPen.SetLineJoin(Gdiplus::LineJoinRound); 231 break; 232 } 233 } 234 235 switch(eLineCap) 236 { 237 default: /*com::sun::star::drawing::LineCap_BUTT*/ 238 { 239 // nothing to do 240 break; 241 } 242 case com::sun::star::drawing::LineCap_ROUND: 243 { 244 aTestPen.SetStartCap(Gdiplus::LineCapRound); 245 aTestPen.SetEndCap(Gdiplus::LineCapRound); 246 break; 247 } 248 case com::sun::star::drawing::LineCap_SQUARE: 249 { 250 aTestPen.SetStartCap(Gdiplus::LineCapSquare); 251 aTestPen.SetEndCap(Gdiplus::LineCapSquare); 252 break; 253 } 254 } 255 256 if(nCount > 250 && basegfx::fTools::more(rLineWidths.getX(), 1.5)) 257 { 258 impAddB2DPolygonToGDIPlusGraphicsPathInteger(aPath, rPolygon, bNoLineJoin); 259 } 260 else 261 { 262 impAddB2DPolygonToGDIPlusGraphicsPathReal(aPath, rPolygon, bNoLineJoin); 263 } 264 265 if(rPolygon.isClosed() && !bNoLineJoin) 266 { 267 // #i101491# needed to create the correct line joins 268 aPath.CloseFigure(); 269 } 270 271 if(getAntiAliasB2DDraw()) 272 { 273 aGraphics.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias); 274 } 275 else 276 { 277 aGraphics.SetSmoothingMode(Gdiplus::SmoothingModeNone); 278 } 279 280 aGraphics.DrawPath(&aTestPen, &aPath); 281 } 282 283 return true; 284 } 285 286 // ----------------------------------------------------------------------- 287 288 void paintToGdiPlus( 289 Gdiplus::Graphics& rGraphics, 290 const SalTwoRect& rTR, 291 Gdiplus::Bitmap& rBitmap) 292 { 293 // only parts of source are used 294 Gdiplus::PointF aDestPoints[3]; 295 Gdiplus::ImageAttributes aAttributes; 296 297 // define target region as paralellogram 298 aDestPoints[0].X = Gdiplus::REAL(rTR.mnDestX); 299 aDestPoints[0].Y = Gdiplus::REAL(rTR.mnDestY); 300 aDestPoints[1].X = Gdiplus::REAL(rTR.mnDestX + rTR.mnDestWidth); 301 aDestPoints[1].Y = Gdiplus::REAL(rTR.mnDestY); 302 aDestPoints[2].X = Gdiplus::REAL(rTR.mnDestX); 303 aDestPoints[2].Y = Gdiplus::REAL(rTR.mnDestY + rTR.mnDestHeight); 304 305 aAttributes.SetWrapMode(Gdiplus::WrapModeTileFlipXY); 306 307 rGraphics.DrawImage( 308 &rBitmap, 309 aDestPoints, 310 3, 311 Gdiplus::REAL(rTR.mnSrcX), 312 Gdiplus::REAL(rTR.mnSrcY), 313 Gdiplus::REAL(rTR.mnSrcWidth), 314 Gdiplus::REAL(rTR.mnSrcHeight), 315 Gdiplus::UnitPixel, 316 &aAttributes, 317 0, 318 0); 319 } 320 321 // ----------------------------------------------------------------------- 322 323 void setInterpolationMode( 324 Gdiplus::Graphics& rGraphics, 325 const long& rSrcWidth, 326 const long& rDestWidth, 327 const long& rSrcHeight, 328 const long& rDestHeight) 329 { 330 const bool bSameWidth(rSrcWidth == rDestWidth); 331 const bool bSameHeight(rSrcHeight == rDestHeight); 332 333 if(bSameWidth && bSameHeight) 334 { 335 rGraphics.SetInterpolationMode(Gdiplus::InterpolationModeInvalid); 336 } 337 else if(rDestWidth > rSrcWidth && rDestHeight > rSrcHeight) 338 { 339 rGraphics.SetInterpolationMode(Gdiplus::InterpolationModeDefault); 340 } 341 else if(rDestWidth < rSrcWidth && rDestHeight < rSrcHeight) 342 { 343 rGraphics.SetInterpolationMode(Gdiplus::InterpolationModeBicubic); 344 } 345 else 346 { 347 rGraphics.SetInterpolationMode(Gdiplus::InterpolationModeDefault); 348 } 349 } 350 351 352 bool WinSalGraphics::tryDrawBitmapGdiPlus(const SalTwoRect& rTR, const SalBitmap& rSrcBitmap) 353 { 354 if(rTR.mnSrcWidth && rTR.mnSrcHeight && rTR.mnDestWidth && rTR.mnDestHeight) 355 { 356 const WinSalBitmap& rSalBitmap = static_cast< const WinSalBitmap& >(rSrcBitmap); 357 GdiPlusBmpPtr aARGB(rSalBitmap.ImplGetGdiPlusBitmap()); 358 359 if(aARGB.get()) 360 { 361 Gdiplus::Graphics aGraphics(getHDC()); 362 363 setInterpolationMode( 364 aGraphics, 365 rTR.mnSrcWidth, 366 rTR.mnDestWidth, 367 rTR.mnSrcHeight, 368 rTR.mnDestHeight); 369 370 paintToGdiPlus( 371 aGraphics, 372 rTR, 373 *aARGB.get()); 374 375 return true; 376 } 377 } 378 379 return false; 380 } 381 382 bool WinSalGraphics::drawAlphaBitmap( 383 const SalTwoRect& rTR, 384 const SalBitmap& rSrcBitmap, 385 const SalBitmap& rAlphaBmp) 386 { 387 if(rTR.mnSrcWidth && rTR.mnSrcHeight && rTR.mnDestWidth && rTR.mnDestHeight) 388 { 389 const WinSalBitmap& rSalBitmap = static_cast< const WinSalBitmap& >(rSrcBitmap); 390 const WinSalBitmap& rSalAlpha = static_cast< const WinSalBitmap& >(rAlphaBmp); 391 GdiPlusBmpPtr aARGB(rSalBitmap.ImplGetGdiPlusBitmap(&rSalAlpha)); 392 393 if(aARGB.get()) 394 { 395 Gdiplus::Graphics aGraphics(getHDC()); 396 397 setInterpolationMode( 398 aGraphics, 399 rTR.mnSrcWidth, 400 rTR.mnDestWidth, 401 rTR.mnSrcHeight, 402 rTR.mnDestHeight); 403 404 paintToGdiPlus( 405 aGraphics, 406 rTR, 407 *aARGB.get()); 408 409 return true; 410 } 411 } 412 413 return false; 414 } 415 416 // ----------------------------------------------------------------------- 417 418 bool WinSalGraphics::drawTransformedBitmap( 419 const basegfx::B2DPoint& rNull, 420 const basegfx::B2DPoint& rX, 421 const basegfx::B2DPoint& rY, 422 const SalBitmap& rSourceBitmap, 423 const SalBitmap* pAlphaBitmap) 424 { 425 const WinSalBitmap& rSalBitmap = static_cast< const WinSalBitmap& >(rSourceBitmap); 426 const WinSalBitmap* pSalAlpha = static_cast< const WinSalBitmap* >(pAlphaBitmap); 427 GdiPlusBmpPtr aARGB(rSalBitmap.ImplGetGdiPlusBitmap(pSalAlpha)); 428 429 if(aARGB.get()) 430 { 431 const long nSrcWidth(aARGB->GetWidth()); 432 const long nSrcHeight(aARGB->GetHeight()); 433 434 if(nSrcWidth && nSrcHeight) 435 { 436 const long nDestWidth(basegfx::fround(basegfx::B2DVector(rX - rNull).getLength())); 437 const long nDestHeight(basegfx::fround(basegfx::B2DVector(rY - rNull).getLength())); 438 439 if(nDestWidth && nDestHeight) 440 { 441 Gdiplus::Graphics aGraphics(getHDC()); 442 Gdiplus::PointF aDestPoints[3]; 443 Gdiplus::ImageAttributes aAttributes; 444 445 setInterpolationMode( 446 aGraphics, 447 nSrcWidth, 448 nDestWidth, 449 nSrcHeight, 450 nDestHeight); 451 452 // this mode is only capable of drawing the whole bitmap to a paralellogram 453 aDestPoints[0].X = Gdiplus::REAL(rNull.getX()); 454 aDestPoints[0].Y = Gdiplus::REAL(rNull.getY()); 455 aDestPoints[1].X = Gdiplus::REAL(rX.getX()); 456 aDestPoints[1].Y = Gdiplus::REAL(rX.getY()); 457 aDestPoints[2].X = Gdiplus::REAL(rY.getX()); 458 aDestPoints[2].Y = Gdiplus::REAL(rY.getY()); 459 460 aAttributes.SetWrapMode(Gdiplus::WrapModeTileFlipXY); 461 462 aGraphics.DrawImage( 463 aARGB.get(), 464 aDestPoints, 465 3, 466 Gdiplus::REAL(0.0), 467 Gdiplus::REAL(0.0), 468 Gdiplus::REAL(nSrcWidth), 469 Gdiplus::REAL(nSrcHeight), 470 Gdiplus::UnitPixel, 471 &aAttributes, 472 0, 473 0); 474 } 475 } 476 477 return true; 478 } 479 480 return false; 481 } 482 483 // ----------------------------------------------------------------------- 484 // eof 485