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 <tools/debug.hxx> 26 #include <vcl/bitmap.hxx> 27 #include <vcl/bitmapex.hxx> 28 #include <vcl/window.hxx> 29 #include <vcl/metaact.hxx> 30 #include <vcl/gdimtf.hxx> 31 #include <vcl/virdev.hxx> 32 #include <vcl/bmpacc.hxx> 33 #include <vcl/outdev.hxx> 34 #include <vcl/window.hxx> 35 #include <vcl/image.hxx> 36 #include <bmpfast.hxx> 37 #include <salbmp.hxx> 38 #include <salgdi.hxx> 39 #include <impbmp.hxx> 40 #include <sallayout.hxx> 41 #include <image.h> 42 #include <outdev.h> 43 #include <window.h> 44 #include <outdata.hxx> 45 #include <basegfx/matrix/b2dhommatrix.hxx> 46 47 #define BAND_MAX_SIZE 512000 48 49 // ======================================================================= 50 51 DBG_NAMEEX( OutputDevice ) 52 53 // ======================================================================= 54 55 // ----------- 56 // - Defines - 57 // ----------- 58 59 #define OUTDEV_INIT() \ 60 { \ 61 if ( !IsDeviceOutputNecessary() ) \ 62 return; \ 63 \ 64 if ( !mpGraphics ) \ 65 if ( !ImplGetGraphics() ) \ 66 return; \ 67 \ 68 if ( mbInitClipRegion ) \ 69 ImplInitClipRegion(); \ 70 \ 71 if ( mbOutputClipped ) \ 72 return; \ 73 } 74 75 // ------------- 76 // - externals - 77 // ------------- 78 79 extern sal_uLong nVCLRLut[ 6 ]; 80 extern sal_uLong nVCLGLut[ 6 ]; 81 extern sal_uLong nVCLBLut[ 6 ]; 82 extern sal_uLong nVCLDitherLut[ 256 ]; 83 extern sal_uLong nVCLLut[ 256 ]; 84 85 // ======================================================================= 86 87 sal_uLong ImplAdjustTwoRect( SalTwoRect& rTwoRect, const Size& rSizePix ) 88 { 89 sal_uLong nMirrFlags = 0; 90 91 if ( rTwoRect.mnDestWidth < 0 ) 92 { 93 rTwoRect.mnSrcX = rSizePix.Width() - rTwoRect.mnSrcX - rTwoRect.mnSrcWidth; 94 rTwoRect.mnDestWidth = -rTwoRect.mnDestWidth; 95 rTwoRect.mnDestX -= rTwoRect.mnDestWidth-1; 96 nMirrFlags |= BMP_MIRROR_HORZ; 97 } 98 99 if ( rTwoRect.mnDestHeight < 0 ) 100 { 101 rTwoRect.mnSrcY = rSizePix.Height() - rTwoRect.mnSrcY - rTwoRect.mnSrcHeight; 102 rTwoRect.mnDestHeight = -rTwoRect.mnDestHeight; 103 rTwoRect.mnDestY -= rTwoRect.mnDestHeight-1; 104 nMirrFlags |= BMP_MIRROR_VERT; 105 } 106 107 if( ( rTwoRect.mnSrcX < 0 ) || ( rTwoRect.mnSrcX >= rSizePix.Width() ) || 108 ( rTwoRect.mnSrcY < 0 ) || ( rTwoRect.mnSrcY >= rSizePix.Height() ) || 109 ( ( rTwoRect.mnSrcX + rTwoRect.mnSrcWidth ) > rSizePix.Width() ) || 110 ( ( rTwoRect.mnSrcY + rTwoRect.mnSrcHeight ) > rSizePix.Height() ) ) 111 { 112 const Rectangle aSourceRect( Point( rTwoRect.mnSrcX, rTwoRect.mnSrcY ), 113 Size( rTwoRect.mnSrcWidth, rTwoRect.mnSrcHeight ) ); 114 Rectangle aCropRect( aSourceRect ); 115 116 aCropRect.Intersection( Rectangle( Point(), rSizePix ) ); 117 118 if( aCropRect.IsEmpty() ) 119 rTwoRect.mnSrcWidth = rTwoRect.mnSrcHeight = rTwoRect.mnDestWidth = rTwoRect.mnDestHeight = 0; 120 else 121 { 122 const double fFactorX = ( rTwoRect.mnSrcWidth > 1 ) ? (double) ( rTwoRect.mnDestWidth - 1 ) / ( rTwoRect.mnSrcWidth - 1 ) : 0.0; 123 const double fFactorY = ( rTwoRect.mnSrcHeight > 1 ) ? (double) ( rTwoRect.mnDestHeight - 1 ) / ( rTwoRect.mnSrcHeight - 1 ) : 0.0; 124 125 const long nDstX1 = rTwoRect.mnDestX + FRound( fFactorX * ( aCropRect.Left() - rTwoRect.mnSrcX ) ); 126 const long nDstY1 = rTwoRect.mnDestY + FRound( fFactorY * ( aCropRect.Top() - rTwoRect.mnSrcY ) ); 127 const long nDstX2 = rTwoRect.mnDestX + FRound( fFactorX * ( aCropRect.Right() - rTwoRect.mnSrcX ) ); 128 const long nDstY2 = rTwoRect.mnDestY + FRound( fFactorY * ( aCropRect.Bottom() - rTwoRect.mnSrcY ) ); 129 130 rTwoRect.mnSrcX = aCropRect.Left(); 131 rTwoRect.mnSrcY = aCropRect.Top(); 132 rTwoRect.mnSrcWidth = aCropRect.GetWidth(); 133 rTwoRect.mnSrcHeight = aCropRect.GetHeight(); 134 rTwoRect.mnDestX = nDstX1; 135 rTwoRect.mnDestY = nDstY1; 136 rTwoRect.mnDestWidth = nDstX2 - nDstX1 + 1; 137 rTwoRect.mnDestHeight = nDstY2 - nDstY1 + 1; 138 } 139 } 140 141 return nMirrFlags; 142 } 143 144 // ======================================================================= 145 146 void OutputDevice::ImplDrawOutDevDirect( const OutputDevice* pSrcDev, SalTwoRect& rPosAry ) 147 { 148 SalGraphics* pGraphics2; 149 150 if ( rPosAry.mnSrcWidth && rPosAry.mnSrcHeight && rPosAry.mnDestWidth && rPosAry.mnDestHeight ) 151 { 152 if ( this == pSrcDev ) 153 pGraphics2 = NULL; 154 else 155 { 156 if ( (GetOutDevType() != pSrcDev->GetOutDevType()) || 157 (GetOutDevType() != OUTDEV_WINDOW) ) 158 { 159 if ( !pSrcDev->mpGraphics ) 160 { 161 if ( !((OutputDevice*)pSrcDev)->ImplGetGraphics() ) 162 return; 163 } 164 pGraphics2 = pSrcDev->mpGraphics; 165 } 166 else 167 { 168 if ( ((Window*)this)->mpWindowImpl->mpFrameWindow == ((Window*)pSrcDev)->mpWindowImpl->mpFrameWindow ) 169 pGraphics2 = NULL; 170 else 171 { 172 if ( !pSrcDev->mpGraphics ) 173 { 174 if ( !((OutputDevice*)pSrcDev)->ImplGetGraphics() ) 175 return; 176 } 177 pGraphics2 = pSrcDev->mpGraphics; 178 179 if ( !mpGraphics ) 180 { 181 if ( !ImplGetGraphics() ) 182 return; 183 } 184 DBG_ASSERT( mpGraphics && pSrcDev->mpGraphics, 185 "OutputDevice::DrawOutDev(): We need more than one Graphics" ); 186 } 187 } 188 } 189 190 // #102532# Offset only has to be pseudo window offset 191 Rectangle aSrcOutRect( Point( pSrcDev->mnOutOffX, pSrcDev->mnOutOffY ), 192 Size( pSrcDev->mnOutWidth, pSrcDev->mnOutHeight ) ); 193 Rectangle aSrcRect( Point( rPosAry.mnSrcX, rPosAry.mnSrcY ), 194 Size( rPosAry.mnSrcWidth, rPosAry.mnSrcHeight ) ); 195 const long nOldRight = aSrcRect.Right(); 196 const long nOldBottom = aSrcRect.Bottom(); 197 198 if ( !aSrcRect.Intersection( aSrcOutRect ).IsEmpty() ) 199 { 200 if ( (rPosAry.mnSrcX+rPosAry.mnSrcWidth-1) > aSrcOutRect.Right() ) 201 { 202 const long nOldWidth = rPosAry.mnSrcWidth; 203 rPosAry.mnSrcWidth -= (nOldRight - aSrcRect.Right()); 204 rPosAry.mnDestWidth = rPosAry.mnDestWidth * rPosAry.mnSrcWidth / nOldWidth; 205 } 206 207 if ( (rPosAry.mnSrcY+rPosAry.mnSrcHeight-1) > aSrcOutRect.Bottom() ) 208 { 209 const long nOldHeight = rPosAry.mnSrcHeight; 210 rPosAry.mnSrcHeight -= (nOldBottom - aSrcRect.Bottom()); 211 rPosAry.mnDestHeight = rPosAry.mnDestHeight * rPosAry.mnSrcHeight / nOldHeight; 212 } 213 214 // --- RTL --- if this is no window, but pSrcDev is a window 215 // mirroring may be required 216 // because only windows have a SalGraphicsLayout 217 // mirroring is performed here 218 if( (GetOutDevType() != OUTDEV_WINDOW) && pGraphics2 && (pGraphics2->GetLayout() & SAL_LAYOUT_BIDI_RTL) ) 219 { 220 SalTwoRect aPosAry2 = rPosAry; 221 pGraphics2->mirror( aPosAry2.mnSrcX, aPosAry2.mnSrcWidth, pSrcDev ); 222 mpGraphics->CopyBits( aPosAry2, pGraphics2, this, pSrcDev ); 223 } 224 else 225 mpGraphics->CopyBits( rPosAry, pGraphics2, this, pSrcDev ); 226 } 227 } 228 } 229 230 // ------------------------------------------------------------------ 231 232 void OutputDevice::DrawOutDev( const Point& rDestPt, const Size& rDestSize, 233 const Point& rSrcPt, const Size& rSrcSize ) 234 { 235 DBG_TRACE( "OutputDevice::DrawOutDev()" ); 236 DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); 237 DBG_ASSERT( meOutDevType != OUTDEV_PRINTER, "Don't use OutputDevice::DrawOutDev(...) with printer devices!" ); 238 239 if( ImplIsRecordLayout() ) 240 return; 241 242 if ( meOutDevType == OUTDEV_PRINTER ) 243 return; 244 245 if ( ROP_INVERT == meRasterOp ) 246 { 247 DrawRect( Rectangle( rDestPt, rDestSize ) ); 248 return; 249 } 250 251 if ( mpMetaFile ) 252 { 253 const Bitmap aBmp( GetBitmap( rSrcPt, rSrcSize ) ); 254 mpMetaFile->AddAction( new MetaBmpScaleAction( rDestPt, rDestSize, aBmp ) ); 255 } 256 257 OUTDEV_INIT(); 258 259 SalTwoRect aPosAry; 260 aPosAry.mnSrcWidth = ImplLogicWidthToDevicePixel( rSrcSize.Width() ); 261 aPosAry.mnSrcHeight = ImplLogicHeightToDevicePixel( rSrcSize.Height() ); 262 aPosAry.mnDestWidth = ImplLogicWidthToDevicePixel( rDestSize.Width() ); 263 aPosAry.mnDestHeight = ImplLogicHeightToDevicePixel( rDestSize.Height() ); 264 265 if ( aPosAry.mnSrcWidth && aPosAry.mnSrcHeight && aPosAry.mnDestWidth && aPosAry.mnDestHeight ) 266 { 267 aPosAry.mnSrcX = ImplLogicXToDevicePixel( rSrcPt.X() ); 268 aPosAry.mnSrcY = ImplLogicYToDevicePixel( rSrcPt.Y() ); 269 aPosAry.mnDestX = ImplLogicXToDevicePixel( rDestPt.X() ); 270 aPosAry.mnDestY = ImplLogicYToDevicePixel( rDestPt.Y() ); 271 272 Rectangle aSrcOutRect( Point( mnOutOffX, mnOutOffY ), 273 Size( mnOutWidth, mnOutHeight ) ); 274 Rectangle aSrcRect( Point( aPosAry.mnSrcX, aPosAry.mnSrcY ), 275 Size( aPosAry.mnSrcWidth, aPosAry.mnSrcHeight ) ); 276 long nOldRight = aSrcRect.Right(); 277 long nOldBottom = aSrcRect.Bottom(); 278 279 if ( !aSrcRect.Intersection( aSrcOutRect ).IsEmpty() ) 280 { 281 if ( (aPosAry.mnSrcX+aPosAry.mnSrcWidth-1) > aSrcOutRect.Right() ) 282 { 283 long nOldWidth = aPosAry.mnSrcWidth; 284 aPosAry.mnSrcWidth -= nOldRight-aSrcRect.Right(); 285 aPosAry.mnDestWidth = aPosAry.mnDestWidth*aPosAry.mnSrcWidth/nOldWidth; 286 } 287 288 if ( (aPosAry.mnSrcY+aPosAry.mnSrcHeight-1) > aSrcOutRect.Bottom() ) 289 { 290 long nOldHeight = aPosAry.mnSrcHeight; 291 aPosAry.mnSrcHeight -= nOldBottom-aSrcRect.Bottom(); 292 aPosAry.mnDestHeight = aPosAry.mnDestHeight*aPosAry.mnSrcHeight/nOldHeight; 293 } 294 295 mpGraphics->CopyBits( aPosAry, NULL, this, NULL ); 296 } 297 } 298 299 if( mpAlphaVDev ) 300 mpAlphaVDev->DrawOutDev( rDestPt, rDestSize, rSrcPt, rSrcSize ); 301 } 302 303 // ------------------------------------------------------------------ 304 305 void OutputDevice::DrawOutDev( const Point& rDestPt, const Size& rDestSize, 306 const Point& rSrcPt, const Size& rSrcSize, 307 const OutputDevice& rOutDev ) 308 { 309 DBG_TRACE( "OutputDevice::DrawOutDev()" ); 310 DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); 311 DBG_CHKOBJ( &rOutDev, OutputDevice, ImplDbgCheckOutputDevice ); 312 DBG_ASSERT( meOutDevType != OUTDEV_PRINTER, "Don't use OutputDevice::DrawOutDev(...) with printer devices!" ); 313 DBG_ASSERT( rOutDev.meOutDevType != OUTDEV_PRINTER, "Don't use OutputDevice::DrawOutDev(...) with printer devices!" ); 314 315 if ( (meOutDevType == OUTDEV_PRINTER) || (rOutDev.meOutDevType == OUTDEV_PRINTER) || ImplIsRecordLayout() ) 316 return; 317 318 if ( ROP_INVERT == meRasterOp ) 319 { 320 DrawRect( Rectangle( rDestPt, rDestSize ) ); 321 return; 322 } 323 324 if ( mpMetaFile ) 325 { 326 const Bitmap aBmp( rOutDev.GetBitmap( rSrcPt, rSrcSize ) ); 327 mpMetaFile->AddAction( new MetaBmpScaleAction( rDestPt, rDestSize, aBmp ) ); 328 } 329 330 OUTDEV_INIT(); 331 332 SalTwoRect aPosAry; 333 aPosAry.mnSrcX = rOutDev.ImplLogicXToDevicePixel( rSrcPt.X() ); 334 aPosAry.mnSrcY = rOutDev.ImplLogicYToDevicePixel( rSrcPt.Y() ); 335 aPosAry.mnSrcWidth = rOutDev.ImplLogicWidthToDevicePixel( rSrcSize.Width() ); 336 aPosAry.mnSrcHeight = rOutDev.ImplLogicHeightToDevicePixel( rSrcSize.Height() ); 337 aPosAry.mnDestX = ImplLogicXToDevicePixel( rDestPt.X() ); 338 aPosAry.mnDestY = ImplLogicYToDevicePixel( rDestPt.Y() ); 339 aPosAry.mnDestWidth = ImplLogicWidthToDevicePixel( rDestSize.Width() ); 340 aPosAry.mnDestHeight = ImplLogicHeightToDevicePixel( rDestSize.Height() ); 341 342 if( mpAlphaVDev ) 343 { 344 if( rOutDev.mpAlphaVDev ) 345 { 346 // alpha-blend source over destination 347 DrawBitmapEx( rDestPt, rDestSize, rOutDev.GetBitmapEx(rSrcPt, rSrcSize) ); 348 349 // This would be mode SOURCE: 350 // copy source alpha channel to our alpha channel 351 //mpAlphaVDev->DrawOutDev( rDestPt, rDestSize, rSrcPt, rSrcSize, *rOutDev.mpAlphaVDev ); 352 } 353 else 354 { 355 ImplDrawOutDevDirect( &rOutDev, aPosAry ); 356 357 // #i32109#: make destination rectangle opaque - source has no alpha 358 mpAlphaVDev->ImplFillOpaqueRectangle( Rectangle(rDestPt, rDestSize) ); 359 } 360 } 361 else 362 { 363 if( rOutDev.mpAlphaVDev ) 364 { 365 // alpha-blend source over destination 366 DrawBitmapEx( rDestPt, rDestSize, rOutDev.GetBitmapEx(rSrcPt, rSrcSize) ); 367 } 368 else 369 { 370 // no alpha at all, neither in source nor destination device 371 ImplDrawOutDevDirect( &rOutDev, aPosAry ); 372 } 373 } 374 } 375 376 // ------------------------------------------------------------------ 377 378 void OutputDevice::CopyArea( const Point& rDestPt, 379 const Point& rSrcPt, const Size& rSrcSize, 380 sal_uInt16 nFlags ) 381 { 382 DBG_TRACE( "OutputDevice::CopyArea()" ); 383 DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); 384 DBG_ASSERT( meOutDevType != OUTDEV_PRINTER, "Don't use OutputDevice::CopyArea(...) with printer devices!" ); 385 386 if ( meOutDevType == OUTDEV_PRINTER || ImplIsRecordLayout() ) 387 return; 388 389 RasterOp eOldRop = GetRasterOp(); 390 SetRasterOp( ROP_OVERPAINT ); 391 392 OUTDEV_INIT(); 393 394 SalTwoRect aPosAry; 395 aPosAry.mnSrcWidth = ImplLogicWidthToDevicePixel( rSrcSize.Width() ); 396 aPosAry.mnSrcHeight = ImplLogicHeightToDevicePixel( rSrcSize.Height() ); 397 398 if ( aPosAry.mnSrcWidth && aPosAry.mnSrcHeight ) 399 { 400 aPosAry.mnSrcX = ImplLogicXToDevicePixel( rSrcPt.X() ); 401 aPosAry.mnSrcY = ImplLogicYToDevicePixel( rSrcPt.Y() ); 402 aPosAry.mnDestX = ImplLogicXToDevicePixel( rDestPt.X() ); 403 aPosAry.mnDestY = ImplLogicYToDevicePixel( rDestPt.Y() ); 404 405 Rectangle aSrcOutRect( Point( mnOutOffX, mnOutOffY ), 406 Size( mnOutWidth, mnOutHeight ) ); 407 Rectangle aSrcRect( Point( aPosAry.mnSrcX, aPosAry.mnSrcY ), 408 Size( aPosAry.mnSrcWidth, aPosAry.mnSrcHeight ) ); 409 long nOldRight = aSrcRect.Right(); 410 long nOldBottom = aSrcRect.Bottom(); 411 412 if ( !aSrcRect.Intersection( aSrcOutRect ).IsEmpty() ) 413 { 414 if ( (aPosAry.mnSrcX+aPosAry.mnSrcWidth-1) > aSrcOutRect.Right() ) 415 aPosAry.mnSrcWidth -= nOldRight-aSrcRect.Right(); 416 417 if ( (aPosAry.mnSrcY+aPosAry.mnSrcHeight-1) > aSrcOutRect.Bottom() ) 418 aPosAry.mnSrcHeight -= nOldBottom-aSrcRect.Bottom(); 419 420 if ( (meOutDevType == OUTDEV_WINDOW) && (nFlags & COPYAREA_WINDOWINVALIDATE) ) 421 { 422 ((Window*)this)->ImplMoveAllInvalidateRegions( aSrcRect, 423 aPosAry.mnDestX-aPosAry.mnSrcX, 424 aPosAry.mnDestY-aPosAry.mnSrcY, 425 sal_False ); 426 427 mpGraphics->CopyArea( aPosAry.mnDestX, aPosAry.mnDestY, 428 aPosAry.mnSrcX, aPosAry.mnSrcY, 429 aPosAry.mnSrcWidth, aPosAry.mnSrcHeight, 430 SAL_COPYAREA_WINDOWINVALIDATE, this ); 431 } 432 else 433 { 434 aPosAry.mnDestWidth = aPosAry.mnSrcWidth; 435 aPosAry.mnDestHeight = aPosAry.mnSrcHeight; 436 mpGraphics->CopyBits( aPosAry, NULL, this, NULL ); 437 } 438 } 439 } 440 441 SetRasterOp( eOldRop ); 442 443 if( mpAlphaVDev ) 444 mpAlphaVDev->CopyArea( rDestPt, rSrcPt, rSrcSize, nFlags ); 445 } 446 447 // ------------------------------------------------------------------ 448 449 void OutputDevice::ImplDrawFrameDev( const Point& rPt, const Point& rDevPt, const Size& rDevSize, 450 const OutputDevice& rOutDev, const Region& rRegion ) 451 { 452 DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); 453 454 GDIMetaFile* pOldMetaFile = mpMetaFile; 455 sal_Bool bOldMap = mbMap; 456 RasterOp eOldROP = GetRasterOp(); 457 mpMetaFile = NULL; 458 mbMap = sal_False; 459 SetRasterOp( ROP_OVERPAINT ); 460 461 if ( !IsDeviceOutputNecessary() ) 462 return; 463 464 if ( !mpGraphics ) 465 { 466 if ( !ImplGetGraphics() ) 467 return; 468 } 469 470 // ClipRegion zuruecksetzen 471 if ( rRegion.IsNull() ) 472 mpGraphics->ResetClipRegion(); 473 else 474 ImplSelectClipRegion( rRegion ); 475 476 SalTwoRect aPosAry; 477 aPosAry.mnSrcX = rDevPt.X(); 478 aPosAry.mnSrcY = rDevPt.Y(); 479 aPosAry.mnSrcWidth = rDevSize.Width(); 480 aPosAry.mnSrcHeight = rDevSize.Height(); 481 aPosAry.mnDestX = rPt.X(); 482 aPosAry.mnDestY = rPt.Y(); 483 aPosAry.mnDestWidth = rDevSize.Width(); 484 aPosAry.mnDestHeight = rDevSize.Height(); 485 ImplDrawOutDevDirect( &rOutDev, aPosAry ); 486 487 // Dafuer sorgen, das ClipRegion neu berechnet und gesetzt wird 488 mbInitClipRegion = sal_True; 489 490 SetRasterOp( eOldROP ); 491 mbMap = bOldMap; 492 mpMetaFile = pOldMetaFile; 493 } 494 495 // ------------------------------------------------------------------ 496 497 void OutputDevice::ImplGetFrameDev( const Point& rPt, const Point& rDevPt, const Size& rDevSize, 498 OutputDevice& rDev ) 499 { 500 DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); 501 502 sal_Bool bOldMap = mbMap; 503 mbMap = sal_False; 504 rDev.DrawOutDev( rDevPt, rDevSize, rPt, rDevSize, *this ); 505 mbMap = bOldMap; 506 } 507 508 // ------------------------------------------------------------------ 509 510 void OutputDevice::DrawBitmap( const Point& rDestPt, const Bitmap& rBitmap ) 511 { 512 DBG_TRACE( "OutputDevice::DrawBitmap()" ); 513 514 if( ImplIsRecordLayout() ) 515 return; 516 517 const Size aSizePix( rBitmap.GetSizePixel() ); 518 ImplDrawBitmap( rDestPt, PixelToLogic( aSizePix ), Point(), aSizePix, rBitmap, META_BMP_ACTION ); 519 520 if( mpAlphaVDev ) 521 { 522 // #i32109#: Make bitmap area opaque 523 mpAlphaVDev->ImplFillOpaqueRectangle( Rectangle(rDestPt, PixelToLogic( aSizePix )) ); 524 } 525 } 526 527 // ------------------------------------------------------------------ 528 529 void OutputDevice::DrawBitmap( const Point& rDestPt, const Size& rDestSize, const Bitmap& rBitmap ) 530 { 531 DBG_TRACE( "OutputDevice::DrawBitmap( Size )" ); 532 533 if( ImplIsRecordLayout() ) 534 return; 535 536 ImplDrawBitmap( rDestPt, rDestSize, Point(), rBitmap.GetSizePixel(), rBitmap, META_BMPSCALE_ACTION ); 537 538 if( mpAlphaVDev ) 539 { 540 // #i32109#: Make bitmap area opaque 541 mpAlphaVDev->ImplFillOpaqueRectangle( Rectangle(rDestPt, rDestSize) ); 542 } 543 } 544 545 // ------------------------------------------------------------------ 546 547 void OutputDevice::DrawBitmap( const Point& rDestPt, const Size& rDestSize, 548 const Point& rSrcPtPixel, const Size& rSrcSizePixel, 549 const Bitmap& rBitmap ) 550 { 551 DBG_TRACE( "OutputDevice::DrawBitmap( Point, Size )" ); 552 553 if( ImplIsRecordLayout() ) 554 return; 555 556 ImplDrawBitmap( rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel, rBitmap, META_BMPSCALEPART_ACTION ); 557 558 if( mpAlphaVDev ) 559 { 560 // #i32109#: Make bitmap area opaque 561 mpAlphaVDev->ImplFillOpaqueRectangle( Rectangle(rDestPt, rDestSize) ); 562 } 563 } 564 565 // ----------------------------------------------------------------------------- 566 567 void OutputDevice::ImplDrawBitmap( const Point& rDestPt, const Size& rDestSize, 568 const Point& rSrcPtPixel, const Size& rSrcSizePixel, 569 const Bitmap& rBitmap, const sal_uLong nAction ) 570 { 571 DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); 572 573 if ( ( mnDrawMode & DRAWMODE_NOBITMAP ) ) 574 return; 575 576 if ( ROP_INVERT == meRasterOp ) 577 { 578 DrawRect( Rectangle( rDestPt, rDestSize ) ); 579 return; 580 } 581 582 Bitmap aBmp( rBitmap ); 583 584 if ( mnDrawMode & ( DRAWMODE_BLACKBITMAP | DRAWMODE_WHITEBITMAP | 585 DRAWMODE_GRAYBITMAP | DRAWMODE_GHOSTEDBITMAP ) ) 586 { 587 if ( mnDrawMode & ( DRAWMODE_BLACKBITMAP | DRAWMODE_WHITEBITMAP ) ) 588 { 589 sal_uInt8 cCmpVal; 590 591 if ( mnDrawMode & DRAWMODE_BLACKBITMAP ) 592 cCmpVal = ( mnDrawMode & DRAWMODE_GHOSTEDBITMAP ) ? 0x80 : 0; 593 else 594 cCmpVal = 255; 595 596 Color aCol( cCmpVal, cCmpVal, cCmpVal ); 597 Push( PUSH_LINECOLOR | PUSH_FILLCOLOR ); 598 SetLineColor( aCol ); 599 SetFillColor( aCol ); 600 DrawRect( Rectangle( rDestPt, rDestSize ) ); 601 Pop(); 602 return; 603 } 604 else if( !!aBmp ) 605 { 606 if ( mnDrawMode & DRAWMODE_GRAYBITMAP ) 607 aBmp.Convert( BMP_CONVERSION_8BIT_GREYS ); 608 609 if ( mnDrawMode & DRAWMODE_GHOSTEDBITMAP ) 610 aBmp.Convert( BMP_CONVERSION_GHOSTED ); 611 } 612 } 613 614 if ( mpMetaFile ) 615 { 616 switch( nAction ) 617 { 618 case( META_BMP_ACTION ): 619 mpMetaFile->AddAction( new MetaBmpAction( rDestPt, aBmp ) ); 620 break; 621 622 case( META_BMPSCALE_ACTION ): 623 mpMetaFile->AddAction( new MetaBmpScaleAction( rDestPt, rDestSize, aBmp ) ); 624 break; 625 626 case( META_BMPSCALEPART_ACTION ): 627 mpMetaFile->AddAction( new MetaBmpScalePartAction( 628 rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel, aBmp ) ); 629 break; 630 } 631 } 632 633 OUTDEV_INIT(); 634 635 if( !aBmp.IsEmpty() ) 636 { 637 SalTwoRect aPosAry; 638 639 aPosAry.mnSrcX = rSrcPtPixel.X(); 640 aPosAry.mnSrcY = rSrcPtPixel.Y(); 641 aPosAry.mnSrcWidth = rSrcSizePixel.Width(); 642 aPosAry.mnSrcHeight = rSrcSizePixel.Height(); 643 aPosAry.mnDestX = ImplLogicXToDevicePixel( rDestPt.X() ); 644 aPosAry.mnDestY = ImplLogicYToDevicePixel( rDestPt.Y() ); 645 aPosAry.mnDestWidth = ImplLogicWidthToDevicePixel( rDestSize.Width() ); 646 aPosAry.mnDestHeight = ImplLogicHeightToDevicePixel( rDestSize.Height() ); 647 648 const sal_uLong nMirrFlags = ImplAdjustTwoRect( aPosAry, aBmp.GetSizePixel() ); 649 650 if ( aPosAry.mnSrcWidth && aPosAry.mnSrcHeight && aPosAry.mnDestWidth && aPosAry.mnDestHeight ) 651 { 652 if ( nMirrFlags ) 653 aBmp.Mirror( nMirrFlags ); 654 655 /* #i75264# (corrected with #i81576#) 656 * sometimes a bitmap is scaled to a ridiculous size and drawn 657 * to a quite normal VDev, so only a very small part of 658 * the scaled bitmap will be visible. However actually scaling 659 * the bitmap will use so much memory that we end with a crash. 660 * Workaround: since only a small part of the scaled bitmap will 661 * be actually drawn anyway (because of clipping on the device 662 * boundary), limit the destination and source rectangles so 663 * that the destination rectangle will overlap the device but only 664 * be reasonably (say factor 2) larger than the device itself. 665 */ 666 667 // not needed for win32, it uses GdiPlus and is able to do everything without 668 // internally scaling the bitmap 669 #ifndef WIN32 670 671 if( aPosAry.mnDestWidth > 2048 || aPosAry.mnDestHeight > 2048 ) 672 { 673 if( meOutDevType == OUTDEV_WINDOW || 674 (meOutDevType == OUTDEV_VIRDEV && mpPDFWriter == 0 ) ) 675 { 676 // #i81576# do the following trick only if there is overlap at all 677 // else the formulae don't work 678 // theoretically in this case we wouldn't need to draw the bitmap at all 679 // however there are some esoteric case where that is needed 680 if( aPosAry.mnDestX + aPosAry.mnDestWidth >= 0 681 && aPosAry.mnDestX < mnOutWidth 682 && aPosAry.mnDestY + aPosAry.mnDestHeight >= 0 683 && aPosAry.mnDestY < mnOutHeight ) 684 { 685 // reduce scaling to something reasonable taking into account the output size 686 if( aPosAry.mnDestWidth > 3*mnOutWidth && aPosAry.mnSrcWidth ) 687 { 688 const double nScaleX = aPosAry.mnDestWidth/double(aPosAry.mnSrcWidth); 689 690 if( aPosAry.mnDestX + aPosAry.mnDestWidth > mnOutWidth ) 691 { 692 aPosAry.mnDestWidth = Max(long(0),mnOutWidth-aPosAry.mnDestX); 693 } 694 if( aPosAry.mnDestX < 0 ) 695 { 696 aPosAry.mnDestWidth += aPosAry.mnDestX; 697 aPosAry.mnSrcX -= sal::static_int_cast<long>(aPosAry.mnDestX / nScaleX); 698 aPosAry.mnDestX = 0; 699 } 700 701 aPosAry.mnSrcWidth = sal::static_int_cast<long>(aPosAry.mnDestWidth / nScaleX); 702 } 703 704 if( aPosAry.mnDestHeight > 3*mnOutHeight && aPosAry.mnSrcHeight != 0 ) 705 { 706 const double nScaleY = aPosAry.mnDestHeight/double(aPosAry.mnSrcHeight); 707 708 if( aPosAry.mnDestY + aPosAry.mnDestHeight > mnOutHeight ) 709 { 710 aPosAry.mnDestHeight = Max(long(0),mnOutHeight-aPosAry.mnDestY); 711 } 712 if( aPosAry.mnDestY < 0 ) 713 { 714 aPosAry.mnDestHeight += aPosAry.mnDestY; 715 aPosAry.mnSrcY -= sal::static_int_cast<long>(aPosAry.mnDestY / nScaleY); 716 aPosAry.mnDestY = 0; 717 } 718 719 aPosAry.mnSrcHeight = sal::static_int_cast<long>(aPosAry.mnDestHeight / nScaleY); 720 } 721 } 722 } 723 } 724 #endif 725 726 if ( aPosAry.mnSrcWidth && aPosAry.mnSrcHeight && aPosAry.mnDestWidth && aPosAry.mnDestHeight ) 727 { 728 mpGraphics->DrawBitmap( aPosAry, *aBmp.ImplGetImpBitmap()->ImplGetSalBitmap(), this ); 729 } 730 } 731 } 732 } 733 734 // ------------------------------------------------------------------ 735 736 void OutputDevice::DrawBitmapEx( const Point& rDestPt, 737 const BitmapEx& rBitmapEx ) 738 { 739 DBG_TRACE( "OutputDevice::DrawBitmapEx()" ); 740 741 if( ImplIsRecordLayout() ) 742 return; 743 744 if( TRANSPARENT_NONE == rBitmapEx.GetTransparentType() ) 745 { 746 DrawBitmap( rDestPt, rBitmapEx.GetBitmap() ); 747 } 748 else 749 { 750 const Size aSizePix( rBitmapEx.GetSizePixel() ); 751 ImplDrawBitmapEx( rDestPt, PixelToLogic( aSizePix ), Point(), aSizePix, rBitmapEx, META_BMPEX_ACTION ); 752 } 753 } 754 755 // ------------------------------------------------------------------ 756 757 void OutputDevice::DrawBitmapEx( const Point& rDestPt, const Size& rDestSize, 758 const BitmapEx& rBitmapEx ) 759 { 760 DBG_TRACE( "OutputDevice::DrawBitmapEx( Size )" ); 761 762 if( ImplIsRecordLayout() ) 763 return; 764 765 if ( TRANSPARENT_NONE == rBitmapEx.GetTransparentType() ) 766 { 767 DrawBitmap( rDestPt, rDestSize, rBitmapEx.GetBitmap() ); 768 } 769 else 770 { 771 ImplDrawBitmapEx( rDestPt, rDestSize, Point(), rBitmapEx.GetSizePixel(), rBitmapEx, META_BMPEXSCALE_ACTION ); 772 } 773 } 774 775 // ------------------------------------------------------------------ 776 777 void OutputDevice::DrawBitmapEx( const Point& rDestPt, const Size& rDestSize, 778 const Point& rSrcPtPixel, const Size& rSrcSizePixel, 779 const BitmapEx& rBitmapEx ) 780 { 781 DBG_TRACE( "OutputDevice::DrawBitmapEx( Point, Size )" ); 782 783 if( ImplIsRecordLayout() ) 784 return; 785 786 if( TRANSPARENT_NONE == rBitmapEx.GetTransparentType() ) 787 { 788 DrawBitmap( rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel, rBitmapEx.GetBitmap() ); 789 } 790 else 791 { 792 ImplDrawBitmapEx( rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel, rBitmapEx, META_BMPEXSCALEPART_ACTION ); 793 } 794 } 795 796 // ------------------------------------------------------------------ 797 798 void OutputDevice::DrawTransformedBitmapEx( 799 const basegfx::B2DHomMatrix& rTransformation, 800 const BitmapEx& rBitmapEx) 801 { 802 DBG_TRACE( "OutputDevice::DrawBitmapEx( Point, Size )" ); 803 804 if( ImplIsRecordLayout() ) 805 return; 806 807 if(rBitmapEx.IsEmpty()) 808 return; 809 810 if ( mnDrawMode & DRAWMODE_NOBITMAP ) 811 return; 812 813 // decompose matrix to check rotation and shear 814 basegfx::B2DVector aScale, aTranslate; 815 double fRotate, fShearX; 816 rTransformation.decompose(aScale, aTranslate, fRotate, fShearX); 817 const bool bRotated(!basegfx::fTools::equalZero(fRotate)); 818 const bool bSheared(!basegfx::fTools::equalZero(fShearX)); 819 const bool bMirroredX(basegfx::fTools::less(aScale.getX(), 0.0)); 820 const bool bMirroredY(basegfx::fTools::less(aScale.getY(), 0.0)); 821 822 if(!bRotated && !bSheared && !bMirroredX && !bMirroredY) 823 { 824 // with no rotation, shear or mirroring it can be mapped to DrawBitmapEx 825 // do *not* execute the mirroring here, it's done in the fallback 826 const Point aDestPt(basegfx::fround(aTranslate.getX()), basegfx::fround(aTranslate.getY())); 827 const Size aDestSize(basegfx::fround(aScale.getX()), basegfx::fround(aScale.getY())); 828 829 DrawBitmapEx(aDestPt, aDestSize, rBitmapEx); 830 return; 831 } 832 833 // we have rotation,shear or mirror, check if some crazy mode needs the 834 // created transformed bitmap 835 const bool bInvert(ROP_INVERT == meRasterOp); 836 const bool bBitmapChangedColor(mnDrawMode & (DRAWMODE_BLACKBITMAP | DRAWMODE_WHITEBITMAP | DRAWMODE_GRAYBITMAP | DRAWMODE_GHOSTEDBITMAP)); 837 const bool bMetafile(mpMetaFile); 838 const bool bPrinter(OUTDEV_PRINTER == meOutDevType); 839 bool bDone(false); 840 const basegfx::B2DHomMatrix aFullTransform(GetViewTransformation() * rTransformation); 841 const bool bTryDirectPaint(!bInvert && !bBitmapChangedColor && !bMetafile && !bPrinter); 842 843 if(bTryDirectPaint) 844 { 845 // try to paint directly 846 const basegfx::B2DPoint aNull(aFullTransform * basegfx::B2DPoint(0.0, 0.0)); 847 const basegfx::B2DPoint aTopX(aFullTransform * basegfx::B2DPoint(1.0, 0.0)); 848 const basegfx::B2DPoint aTopY(aFullTransform * basegfx::B2DPoint(0.0, 1.0)); 849 SalBitmap* pSalSrcBmp = rBitmapEx.GetBitmap().ImplGetImpBitmap()->ImplGetSalBitmap(); 850 SalBitmap* pSalAlphaBmp = 0; 851 852 if(rBitmapEx.IsTransparent()) 853 { 854 if(rBitmapEx.IsAlpha()) 855 { 856 pSalAlphaBmp = rBitmapEx.GetAlpha().ImplGetImpBitmap()->ImplGetSalBitmap(); 857 } 858 else 859 { 860 pSalAlphaBmp = rBitmapEx.GetMask().ImplGetImpBitmap()->ImplGetSalBitmap(); 861 } 862 } 863 864 bDone = mpGraphics->DrawTransformedBitmap( 865 aNull, 866 aTopX, 867 aTopY, 868 *pSalSrcBmp, 869 pSalAlphaBmp, 870 this); 871 } 872 873 if(!bDone) 874 { 875 // take the fallback when no rotate and shear, but mirror (else we would have done this above) 876 if(!bRotated && !bSheared) 877 { 878 // with no rotation or shear it can be mapped to DrawBitmapEx 879 // do *not* execute the mirroring here, it's done in the fallback 880 const Point aDestPt(basegfx::fround(aTranslate.getX()), basegfx::fround(aTranslate.getY())); 881 const Size aDestSize(basegfx::fround(aScale.getX()), basegfx::fround(aScale.getY())); 882 883 DrawBitmapEx(aDestPt, aDestSize, rBitmapEx); 884 return; 885 } 886 887 // fallback; create transformed bitmap the hard way (back-transform 888 // the pixels) and paint 889 basegfx::B2DRange aTargetRange(0.0, 0.0, 1.0, 1.0); 890 const double fMaximumArea(bMetafile ? 800000.0 : 200000.0); 891 const BitmapEx aTransformed(rBitmapEx.getTransformed(aFullTransform, fMaximumArea)); 892 aTargetRange.transform(rTransformation); 893 const Point aDestPt(basegfx::fround(aTargetRange.getMinX()), basegfx::fround(aTargetRange.getMinY())); 894 const Size aDestSize(basegfx::fround(aTargetRange.getWidth()), basegfx::fround(aTargetRange.getHeight())); 895 896 DrawBitmapEx(aDestPt, aDestSize, aTransformed); 897 } 898 } 899 900 // ------------------------------------------------------------------ 901 902 void OutputDevice::ImplDrawBitmapEx( const Point& rDestPt, const Size& rDestSize, 903 const Point& rSrcPtPixel, const Size& rSrcSizePixel, 904 const BitmapEx& rBitmapEx, const sal_uLong nAction ) 905 { 906 DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); 907 OSL_ENSURE(TRANSPARENT_NONE != rBitmapEx.GetTransparentType(), "ImplDrawBitmapEx not needed, no transparency in BitmapEx (!)"); 908 909 if ( mnDrawMode & DRAWMODE_NOBITMAP ) 910 return; 911 912 if ( ROP_INVERT == meRasterOp ) 913 { 914 DrawRect( Rectangle( rDestPt, rDestSize ) ); 915 return; 916 } 917 918 BitmapEx aBmpEx( rBitmapEx ); 919 920 if ( mnDrawMode & ( DRAWMODE_BLACKBITMAP | DRAWMODE_WHITEBITMAP | 921 DRAWMODE_GRAYBITMAP | DRAWMODE_GHOSTEDBITMAP ) ) 922 { 923 if ( mnDrawMode & ( DRAWMODE_BLACKBITMAP | DRAWMODE_WHITEBITMAP ) ) 924 { 925 Bitmap aColorBmp( aBmpEx.GetSizePixel(), ( mnDrawMode & DRAWMODE_GHOSTEDBITMAP ) ? 4 : 1 ); 926 sal_uInt8 cCmpVal; 927 928 if ( mnDrawMode & DRAWMODE_BLACKBITMAP ) 929 cCmpVal = ( mnDrawMode & DRAWMODE_GHOSTEDBITMAP ) ? 0x80 : 0; 930 else 931 cCmpVal = 255; 932 933 aColorBmp.Erase( Color( cCmpVal, cCmpVal, cCmpVal ) ); 934 935 if( aBmpEx.IsAlpha() ) 936 { 937 // Create one-bit mask out of alpha channel, by 938 // thresholding it at alpha=0.5. As 939 // DRAWMODE_BLACK/WHITEBITMAP requires monochrome 940 // output, having alpha-induced grey levels is not 941 // acceptable. 942 Bitmap aMask( aBmpEx.GetAlpha().GetBitmap() ); 943 aMask.MakeMono( 128 ); 944 aBmpEx = BitmapEx( aColorBmp, aMask ); 945 } 946 else 947 { 948 aBmpEx = BitmapEx( aColorBmp, aBmpEx.GetMask() ); 949 } 950 } 951 else if( !!aBmpEx ) 952 { 953 if ( mnDrawMode & DRAWMODE_GRAYBITMAP ) 954 aBmpEx.Convert( BMP_CONVERSION_8BIT_GREYS ); 955 956 if ( mnDrawMode & DRAWMODE_GHOSTEDBITMAP ) 957 aBmpEx.Convert( BMP_CONVERSION_GHOSTED ); 958 } 959 } 960 961 if ( mpMetaFile ) 962 { 963 switch( nAction ) 964 { 965 case( META_BMPEX_ACTION ): 966 mpMetaFile->AddAction( new MetaBmpExAction( rDestPt, aBmpEx ) ); 967 break; 968 969 case( META_BMPEXSCALE_ACTION ): 970 mpMetaFile->AddAction( new MetaBmpExScaleAction( rDestPt, rDestSize, aBmpEx ) ); 971 break; 972 973 case( META_BMPEXSCALEPART_ACTION ): 974 mpMetaFile->AddAction( new MetaBmpExScalePartAction( rDestPt, rDestSize, 975 rSrcPtPixel, rSrcSizePixel, aBmpEx ) ); 976 break; 977 } 978 } 979 980 OUTDEV_INIT(); 981 982 if( OUTDEV_PRINTER == meOutDevType ) 983 { 984 if( aBmpEx.IsAlpha() ) 985 { 986 // #107169# For true alpha bitmaps, no longer masking the 987 // bitmap, but perform a full alpha blend against a white 988 // background here. 989 Bitmap aBmp( aBmpEx.GetBitmap() ); 990 aBmp.Blend( aBmpEx.GetAlpha(), Color( COL_WHITE) ); 991 DrawBitmap( rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel, aBmp ); 992 } 993 else 994 { 995 Bitmap aBmp( aBmpEx.GetBitmap() ), aMask( aBmpEx.GetMask() ); 996 aBmp.Replace( aMask, Color( COL_WHITE ) ); 997 ImplPrintTransparent( aBmp, aMask, rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel ); 998 } 999 1000 return; 1001 } 1002 1003 if(aBmpEx.IsAlpha()) 1004 { 1005 ImplDrawAlpha( aBmpEx.GetBitmap(), aBmpEx.GetAlpha(), rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel ); 1006 return; 1007 } 1008 1009 if( !( !aBmpEx ) ) 1010 { 1011 SalTwoRect aPosAry; 1012 1013 aPosAry.mnSrcX = rSrcPtPixel.X(); 1014 aPosAry.mnSrcY = rSrcPtPixel.Y(); 1015 aPosAry.mnSrcWidth = rSrcSizePixel.Width(); 1016 aPosAry.mnSrcHeight = rSrcSizePixel.Height(); 1017 aPosAry.mnDestX = ImplLogicXToDevicePixel( rDestPt.X() ); 1018 aPosAry.mnDestY = ImplLogicYToDevicePixel( rDestPt.Y() ); 1019 aPosAry.mnDestWidth = ImplLogicWidthToDevicePixel( rDestSize.Width() ); 1020 aPosAry.mnDestHeight = ImplLogicHeightToDevicePixel( rDestSize.Height() ); 1021 1022 const sal_uLong nMirrFlags = ImplAdjustTwoRect( aPosAry, aBmpEx.GetSizePixel() ); 1023 1024 if( aPosAry.mnSrcWidth && aPosAry.mnSrcHeight && aPosAry.mnDestWidth && aPosAry.mnDestHeight ) 1025 { 1026 1027 if( nMirrFlags ) 1028 aBmpEx.Mirror( nMirrFlags ); 1029 1030 const SalBitmap* pSalSrcBmp = aBmpEx.ImplGetBitmapImpBitmap()->ImplGetSalBitmap(); 1031 const ImpBitmap* pMaskBmp = aBmpEx.ImplGetMaskImpBitmap(); 1032 1033 if ( pMaskBmp ) 1034 { 1035 SalBitmap* pSalAlphaBmp = pMaskBmp->ImplGetSalBitmap(); 1036 bool bTryDirectPaint(pSalSrcBmp && pSalAlphaBmp); 1037 1038 if(bTryDirectPaint) 1039 { 1040 // only paint direct when no scaling and no MapMode, else the 1041 // more expensive conversions may be done for short-time Bitmap/BitmapEx 1042 // used for buffering only 1043 if(!IsMapMode() && aPosAry.mnSrcWidth == aPosAry.mnDestWidth && aPosAry.mnSrcHeight == aPosAry.mnDestHeight) 1044 { 1045 bTryDirectPaint = false; 1046 } 1047 } 1048 1049 if(bTryDirectPaint && mpGraphics->DrawAlphaBitmap(aPosAry, *pSalSrcBmp, *pSalAlphaBmp, this)) 1050 { 1051 // tried to paint as alpha directly. If tis worked, we are done (except 1052 // alpha, see below) 1053 } 1054 else 1055 { 1056 // #4919452# reduce operation area to bounds of 1057 // cliprect. since masked transparency involves 1058 // creation of a large vdev and copying the screen 1059 // content into that (slooow read from framebuffer), 1060 // that should considerably increase performance for 1061 // large bitmaps and small clippings. 1062 1063 // Note that this optimisation is a workaround for a 1064 // Writer peculiarity, namely, to decompose background 1065 // graphics into myriads of disjunct, tiny 1066 // rectangles. That otherwise kills us here, since for 1067 // transparent output, SAL always prepares the whole 1068 // bitmap, if aPosAry contains the whole bitmap (and 1069 // it's _not_ to blame for that). 1070 1071 // Note the call to ImplPixelToDevicePixel(), since 1072 // aPosAry already contains the mnOutOff-offsets, they 1073 // also have to be applied to the region 1074 Rectangle aClipRegionBounds( ImplPixelToDevicePixel(maRegion).GetBoundRect() ); 1075 1076 // TODO: Also respect scaling (that's a bit tricky, 1077 // since the source points have to move fractional 1078 // amounts (which is not possible, thus has to be 1079 // emulated by increases copy area) 1080 // const double nScaleX( aPosAry.mnDestWidth / aPosAry.mnSrcWidth ); 1081 // const double nScaleY( aPosAry.mnDestHeight / aPosAry.mnSrcHeight ); 1082 1083 // for now, only identity scales allowed 1084 if( !aClipRegionBounds.IsEmpty() && 1085 aPosAry.mnDestWidth == aPosAry.mnSrcWidth && 1086 aPosAry.mnDestHeight == aPosAry.mnSrcHeight ) 1087 { 1088 // now intersect dest rect with clip region 1089 aClipRegionBounds.Intersection( Rectangle( aPosAry.mnDestX, 1090 aPosAry.mnDestY, 1091 aPosAry.mnDestX + aPosAry.mnDestWidth - 1, 1092 aPosAry.mnDestY + aPosAry.mnDestHeight - 1 ) ); 1093 1094 // Note: I could theoretically optimize away the 1095 // DrawBitmap below, if the region is empty 1096 // here. Unfortunately, cannot rule out that 1097 // somebody relies on the side effects. 1098 if( !aClipRegionBounds.IsEmpty() ) 1099 { 1100 aPosAry.mnSrcX += aClipRegionBounds.Left() - aPosAry.mnDestX; 1101 aPosAry.mnSrcY += aClipRegionBounds.Top() - aPosAry.mnDestY; 1102 aPosAry.mnSrcWidth = aClipRegionBounds.GetWidth(); 1103 aPosAry.mnSrcHeight = aClipRegionBounds.GetHeight(); 1104 1105 aPosAry.mnDestX = aClipRegionBounds.Left(); 1106 aPosAry.mnDestY = aClipRegionBounds.Top(); 1107 aPosAry.mnDestWidth = aClipRegionBounds.GetWidth(); 1108 aPosAry.mnDestHeight = aClipRegionBounds.GetHeight(); 1109 } 1110 } 1111 1112 mpGraphics->DrawBitmap( aPosAry, *pSalSrcBmp, 1113 *pMaskBmp->ImplGetSalBitmap(), 1114 this ); 1115 } 1116 1117 // #110958# Paint mask to alpha channel. Luckily, the 1118 // black and white representation of the mask maps to 1119 // the alpha channel 1120 1121 // #i25167# Restrict mask painting to _opaque_ areas 1122 // of the mask, otherwise we spoil areas where no 1123 // bitmap content was ever visible. Interestingly 1124 // enough, this can be achieved by taking the mask as 1125 // the transparency mask of itself 1126 if( mpAlphaVDev ) 1127 mpAlphaVDev->DrawBitmapEx( rDestPt, 1128 rDestSize, 1129 BitmapEx( aBmpEx.GetMask(), 1130 aBmpEx.GetMask() ) ); 1131 } 1132 else 1133 { 1134 mpGraphics->DrawBitmap( aPosAry, *pSalSrcBmp, this ); 1135 1136 if( mpAlphaVDev ) 1137 { 1138 // #i32109#: Make bitmap area opaque 1139 mpAlphaVDev->ImplFillOpaqueRectangle( Rectangle(rDestPt, rDestSize) ); 1140 } 1141 } 1142 } 1143 } 1144 } 1145 1146 // ------------------------------------------------------------------ 1147 1148 void OutputDevice::DrawMask( const Point& rDestPt, 1149 const Bitmap& rBitmap, const Color& rMaskColor ) 1150 { 1151 DBG_TRACE( "OutputDevice::DrawMask()" ); 1152 1153 if( ImplIsRecordLayout() ) 1154 return; 1155 1156 const Size aSizePix( rBitmap.GetSizePixel() ); 1157 ImplDrawMask( rDestPt, PixelToLogic( aSizePix ), Point(), aSizePix, rBitmap, rMaskColor, META_MASK_ACTION ); 1158 1159 if( mpAlphaVDev ) 1160 { 1161 const Bitmap& rMask( rBitmap.CreateMask( rMaskColor ) ); 1162 1163 // #i25167# Restrict mask painting to _opaque_ areas 1164 // of the mask, otherwise we spoil areas where no 1165 // bitmap content was ever visible. Interestingly 1166 // enough, this can be achieved by taking the mask as 1167 // the transparency mask of itself 1168 mpAlphaVDev->DrawBitmapEx( rDestPt, 1169 PixelToLogic( aSizePix ), 1170 BitmapEx( rMask, rMask ) ); 1171 } 1172 } 1173 1174 // ------------------------------------------------------------------ 1175 1176 void OutputDevice::DrawMask( const Point& rDestPt, const Size& rDestSize, 1177 const Bitmap& rBitmap, const Color& rMaskColor ) 1178 { 1179 DBG_TRACE( "OutputDevice::DrawMask( Size )" ); 1180 1181 if( ImplIsRecordLayout() ) 1182 return; 1183 1184 ImplDrawMask( rDestPt, rDestSize, Point(), rBitmap.GetSizePixel(), rBitmap, rMaskColor, META_MASKSCALE_ACTION ); 1185 1186 // TODO: Use mask here 1187 if( mpAlphaVDev ) 1188 { 1189 const Bitmap& rMask( rBitmap.CreateMask( rMaskColor ) ); 1190 1191 // #i25167# Restrict mask painting to _opaque_ areas 1192 // of the mask, otherwise we spoil areas where no 1193 // bitmap content was ever visible. Interestingly 1194 // enough, this can be achieved by taking the mask as 1195 // the transparency mask of itself 1196 mpAlphaVDev->DrawBitmapEx( rDestPt, 1197 rDestSize, 1198 BitmapEx( rMask, rMask ) ); 1199 } 1200 } 1201 1202 // ------------------------------------------------------------------ 1203 1204 void OutputDevice::DrawMask( const Point& rDestPt, const Size& rDestSize, 1205 const Point& rSrcPtPixel, const Size& rSrcSizePixel, 1206 const Bitmap& rBitmap, const Color& rMaskColor ) 1207 { 1208 DBG_TRACE( "OutputDevice::DrawMask( Point, Size )" ); 1209 1210 if( ImplIsRecordLayout() ) 1211 return; 1212 1213 ImplDrawMask( rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel, rBitmap, rMaskColor, META_MASKSCALEPART_ACTION ); 1214 1215 // TODO: Use mask here 1216 if( mpAlphaVDev ) 1217 { 1218 const Bitmap& rMask( rBitmap.CreateMask( rMaskColor ) ); 1219 1220 // #i25167# Restrict mask painting to _opaque_ areas 1221 // of the mask, otherwise we spoil areas where no 1222 // bitmap content was ever visible. Interestingly 1223 // enough, this can be achieved by taking the mask as 1224 // the transparency mask of itself 1225 mpAlphaVDev->DrawBitmapEx( rDestPt, 1226 rDestSize, 1227 rSrcPtPixel, 1228 rSrcSizePixel, 1229 BitmapEx( rMask, rMask ) ); 1230 } 1231 } 1232 1233 // ------------------------------------------------------------------ 1234 1235 void OutputDevice::ImplDrawMask( const Point& rDestPt, const Size& rDestSize, 1236 const Point& rSrcPtPixel, const Size& rSrcSizePixel, 1237 const Bitmap& rBitmap, const Color& rMaskColor, 1238 const sal_uLong nAction ) 1239 { 1240 DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); 1241 1242 if( ROP_INVERT == meRasterOp ) 1243 { 1244 DrawRect( Rectangle( rDestPt, rDestSize ) ); 1245 return; 1246 } 1247 1248 if ( mpMetaFile ) 1249 { 1250 switch( nAction ) 1251 { 1252 case( META_MASK_ACTION ): 1253 mpMetaFile->AddAction( new MetaMaskAction( rDestPt, 1254 rBitmap, rMaskColor ) ); 1255 break; 1256 1257 case( META_MASKSCALE_ACTION ): 1258 mpMetaFile->AddAction( new MetaMaskScaleAction( rDestPt, 1259 rDestSize, rBitmap, rMaskColor ) ); 1260 break; 1261 1262 case( META_MASKSCALEPART_ACTION ): 1263 mpMetaFile->AddAction( new MetaMaskScalePartAction( rDestPt, rDestSize, 1264 rSrcPtPixel, rSrcSizePixel, rBitmap, rMaskColor ) ); 1265 break; 1266 } 1267 } 1268 1269 OUTDEV_INIT(); 1270 1271 if ( OUTDEV_PRINTER == meOutDevType ) 1272 { 1273 ImplPrintMask( rBitmap, rMaskColor, rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel ); 1274 return; 1275 } 1276 1277 const ImpBitmap* pImpBmp = rBitmap.ImplGetImpBitmap(); 1278 if ( pImpBmp ) 1279 { 1280 SalTwoRect aPosAry; 1281 1282 aPosAry.mnSrcX = rSrcPtPixel.X(); 1283 aPosAry.mnSrcY = rSrcPtPixel.Y(); 1284 aPosAry.mnSrcWidth = rSrcSizePixel.Width(); 1285 aPosAry.mnSrcHeight = rSrcSizePixel.Height(); 1286 aPosAry.mnDestX = ImplLogicXToDevicePixel( rDestPt.X() ); 1287 aPosAry.mnDestY = ImplLogicYToDevicePixel( rDestPt.Y() ); 1288 aPosAry.mnDestWidth = ImplLogicWidthToDevicePixel( rDestSize.Width() ); 1289 aPosAry.mnDestHeight = ImplLogicHeightToDevicePixel( rDestSize.Height() ); 1290 1291 // spiegeln via Koordinaten wollen wir nicht 1292 const sal_uLong nMirrFlags = ImplAdjustTwoRect( aPosAry, pImpBmp->ImplGetSize() ); 1293 1294 // check if output is necessary 1295 if( aPosAry.mnSrcWidth && aPosAry.mnSrcHeight && aPosAry.mnDestWidth && aPosAry.mnDestHeight ) 1296 { 1297 1298 if( nMirrFlags ) 1299 { 1300 Bitmap aTmp( rBitmap ); 1301 aTmp.Mirror( nMirrFlags ); 1302 mpGraphics->DrawMask( aPosAry, *aTmp.ImplGetImpBitmap()->ImplGetSalBitmap(), 1303 ImplColorToSal( rMaskColor ) , this); 1304 } 1305 else 1306 mpGraphics->DrawMask( aPosAry, *pImpBmp->ImplGetSalBitmap(), 1307 ImplColorToSal( rMaskColor ), this ); 1308 1309 } 1310 } 1311 } 1312 1313 // ------------------------------------------------------------------ 1314 1315 void OutputDevice::DrawImage( const Point& rPos, const Image& rImage, sal_uInt16 nStyle ) 1316 { 1317 DBG_ASSERT( GetOutDevType() != OUTDEV_PRINTER, "DrawImage(): Images can't be drawn on any mprinter" ); 1318 1319 if( !rImage.mpImplData || ImplIsRecordLayout() ) 1320 return; 1321 1322 switch( rImage.mpImplData->meType ) 1323 { 1324 case IMAGETYPE_BITMAP: 1325 DrawBitmap( rPos, *static_cast< Bitmap* >( rImage.mpImplData->mpData ) ); 1326 break; 1327 1328 case IMAGETYPE_IMAGE: 1329 { 1330 ImplImageData* pData = static_cast< ImplImageData* >( rImage.mpImplData->mpData ); 1331 1332 if( !pData->mpImageBitmap ) 1333 { 1334 const Size aSize( pData->maBmpEx.GetSizePixel() ); 1335 1336 pData->mpImageBitmap = new ImplImageBmp; 1337 pData->mpImageBitmap->Create( pData->maBmpEx, aSize.Width(), aSize.Height(), 1 ); 1338 } 1339 1340 pData->mpImageBitmap->Draw( 0, this, rPos, nStyle ); 1341 } 1342 break; 1343 1344 default: 1345 break; 1346 } 1347 } 1348 1349 // ------------------------------------------------------------------ 1350 1351 void OutputDevice::DrawImage( const Point& rPos, const Size& rSize, 1352 const Image& rImage, sal_uInt16 nStyle ) 1353 { 1354 DBG_ASSERT( GetOutDevType() != OUTDEV_PRINTER, "DrawImage(): Images can't be drawn on any mprinter" ); 1355 1356 if( rImage.mpImplData && !ImplIsRecordLayout() ) 1357 { 1358 switch( rImage.mpImplData->meType ) 1359 { 1360 case IMAGETYPE_BITMAP: 1361 DrawBitmap( rPos, rSize, *static_cast< Bitmap* >( rImage.mpImplData->mpData ) ); 1362 break; 1363 1364 case IMAGETYPE_IMAGE: 1365 { 1366 ImplImageData* pData = static_cast< ImplImageData* >( rImage.mpImplData->mpData ); 1367 1368 if ( !pData->mpImageBitmap ) 1369 { 1370 const Size aSize( pData->maBmpEx.GetSizePixel() ); 1371 1372 pData->mpImageBitmap = new ImplImageBmp; 1373 pData->mpImageBitmap->Create( pData->maBmpEx, aSize.Width(), aSize.Height(), 1 ); 1374 } 1375 1376 pData->mpImageBitmap->Draw( 0, this, rPos, nStyle, &rSize ); 1377 } 1378 break; 1379 1380 default: 1381 break; 1382 } 1383 } 1384 } 1385 1386 // ------------------------------------------------------------------ 1387 1388 Bitmap OutputDevice::GetBitmap( const Point& rSrcPt, const Size& rSize ) const 1389 { 1390 DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); 1391 1392 Bitmap aBmp; 1393 long nX = ImplLogicXToDevicePixel( rSrcPt.X() ); 1394 long nY = ImplLogicYToDevicePixel( rSrcPt.Y() ); 1395 long nWidth = ImplLogicWidthToDevicePixel( rSize.Width() ); 1396 long nHeight = ImplLogicHeightToDevicePixel( rSize.Height() ); 1397 1398 if ( mpGraphics || ( (OutputDevice*) this )->ImplGetGraphics() ) 1399 { 1400 if ( nWidth && nHeight ) 1401 { 1402 Rectangle aRect( Point( nX, nY ), Size( nWidth, nHeight ) ); 1403 sal_Bool bClipped = sal_False; 1404 1405 // X-Koordinate ausserhalb des Bereichs? 1406 if ( nX < mnOutOffX ) 1407 { 1408 nWidth -= ( mnOutOffX - nX ); 1409 nX = mnOutOffX; 1410 bClipped = sal_True; 1411 } 1412 1413 // Y-Koordinate ausserhalb des Bereichs? 1414 if ( nY < mnOutOffY ) 1415 { 1416 nHeight -= ( mnOutOffY - nY ); 1417 nY = mnOutOffY; 1418 bClipped = sal_True; 1419 } 1420 1421 // Breite ausserhalb des Bereichs? 1422 if ( (nWidth + nX) > (mnOutWidth + mnOutOffX) ) 1423 { 1424 nWidth = mnOutOffX + mnOutWidth - nX; 1425 bClipped = sal_True; 1426 } 1427 1428 // Hoehe ausserhalb des Bereichs? 1429 if ( (nHeight + nY) > (mnOutHeight + mnOutOffY) ) 1430 { 1431 nHeight = mnOutOffY + mnOutHeight - nY; 1432 bClipped = sal_True; 1433 } 1434 1435 if ( bClipped ) 1436 { 1437 // Falls auf den sichtbaren Bereich geclipped wurde, 1438 // muessen wir eine Bitmap in der rchtigen Groesse 1439 // erzeugen, in die die geclippte Bitmap an die angepasste 1440 // Position kopiert wird 1441 VirtualDevice aVDev( *this ); 1442 1443 if ( aVDev.SetOutputSizePixel( aRect.GetSize() ) ) 1444 { 1445 if ( ((OutputDevice*)&aVDev)->mpGraphics || ((OutputDevice*)&aVDev)->ImplGetGraphics() ) 1446 { 1447 SalTwoRect aPosAry; 1448 1449 aPosAry.mnSrcX = nX; 1450 aPosAry.mnSrcY = nY; 1451 aPosAry.mnSrcWidth = nWidth; 1452 aPosAry.mnSrcHeight = nHeight; 1453 aPosAry.mnDestX = ( aRect.Left() < mnOutOffX ) ? ( mnOutOffX - aRect.Left() ) : 0L; 1454 aPosAry.mnDestY = ( aRect.Top() < mnOutOffY ) ? ( mnOutOffY - aRect.Top() ) : 0L; 1455 aPosAry.mnDestWidth = nWidth; 1456 aPosAry.mnDestHeight = nHeight; 1457 1458 if ( (nWidth > 0) && (nHeight > 0) ) 1459 (((OutputDevice*)&aVDev)->mpGraphics)->CopyBits( aPosAry, mpGraphics, this, this ); 1460 1461 aBmp = aVDev.GetBitmap( Point(), aVDev.GetOutputSizePixel() ); 1462 } 1463 else 1464 bClipped = sal_False; 1465 } 1466 else 1467 bClipped = sal_False; 1468 } 1469 1470 if ( !bClipped ) 1471 { 1472 SalBitmap* pSalBmp = mpGraphics->GetBitmap( nX, nY, nWidth, nHeight, this ); 1473 1474 if( pSalBmp ) 1475 { 1476 ImpBitmap* pImpBmp = new ImpBitmap; 1477 pImpBmp->ImplSetSalBitmap( pSalBmp ); 1478 aBmp.ImplSetImpBitmap( pImpBmp ); 1479 } 1480 } 1481 } 1482 } 1483 1484 return aBmp; 1485 } 1486 1487 // ------------------------------------------------------------------ 1488 1489 BitmapEx OutputDevice::GetBitmapEx( const Point& rSrcPt, const Size& rSize ) const 1490 { 1491 DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); 1492 1493 // #110958# Extract alpha value from VDev, if any 1494 if( mpAlphaVDev ) 1495 { 1496 Bitmap aAlphaBitmap( mpAlphaVDev->GetBitmap( rSrcPt, rSize ) ); 1497 1498 // ensure 8 bit alpha 1499 if( aAlphaBitmap.GetBitCount() > 8 ) 1500 aAlphaBitmap.Convert( BMP_CONVERSION_8BIT_GREYS ); 1501 1502 return BitmapEx(GetBitmap( rSrcPt, rSize ), AlphaMask( aAlphaBitmap ) ); 1503 } 1504 else 1505 return GetBitmap( rSrcPt, rSize ); 1506 } 1507 1508 // ------------------------------------------------------------------ 1509 1510 void OutputDevice::ImplGetFrameBitmap( const Point& rDestPt, const Size& rSize, 1511 Bitmap& rBitmap ) const 1512 { 1513 DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); 1514 1515 sal_Bool bOldMap = mbMap; 1516 ((OutputDevice*)this)->mbMap = sal_False; 1517 rBitmap = GetBitmap( rDestPt, rSize ); 1518 ((OutputDevice*)this)->mbMap = bOldMap; 1519 } 1520 1521 // ------------------------------------------------------------------ 1522 1523 Color OutputDevice::GetPixel( const Point& rPt ) const 1524 { 1525 DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); 1526 1527 Color aColor; 1528 1529 if ( mpGraphics || ((OutputDevice*)this)->ImplGetGraphics() ) 1530 { 1531 if ( mbInitClipRegion ) 1532 ((OutputDevice*)this)->ImplInitClipRegion(); 1533 1534 if ( !mbOutputClipped ) 1535 { 1536 const long nX = ImplLogicXToDevicePixel( rPt.X() ); 1537 const long nY = ImplLogicYToDevicePixel( rPt.Y() ); 1538 const SalColor aSalCol = mpGraphics->GetPixel( nX, nY, this ); 1539 aColor.SetRed( SALCOLOR_RED( aSalCol ) ); 1540 aColor.SetGreen( SALCOLOR_GREEN( aSalCol ) ); 1541 aColor.SetBlue( SALCOLOR_BLUE( aSalCol ) ); 1542 } 1543 } 1544 return aColor; 1545 } 1546 1547 // ------------------------------------------------------------------ 1548 1549 Color* OutputDevice::GetPixel( const Polygon& rPts ) const 1550 { 1551 DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); 1552 1553 Color* pColors = NULL; 1554 const sal_uInt16 nSize = rPts.GetSize(); 1555 1556 if( nSize ) 1557 { 1558 if ( mpGraphics || ((OutputDevice*)this)->ImplGetGraphics() ) 1559 { 1560 if ( mbInitClipRegion ) 1561 ((OutputDevice*)this)->ImplInitClipRegion(); 1562 1563 if ( !mbOutputClipped ) 1564 { 1565 pColors = new Color[ nSize ]; 1566 1567 for( sal_uInt16 i = 0; i < nSize; i++ ) 1568 { 1569 Color& rCol = pColors[ i ]; 1570 const Point& rPt = rPts[ i ]; 1571 const SalColor aSalCol( mpGraphics->GetPixel( ImplLogicXToDevicePixel( rPt.X() ), 1572 ImplLogicYToDevicePixel( rPt.Y() ) , this) ); 1573 1574 rCol.SetRed( SALCOLOR_RED( aSalCol ) ); 1575 rCol.SetGreen( SALCOLOR_GREEN( aSalCol ) ); 1576 rCol.SetBlue( SALCOLOR_BLUE( aSalCol ) ); 1577 } 1578 } 1579 } 1580 } 1581 1582 return pColors; 1583 } 1584 1585 // ----------------------------------------------------------------------- 1586 1587 void OutputDevice::DrawPixel( const Point& rPt ) 1588 { 1589 DBG_TRACE( "OutputDevice::DrawPixel()" ); 1590 DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); 1591 1592 if ( mpMetaFile ) 1593 mpMetaFile->AddAction( new MetaPointAction( rPt ) ); 1594 1595 if ( !IsDeviceOutputNecessary() || !mbLineColor || ImplIsRecordLayout() ) 1596 return; 1597 1598 Point aPt = ImplLogicToDevicePixel( rPt ); 1599 1600 // we need a graphics 1601 if ( !mpGraphics ) 1602 { 1603 if ( !ImplGetGraphics() ) 1604 return; 1605 } 1606 1607 if ( mbInitClipRegion ) 1608 ImplInitClipRegion(); 1609 if ( mbOutputClipped ) 1610 return; 1611 1612 if ( mbInitLineColor ) 1613 ImplInitLineColor(); 1614 1615 mpGraphics->DrawPixel( aPt.X(), aPt.Y(), this ); 1616 1617 if( mpAlphaVDev ) 1618 mpAlphaVDev->DrawPixel( rPt ); 1619 } 1620 1621 // ----------------------------------------------------------------------- 1622 1623 void OutputDevice::DrawPixel( const Point& rPt, const Color& rColor ) 1624 { 1625 DBG_TRACE( "OutputDevice::DrawPixel()" ); 1626 DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); 1627 1628 Color aColor( rColor ); 1629 1630 if( mnDrawMode & ( DRAWMODE_BLACKLINE | DRAWMODE_WHITELINE | 1631 DRAWMODE_GRAYLINE | DRAWMODE_GHOSTEDLINE | 1632 DRAWMODE_SETTINGSLINE ) ) 1633 { 1634 if( !ImplIsColorTransparent( aColor ) ) 1635 { 1636 if( mnDrawMode & DRAWMODE_BLACKLINE ) 1637 { 1638 aColor = Color( COL_BLACK ); 1639 } 1640 else if( mnDrawMode & DRAWMODE_WHITELINE ) 1641 { 1642 aColor = Color( COL_WHITE ); 1643 } 1644 else if( mnDrawMode & DRAWMODE_GRAYLINE ) 1645 { 1646 const sal_uInt8 cLum = aColor.GetLuminance(); 1647 aColor = Color( cLum, cLum, cLum ); 1648 } 1649 else if( mnDrawMode & DRAWMODE_SETTINGSLINE ) 1650 { 1651 aColor = GetSettings().GetStyleSettings().GetFontColor(); 1652 } 1653 1654 if( mnDrawMode & DRAWMODE_GHOSTEDLINE ) 1655 { 1656 aColor = Color( ( aColor.GetRed() >> 1 ) | 0x80, 1657 ( aColor.GetGreen() >> 1 ) | 0x80, 1658 ( aColor.GetBlue() >> 1 ) | 0x80 ); 1659 } 1660 } 1661 } 1662 1663 if ( mpMetaFile ) 1664 mpMetaFile->AddAction( new MetaPixelAction( rPt, aColor ) ); 1665 1666 if ( !IsDeviceOutputNecessary() || ImplIsColorTransparent( aColor ) || ImplIsRecordLayout() ) 1667 return; 1668 1669 Point aPt = ImplLogicToDevicePixel( rPt ); 1670 1671 // we need a graphics 1672 if ( !mpGraphics ) 1673 { 1674 if ( !ImplGetGraphics() ) 1675 return; 1676 } 1677 1678 if ( mbInitClipRegion ) 1679 ImplInitClipRegion(); 1680 if ( mbOutputClipped ) 1681 return; 1682 1683 mpGraphics->DrawPixel( aPt.X(), aPt.Y(), ImplColorToSal( aColor ), this ); 1684 1685 if( mpAlphaVDev ) 1686 mpAlphaVDev->DrawPixel( rPt ); 1687 } 1688 1689 // ----------------------------------------------------------------------- 1690 1691 void OutputDevice::DrawPixel( const Polygon& rPts, const Color* pColors ) 1692 { 1693 if ( !pColors ) 1694 DrawPixel( rPts, GetLineColor() ); 1695 else 1696 { 1697 DBG_TRACE( "OutputDevice::DrawPixel()" ); 1698 DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); 1699 DBG_ASSERT( pColors, "OutputDevice::DrawPixel: No color array specified" ); 1700 1701 const sal_uInt16 nSize = rPts.GetSize(); 1702 1703 if ( nSize ) 1704 { 1705 if ( mpMetaFile ) 1706 for ( sal_uInt16 i = 0; i < nSize; i++ ) 1707 mpMetaFile->AddAction( new MetaPixelAction( rPts[ i ], pColors[ i ] ) ); 1708 1709 if ( !IsDeviceOutputNecessary() || ImplIsRecordLayout() ) 1710 return; 1711 1712 // we need a graphics 1713 if ( mpGraphics || ImplGetGraphics() ) 1714 { 1715 if ( mbInitClipRegion ) 1716 ImplInitClipRegion(); 1717 1718 if ( mbOutputClipped ) 1719 return; 1720 1721 for ( sal_uInt16 i = 0; i < nSize; i++ ) 1722 { 1723 const Point aPt( ImplLogicToDevicePixel( rPts[ i ] ) ); 1724 mpGraphics->DrawPixel( aPt.X(), aPt.Y(), ImplColorToSal( pColors[ i ] ), this ); 1725 } 1726 } 1727 } 1728 } 1729 1730 if( mpAlphaVDev ) 1731 mpAlphaVDev->DrawPixel( rPts, pColors ); 1732 } 1733 1734 // ----------------------------------------------------------------------- 1735 1736 void OutputDevice::DrawPixel( const Polygon& rPts, const Color& rColor ) 1737 { 1738 if( rColor != COL_TRANSPARENT && ! ImplIsRecordLayout() ) 1739 { 1740 const sal_uInt16 nSize = rPts.GetSize(); 1741 Color* pColArray = new Color[ nSize ]; 1742 1743 for( sal_uInt16 i = 0; i < nSize; i++ ) 1744 pColArray[ i ] = rColor; 1745 1746 DrawPixel( rPts, pColArray ); 1747 delete[] pColArray; 1748 } 1749 1750 if( mpAlphaVDev ) 1751 mpAlphaVDev->DrawPixel( rPts, rColor ); 1752 } 1753 1754 // ------------------------------------------------------------------------ 1755 1756 namespace 1757 { 1758 sal_uInt8 lcl_calcColor( const sal_uInt8 nSourceColor, const sal_uInt8 nSourceOpaq, const sal_uInt8 nDestColor ) 1759 { 1760 int c = ( (int)nDestColor * ( 255 - nSourceOpaq ) ) 1761 + (int)nSourceOpaq * (int)nSourceColor; 1762 return sal_uInt8( c / 255 ); 1763 } 1764 } 1765 1766 // ------------------------------------------------------------------------ 1767 1768 Bitmap OutputDevice::ImplBlendWithAlpha( Bitmap aBmp, 1769 BitmapReadAccess* pP, 1770 BitmapReadAccess* pA, 1771 const Rectangle& aDstRect, 1772 const sal_Int32 nOffY, 1773 const sal_Int32 nDstHeight, 1774 const sal_Int32 nOffX, 1775 const sal_Int32 nDstWidth, 1776 const long* pMapX, 1777 const long* pMapY ) 1778 { 1779 BitmapColor aDstCol,aSrcCol; 1780 Bitmap res; 1781 int nX, nOutX, nY, nOutY; 1782 1783 OSL_ENSURE(mpAlphaVDev, 1784 "ImplBlendWithAlpha(): call me only with valid alpha VDev!" ); 1785 1786 sal_Bool bOldMapMode( mpAlphaVDev->IsMapModeEnabled() ); 1787 mpAlphaVDev->EnableMapMode(sal_False); 1788 1789 Bitmap aAlphaBitmap( mpAlphaVDev->GetBitmap( aDstRect.TopLeft(), aDstRect.GetSize() ) ); 1790 BitmapWriteAccess* pAlphaW = aAlphaBitmap.AcquireWriteAccess(); 1791 1792 if( GetBitCount() <= 8 ) 1793 { 1794 Bitmap aDither( aBmp.GetSizePixel(), 8 ); 1795 BitmapColor aIndex( 0 ); 1796 BitmapReadAccess* pB = aBmp.AcquireReadAccess(); 1797 BitmapWriteAccess* pW = aDither.AcquireWriteAccess(); 1798 1799 if( pB && pP && pA && pW && pAlphaW ) 1800 { 1801 for( nY = 0, nOutY = nOffY; nY < nDstHeight; nY++, nOutY++ ) 1802 { 1803 const long nMapY = pMapY[ nY ]; 1804 const long nModY = ( nOutY & 0x0FL ) << 4L; 1805 1806 for( nX = 0, nOutX = nOffX; nX < nDstWidth; nX++, nOutX++ ) 1807 { 1808 const long nMapX = pMapX[ nX ]; 1809 const sal_uLong nD = nVCLDitherLut[ nModY | ( nOutX & 0x0FL ) ]; 1810 1811 aSrcCol = pP->GetColor( nMapY, nMapX ); 1812 aDstCol = pB->GetColor( nY, nX ); 1813 const sal_uInt8 nSrcOpaq = 255 - pA->GetPixelIndex( nMapY, nMapX ); 1814 const sal_uInt8 nDstOpaq = 255 - pAlphaW->GetPixelIndex( nY, nX ); 1815 1816 aDstCol.SetRed( lcl_calcColor( aSrcCol.GetRed(), nSrcOpaq, aDstCol.GetRed() ) ); 1817 aDstCol.SetBlue( lcl_calcColor( aSrcCol.GetBlue(), nSrcOpaq, aDstCol.GetBlue() ) ); 1818 aDstCol.SetGreen( lcl_calcColor( aSrcCol.GetGreen(), nSrcOpaq, aDstCol.GetGreen() ) ); 1819 1820 aIndex.SetIndex( (sal_uInt8) ( nVCLRLut[ ( nVCLLut[ aDstCol.GetRed() ] + nD ) >> 16UL ] + 1821 nVCLGLut[ ( nVCLLut[ aDstCol.GetGreen() ] + nD ) >> 16UL ] + 1822 nVCLBLut[ ( nVCLLut[ aDstCol.GetBlue() ] + nD ) >> 16UL ] ) ); 1823 pW->SetPixel( nY, nX, aIndex ); 1824 1825 // Have to perform the compositing 'algebra' in 1826 // the inverse alpha space (with 255 meaning 1827 // opaque), otherwise, transitivity is not 1828 // achieved. 1829 const sal_uInt8 nSrcAlpha = 255-COLOR_CHANNEL_MERGE( 255, (sal_uInt8)nDstOpaq, nSrcOpaq ); 1830 1831 aIndex.SetIndex( (sal_uInt8) ( nVCLRLut[ ( nVCLLut[ nSrcAlpha ] + nD ) >> 16UL ] + 1832 nVCLGLut[ ( nVCLLut[ nSrcAlpha ] + nD ) >> 16UL ] + 1833 nVCLBLut[ ( nVCLLut[ nSrcAlpha ] + nD ) >> 16UL ] ) ); 1834 pAlphaW->SetPixel( nY, nX, aIndex ); 1835 } 1836 } 1837 } 1838 1839 aBmp.ReleaseAccess( pB ); 1840 aDither.ReleaseAccess( pW ); 1841 res = aDither; 1842 } 1843 else 1844 { 1845 BitmapWriteAccess* pB = aBmp.AcquireWriteAccess(); 1846 if( pP && pA && pB ) 1847 { 1848 for( nY = 0; nY < nDstHeight; nY++ ) 1849 { 1850 const long nMapY = pMapY[ nY ]; 1851 1852 for( nX = 0; nX < nDstWidth; nX++ ) 1853 { 1854 const long nMapX = pMapX[ nX ]; 1855 1856 aSrcCol = pP->GetColor( nMapY, nMapX ); 1857 aDstCol = pB->GetColor( nY, nX ); 1858 const sal_uInt8 nSrcOpaq = 255 - pA->GetPixelIndex( nMapY, nMapX ); 1859 const sal_uInt8 nDstOpaq = 255 - pAlphaW->GetPixelIndex( nY, nX ); 1860 1861 aDstCol.SetRed( lcl_calcColor( aSrcCol.GetRed(), nSrcOpaq, aDstCol.GetRed() ) ); 1862 aDstCol.SetBlue( lcl_calcColor( aSrcCol.GetBlue(), nSrcOpaq, aDstCol.GetBlue() ) ); 1863 aDstCol.SetGreen( lcl_calcColor( aSrcCol.GetGreen(), nSrcOpaq, aDstCol.GetGreen() ) ); 1864 1865 pB->SetPixel( nY, nX, aDstCol ); 1866 1867 // Have to perform the compositing 'algebra' in 1868 // the inverse alpha space (with 255 meaning 1869 // opaque), otherwise, transitivity is not 1870 // achieved. 1871 const sal_uInt8 nSrcAlpha = 255-COLOR_CHANNEL_MERGE( 255, (sal_uInt8)nDstOpaq, nSrcOpaq ); 1872 1873 pAlphaW->SetPixel( nY, nX, Color(nSrcAlpha, nSrcAlpha, nSrcAlpha) ); 1874 } 1875 } 1876 } 1877 1878 aBmp.ReleaseAccess( pB ); 1879 res = aBmp; 1880 } 1881 1882 aAlphaBitmap.ReleaseAccess( pAlphaW ); 1883 mpAlphaVDev->DrawBitmap( aDstRect.TopLeft(), aAlphaBitmap ); 1884 mpAlphaVDev->EnableMapMode( bOldMapMode ); 1885 1886 return res; 1887 } 1888 1889 // ------------------------------------------------------------------------ 1890 1891 Bitmap OutputDevice::ImplBlend( Bitmap aBmp, 1892 BitmapReadAccess* pP, 1893 BitmapReadAccess* pA, 1894 const sal_Int32 nOffY, 1895 const sal_Int32 nDstHeight, 1896 const sal_Int32 nOffX, 1897 const sal_Int32 nDstWidth, 1898 const Rectangle& aBmpRect, 1899 const Size& aOutSz, 1900 const bool bHMirr, 1901 const bool bVMirr, 1902 const long* pMapX, 1903 const long* pMapY ) 1904 { 1905 BitmapColor aDstCol; 1906 Bitmap res; 1907 int nX, nOutX, nY, nOutY; 1908 1909 if( GetBitCount() <= 8 ) 1910 { 1911 Bitmap aDither( aBmp.GetSizePixel(), 8 ); 1912 BitmapColor aIndex( 0 ); 1913 BitmapReadAccess* pB = aBmp.AcquireReadAccess(); 1914 BitmapWriteAccess* pW = aDither.AcquireWriteAccess(); 1915 1916 if( pB && pP && pA && pW ) 1917 { 1918 for( nY = 0, nOutY = nOffY; nY < nDstHeight; nY++, nOutY++ ) 1919 { 1920 const long nMapY = pMapY[ nY ]; 1921 const long nModY = ( nOutY & 0x0FL ) << 4L; 1922 1923 for( nX = 0, nOutX = nOffX; nX < nDstWidth; nX++, nOutX++ ) 1924 { 1925 const long nMapX = pMapX[ nX ]; 1926 const sal_uLong nD = nVCLDitherLut[ nModY | ( nOutX & 0x0FL ) ]; 1927 1928 aDstCol = pB->GetColor( nY, nX ); 1929 aDstCol.Merge( pP->GetColor( nMapY, nMapX ), pA->GetPixelIndex( nMapY, nMapX ) ); 1930 aIndex.SetIndex( (sal_uInt8) ( nVCLRLut[ ( nVCLLut[ aDstCol.GetRed() ] + nD ) >> 16UL ] + 1931 nVCLGLut[ ( nVCLLut[ aDstCol.GetGreen() ] + nD ) >> 16UL ] + 1932 nVCLBLut[ ( nVCLLut[ aDstCol.GetBlue() ] + nD ) >> 16UL ] ) ); 1933 pW->SetPixel( nY, nX, aIndex ); 1934 } 1935 } 1936 } 1937 1938 aBmp.ReleaseAccess( pB ); 1939 aDither.ReleaseAccess( pW ); 1940 res = aDither; 1941 } 1942 else 1943 { 1944 BitmapWriteAccess* pB = aBmp.AcquireWriteAccess(); 1945 1946 bool bFastBlend = false; 1947 if( pP && pA && pB ) 1948 { 1949 SalTwoRect aTR; 1950 aTR.mnSrcX = aBmpRect.Left(); 1951 aTR.mnSrcY = aBmpRect.Top(); 1952 aTR.mnSrcWidth = aBmpRect.GetWidth(); 1953 aTR.mnSrcHeight = aBmpRect.GetHeight(); 1954 aTR.mnDestX = nOffX; 1955 aTR.mnDestY = nOffY; 1956 aTR.mnDestWidth = aOutSz.Width(); 1957 aTR.mnDestHeight= aOutSz.Height(); 1958 1959 if( !bHMirr || !bVMirr ) 1960 bFastBlend = ImplFastBitmapBlending( *pB,*pP,*pA, aTR ); 1961 } 1962 1963 if( pP && pA && pB && !bFastBlend ) 1964 { 1965 switch( pP->GetScanlineFormat() ) 1966 { 1967 case( BMP_FORMAT_8BIT_PAL ): 1968 { 1969 for( nY = 0; nY < nDstHeight; nY++ ) 1970 { 1971 const long nMapY = pMapY[ nY ]; 1972 Scanline pPScan = pP->GetScanline( nMapY ); 1973 Scanline pAScan = pA->GetScanline( nMapY ); 1974 1975 for( nX = 0; nX < nDstWidth; nX++ ) 1976 { 1977 const long nMapX = pMapX[ nX ]; 1978 aDstCol = pB->GetPixel( nY, nX ); 1979 pB->SetPixel( nY, nX, aDstCol.Merge( pP->GetPaletteColor( pPScan[ nMapX ] ), 1980 pAScan[ nMapX ] ) ); 1981 } 1982 } 1983 } 1984 break; 1985 1986 case( BMP_FORMAT_24BIT_TC_BGR ): 1987 { 1988 for( nY = 0; nY < nDstHeight; nY++ ) 1989 { 1990 const long nMapY = pMapY[ nY ]; 1991 Scanline pPScan = pP->GetScanline( nMapY ); 1992 Scanline pAScan = pA->GetScanline( nMapY ); 1993 1994 for( nX = 0; nX < nDstWidth; nX++ ) 1995 { 1996 const long nMapX = pMapX[ nX ]; 1997 Scanline pTmp = pPScan + nMapX * 3; 1998 1999 aDstCol = pB->GetPixel( nY, nX ); 2000 pB->SetPixel( nY, nX, aDstCol.Merge( pTmp[ 2 ], pTmp[ 1 ], pTmp[ 0 ], 2001 pAScan[ nMapX ] ) ); 2002 } 2003 } 2004 } 2005 break; 2006 2007 case( BMP_FORMAT_24BIT_TC_RGB ): 2008 { 2009 for( nY = 0; nY < nDstHeight; nY++ ) 2010 { 2011 const long nMapY = pMapY[ nY ]; 2012 Scanline pPScan = pP->GetScanline( nMapY ); 2013 Scanline pAScan = pA->GetScanline( nMapY ); 2014 2015 for( nX = 0; nX < nDstWidth; nX++ ) 2016 { 2017 const long nMapX = pMapX[ nX ]; 2018 Scanline pTmp = pPScan + nMapX * 3; 2019 2020 aDstCol = pB->GetPixel( nY, nX ); 2021 pB->SetPixel( nY, nX, aDstCol.Merge( pTmp[ 0 ], pTmp[ 1 ], pTmp[ 2 ], 2022 pAScan[ nMapX ] ) ); 2023 } 2024 } 2025 } 2026 break; 2027 2028 default: 2029 { 2030 for( nY = 0; nY < nDstHeight; nY++ ) 2031 { 2032 const long nMapY = pMapY[ nY ]; 2033 Scanline pAScan = pA->GetScanline( nMapY ); 2034 2035 for( nX = 0; nX < nDstWidth; nX++ ) 2036 { 2037 const long nMapX = pMapX[ nX ]; 2038 aDstCol = pB->GetPixel( nY, nX ); 2039 pB->SetPixel( nY, nX, aDstCol.Merge( pP->GetColor( nMapY, nMapX ), 2040 pAScan[ nMapX ] ) ); 2041 } 2042 } 2043 } 2044 break; 2045 } 2046 } 2047 2048 aBmp.ReleaseAccess( pB ); 2049 res = aBmp; 2050 } 2051 2052 return res; 2053 } 2054 2055 // ------------------------------------------------------------------------ 2056 2057 void OutputDevice::ImplDrawAlpha( const Bitmap& rBmp, const AlphaMask& rAlpha, 2058 const Point& rDestPt, const Size& rDestSize, 2059 const Point& rSrcPtPixel, const Size& rSrcSizePixel ) 2060 { 2061 const Point aNullPt; 2062 Point aOutPt( LogicToPixel( rDestPt ) ); 2063 Size aOutSz( LogicToPixel( rDestSize ) ); 2064 Rectangle aDstRect( aNullPt, GetOutputSizePixel() ); 2065 const sal_Bool bHMirr = aOutSz.Width() < 0, bVMirr = aOutSz.Height() < 0; 2066 2067 if( OUTDEV_WINDOW == meOutDevType ) 2068 { 2069 const Region aPaintRgn( ( (Window*) this )->GetPaintRegion() ); 2070 2071 if( !aPaintRgn.IsNull() ) 2072 aDstRect.Intersection( LogicToPixel( aPaintRgn.GetBoundRect() ) ); 2073 } 2074 2075 if( bHMirr ) 2076 { 2077 aOutSz.Width() = -aOutSz.Width(); 2078 aOutPt.X() -= ( aOutSz.Width() - 1L ); 2079 } 2080 2081 if( bVMirr ) 2082 { 2083 aOutSz.Height() = -aOutSz.Height(); 2084 aOutPt.Y() -= ( aOutSz.Height() - 1L ); 2085 } 2086 2087 if( !aDstRect.Intersection( Rectangle( aOutPt, aOutSz ) ).IsEmpty() ) 2088 { 2089 bool bNativeAlpha = false; 2090 static const char* pDisableNative = getenv( "SAL_DISABLE_NATIVE_ALPHA"); 2091 // #i83087# Naturally, system alpha blending cannot work with 2092 // separate alpha VDev 2093 bool bTryDirectPaint(!mpAlphaVDev && !pDisableNative && !bHMirr && !bVMirr); 2094 2095 #ifdef WNT 2096 if(bTryDirectPaint) 2097 { 2098 // only paint direct when no scaling and no MapMode, else the 2099 // more expensive conversions may be done for short-time Bitmap/BitmapEx 2100 // used for buffering only 2101 if(!IsMapMode() && rSrcSizePixel.Width() == aOutSz.Width() && rSrcSizePixel.Height() == aOutSz.Height()) 2102 { 2103 bTryDirectPaint = false; 2104 } 2105 } 2106 #endif 2107 2108 if(bTryDirectPaint) 2109 { 2110 Point aRelPt = aOutPt + Point( mnOutOffX, mnOutOffY ); 2111 SalTwoRect aTR = { 2112 rSrcPtPixel.X(), rSrcPtPixel.Y(), 2113 rSrcSizePixel.Width(), rSrcSizePixel.Height(), 2114 aRelPt.X(), aRelPt.Y(), 2115 aOutSz.Width(), aOutSz.Height() 2116 }; 2117 SalBitmap* pSalSrcBmp = rBmp.ImplGetImpBitmap()->ImplGetSalBitmap(); 2118 SalBitmap* pSalAlphaBmp = rAlpha.ImplGetImpBitmap()->ImplGetSalBitmap(); 2119 bNativeAlpha = mpGraphics->DrawAlphaBitmap( aTR, *pSalSrcBmp, *pSalAlphaBmp, this ); 2120 } 2121 2122 VirtualDevice* pOldVDev = mpAlphaVDev; 2123 2124 Rectangle aBmpRect( aNullPt, rBmp.GetSizePixel() ); 2125 if( !bNativeAlpha 2126 && !aBmpRect.Intersection( Rectangle( rSrcPtPixel, rSrcSizePixel ) ).IsEmpty() ) 2127 { 2128 GDIMetaFile* pOldMetaFile = mpMetaFile; mpMetaFile = NULL; 2129 const sal_Bool bOldMap = mbMap; mbMap = sal_False; 2130 Bitmap aBmp( GetBitmap( aDstRect.TopLeft(), aDstRect.GetSize() ) ); 2131 2132 // #109044# The generated bitmap need not necessarily be 2133 // of aDstRect dimensions, it's internally clipped to 2134 // window bounds. Thus, we correct the dest size here, 2135 // since we later use it (in nDstWidth/Height) for pixel 2136 // access) 2137 // #i38887# reading from screen may sometimes fail 2138 if( aBmp.ImplGetImpBitmap() ) 2139 aDstRect.SetSize( aBmp.GetSizePixel() ); 2140 2141 BitmapColor aDstCol; 2142 const long nSrcWidth = aBmpRect.GetWidth(), nSrcHeight = aBmpRect.GetHeight(); 2143 const long nDstWidth = aDstRect.GetWidth(), nDstHeight = aDstRect.GetHeight(); 2144 const long nOutWidth = aOutSz.Width(), nOutHeight = aOutSz.Height(); 2145 // calculate offset in original bitmap 2146 // in RTL case this is a little more complicated since the contents of the 2147 // bitmap is not mirrored (it never is), however the paint region and bmp region 2148 // are in mirrored coordinates, so the intersection of (aOutPt,aOutSz) with these 2149 // is content wise somewhere else and needs to take mirroring into account 2150 const long nOffX = IsRTLEnabled() 2151 ? aOutSz.Width() - aDstRect.GetWidth() - (aDstRect.Left() - aOutPt.X()) 2152 : aDstRect.Left() - aOutPt.X(), 2153 nOffY = aDstRect.Top() - aOutPt.Y(); 2154 long nX, nOutX, nY, nOutY; 2155 long nMirrOffX = 0; 2156 long nMirrOffY = 0; 2157 long* pMapX = new long[ nDstWidth ]; 2158 long* pMapY = new long[ nDstHeight ]; 2159 2160 // create horizontal mapping table 2161 if( bHMirr ) 2162 nMirrOffX = ( aBmpRect.Left() << 1 ) + nSrcWidth - 1; 2163 2164 for( nX = 0L, nOutX = nOffX; nX < nDstWidth; nX++, nOutX++ ) 2165 { 2166 pMapX[ nX ] = aBmpRect.Left() + nOutX * nSrcWidth / nOutWidth; 2167 if( bHMirr ) 2168 pMapX[ nX ] = nMirrOffX - pMapX[ nX ]; 2169 } 2170 2171 // create vertical mapping table 2172 if( bVMirr ) 2173 nMirrOffY = ( aBmpRect.Top() << 1 ) + nSrcHeight - 1; 2174 2175 for( nY = 0L, nOutY = nOffY; nY < nDstHeight; nY++, nOutY++ ) 2176 { 2177 pMapY[ nY ] = aBmpRect.Top() + nOutY * nSrcHeight / nOutHeight; 2178 2179 if( bVMirr ) 2180 pMapY[ nY ] = nMirrOffY - pMapY[ nY ]; 2181 } 2182 2183 BitmapReadAccess* pP = ( (Bitmap&) rBmp ).AcquireReadAccess(); 2184 BitmapReadAccess* pA = ( (AlphaMask&) rAlpha ).AcquireReadAccess(); 2185 2186 DBG_ASSERT( pA->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL || 2187 pA->GetScanlineFormat() == BMP_FORMAT_8BIT_TC_MASK, 2188 "OutputDevice::ImplDrawAlpha(): non-8bit alpha no longer supported!" ); 2189 2190 // #i38887# reading from screen may sometimes fail 2191 if( aBmp.ImplGetImpBitmap() ) 2192 { 2193 Bitmap aTmp; 2194 2195 if( mpAlphaVDev ) 2196 { 2197 aTmp = ImplBlendWithAlpha( 2198 aBmp,pP,pA, 2199 aDstRect, 2200 nOffY,nDstHeight, 2201 nOffX,nDstWidth, 2202 pMapX,pMapY ); 2203 } 2204 else 2205 { 2206 aTmp = ImplBlend( 2207 aBmp,pP,pA, 2208 nOffY,nDstHeight, 2209 nOffX,nDstWidth, 2210 aBmpRect,aOutSz, 2211 bHMirr,bVMirr, 2212 pMapX,pMapY ); 2213 } 2214 2215 // #110958# Disable alpha VDev, we're doing the necessary 2216 // stuff explicitely furher below 2217 if( mpAlphaVDev ) 2218 mpAlphaVDev = NULL; 2219 2220 DrawBitmap( aDstRect.TopLeft(), 2221 aTmp ); 2222 2223 // #110958# Enable alpha VDev again 2224 mpAlphaVDev = pOldVDev; 2225 } 2226 2227 ( (Bitmap&) rBmp ).ReleaseAccess( pP ); 2228 ( (AlphaMask&) rAlpha ).ReleaseAccess( pA ); 2229 2230 delete[] pMapX; 2231 delete[] pMapY; 2232 mbMap = bOldMap; 2233 mpMetaFile = pOldMetaFile; 2234 } 2235 } 2236 } 2237 2238 // ------------------------------------------------------------------------ 2239 2240 void OutputDevice::ImplPrintTransparent( const Bitmap& rBmp, const Bitmap& rMask, 2241 const Point& rDestPt, const Size& rDestSize, 2242 const Point& rSrcPtPixel, const Size& rSrcSizePixel ) 2243 { 2244 Point aPt; 2245 Point aDestPt( LogicToPixel( rDestPt ) ); 2246 Size aDestSz( LogicToPixel( rDestSize ) ); 2247 Rectangle aSrcRect( rSrcPtPixel, rSrcSizePixel ); 2248 2249 aSrcRect.Justify(); 2250 2251 if( !rBmp.IsEmpty() && aSrcRect.GetWidth() && aSrcRect.GetHeight() && aDestSz.Width() && aDestSz.Height() ) 2252 { 2253 Bitmap aPaint( rBmp ), aMask( rMask ); 2254 sal_uLong nMirrFlags = 0UL; 2255 2256 if( aMask.GetBitCount() > 1 ) 2257 aMask.Convert( BMP_CONVERSION_1BIT_THRESHOLD ); 2258 2259 // mirrored horizontically 2260 if( aDestSz.Width() < 0L ) 2261 { 2262 aDestSz.Width() = -aDestSz.Width(); 2263 aDestPt.X() -= ( aDestSz.Width() - 1L ); 2264 nMirrFlags |= BMP_MIRROR_HORZ; 2265 } 2266 2267 // mirrored vertically 2268 if( aDestSz.Height() < 0L ) 2269 { 2270 aDestSz.Height() = -aDestSz.Height(); 2271 aDestPt.Y() -= ( aDestSz.Height() - 1L ); 2272 nMirrFlags |= BMP_MIRROR_VERT; 2273 } 2274 2275 // source cropped? 2276 if( aSrcRect != Rectangle( aPt, aPaint.GetSizePixel() ) ) 2277 { 2278 aPaint.Crop( aSrcRect ); 2279 aMask.Crop( aSrcRect ); 2280 } 2281 2282 // destination mirrored 2283 if( nMirrFlags ) 2284 { 2285 aPaint.Mirror( nMirrFlags ); 2286 aMask.Mirror( nMirrFlags ); 2287 } 2288 2289 // we always want to have a mask 2290 if( aMask.IsEmpty() ) 2291 { 2292 aMask = Bitmap( aSrcRect.GetSize(), 1 ); 2293 aMask.Erase( Color( COL_BLACK ) ); 2294 } 2295 2296 // do painting 2297 const long nSrcWidth = aSrcRect.GetWidth(), nSrcHeight = aSrcRect.GetHeight(); 2298 long nX, nY; // , nWorkX, nWorkY, nWorkWidth, nWorkHeight; 2299 long* pMapX = new long[ nSrcWidth + 1 ]; 2300 long* pMapY = new long[ nSrcHeight + 1 ]; 2301 const sal_Bool bOldMap = mbMap; 2302 2303 mbMap = sal_False; 2304 2305 // create forward mapping tables 2306 for( nX = 0L; nX <= nSrcWidth; nX++ ) 2307 pMapX[ nX ] = aDestPt.X() + FRound( (double) aDestSz.Width() * nX / nSrcWidth ); 2308 2309 for( nY = 0L; nY <= nSrcHeight; nY++ ) 2310 pMapY[ nY ] = aDestPt.Y() + FRound( (double) aDestSz.Height() * nY / nSrcHeight ); 2311 2312 // walk through all rectangles of mask 2313 const Region aWorkRgn(aMask.CreateRegion(COL_BLACK, Rectangle(Point(), aMask.GetSizePixel()))); 2314 RectangleVector aRectangles; 2315 aWorkRgn.GetRegionRectangles(aRectangles); 2316 2317 for(RectangleVector::const_iterator aRectIter(aRectangles.begin()); aRectIter != aRectangles.end(); aRectIter++) 2318 { 2319 const Point aMapPt(pMapX[aRectIter->Left()], pMapY[aRectIter->Top()]); 2320 const Size aMapSz( 2321 pMapX[aRectIter->Right() + 1] - aMapPt.X(), // pMapX[L + W] -> L + ((R - L) + 1) -> R + 1 2322 pMapY[aRectIter->Bottom() + 1] - aMapPt.Y()); // same for Y 2323 Bitmap aBandBmp(aPaint); 2324 2325 aBandBmp.Crop(*aRectIter); 2326 ImplDrawBitmap(aMapPt, aMapSz, Point(), aBandBmp.GetSizePixel(), aBandBmp, META_BMPSCALEPART_ACTION); 2327 } 2328 2329 //Region aWorkRgn( aMask.CreateRegion( COL_BLACK, Rectangle( Point(), aMask.GetSizePixel() ) ) ); 2330 //ImplRegionInfo aInfo; 2331 //sal_Bool bRgnRect = aWorkRgn.ImplGetFirstRect( aInfo, nWorkX, nWorkY, nWorkWidth, nWorkHeight ); 2332 // 2333 //while( bRgnRect ) 2334 //{ 2335 // Bitmap aBandBmp( aPaint ); 2336 // const Rectangle aBandRect( Point( nWorkX, nWorkY ), Size( nWorkWidth, nWorkHeight ) ); 2337 // const Point aMapPt( pMapX[ nWorkX ], pMapY[ nWorkY ] ); 2338 // const Size aMapSz( pMapX[ nWorkX + nWorkWidth ] - aMapPt.X(), pMapY[ nWorkY + nWorkHeight ] - aMapPt.Y() ); 2339 // 2340 // aBandBmp.Crop( aBandRect ); 2341 // ImplDrawBitmap( aMapPt, aMapSz, Point(), aBandBmp.GetSizePixel(), aBandBmp, META_BMPSCALEPART_ACTION ); 2342 // bRgnRect = aWorkRgn.ImplGetNextRect( aInfo, nWorkX, nWorkY, nWorkWidth, nWorkHeight ); 2343 //} 2344 2345 mbMap = bOldMap; 2346 2347 delete[] pMapX; 2348 delete[] pMapY; 2349 } 2350 } 2351 2352 // ------------------------------------------------------------------------ 2353 2354 void OutputDevice::ImplPrintMask( const Bitmap& rMask, const Color& rMaskColor, 2355 const Point& rDestPt, const Size& rDestSize, 2356 const Point& rSrcPtPixel, const Size& rSrcSizePixel ) 2357 { 2358 Point aPt; 2359 Point aDestPt( LogicToPixel( rDestPt ) ); 2360 Size aDestSz( LogicToPixel( rDestSize ) ); 2361 Rectangle aSrcRect( rSrcPtPixel, rSrcSizePixel ); 2362 2363 aSrcRect.Justify(); 2364 2365 if( !rMask.IsEmpty() && aSrcRect.GetWidth() && aSrcRect.GetHeight() && aDestSz.Width() && aDestSz.Height() ) 2366 { 2367 Bitmap aMask( rMask ); 2368 sal_uLong nMirrFlags = 0UL; 2369 2370 if( aMask.GetBitCount() > 1 ) 2371 aMask.Convert( BMP_CONVERSION_1BIT_THRESHOLD ); 2372 2373 // mirrored horizontically 2374 if( aDestSz.Width() < 0L ) 2375 { 2376 aDestSz.Width() = -aDestSz.Width(); 2377 aDestPt.X() -= ( aDestSz.Width() - 1L ); 2378 nMirrFlags |= BMP_MIRROR_HORZ; 2379 } 2380 2381 // mirrored vertically 2382 if( aDestSz.Height() < 0L ) 2383 { 2384 aDestSz.Height() = -aDestSz.Height(); 2385 aDestPt.Y() -= ( aDestSz.Height() - 1L ); 2386 nMirrFlags |= BMP_MIRROR_VERT; 2387 } 2388 2389 // source cropped? 2390 if( aSrcRect != Rectangle( aPt, aMask.GetSizePixel() ) ) 2391 aMask.Crop( aSrcRect ); 2392 2393 // destination mirrored 2394 if( nMirrFlags ) 2395 aMask.Mirror( nMirrFlags ); 2396 2397 // do painting 2398 const long nSrcWidth = aSrcRect.GetWidth(), nSrcHeight = aSrcRect.GetHeight(); 2399 long nX, nY; //, nWorkX, nWorkY, nWorkWidth, nWorkHeight; 2400 long* pMapX = new long[ nSrcWidth + 1 ]; 2401 long* pMapY = new long[ nSrcHeight + 1 ]; 2402 GDIMetaFile* pOldMetaFile = mpMetaFile; 2403 const sal_Bool bOldMap = mbMap; 2404 2405 mpMetaFile = NULL; 2406 mbMap = sal_False; 2407 Push( PUSH_FILLCOLOR | PUSH_LINECOLOR ); 2408 SetLineColor( rMaskColor ); 2409 SetFillColor( rMaskColor ); 2410 ImplInitLineColor(); 2411 ImplInitFillColor(); 2412 2413 // create forward mapping tables 2414 for( nX = 0L; nX <= nSrcWidth; nX++ ) 2415 pMapX[ nX ] = aDestPt.X() + FRound( (double) aDestSz.Width() * nX / nSrcWidth ); 2416 2417 for( nY = 0L; nY <= nSrcHeight; nY++ ) 2418 pMapY[ nY ] = aDestPt.Y() + FRound( (double) aDestSz.Height() * nY / nSrcHeight ); 2419 2420 // walk through all rectangles of mask 2421 const Region aWorkRgn(aMask.CreateRegion(COL_BLACK, Rectangle(Point(), aMask.GetSizePixel()))); 2422 RectangleVector aRectangles; 2423 aWorkRgn.GetRegionRectangles(aRectangles); 2424 2425 for(RectangleVector::const_iterator aRectIter(aRectangles.begin()); aRectIter != aRectangles.end(); aRectIter++) 2426 { 2427 const Point aMapPt(pMapX[aRectIter->Left()], pMapY[aRectIter->Top()]); 2428 const Size aMapSz( 2429 pMapX[aRectIter->Right() + 1] - aMapPt.X(), // pMapX[L + W] -> L + ((R - L) + 1) -> R + 1 2430 pMapY[aRectIter->Bottom() + 1] - aMapPt.Y()); // same for Y 2431 2432 DrawRect(Rectangle(aMapPt, aMapSz)); 2433 } 2434 2435 //Region aWorkRgn( aMask.CreateRegion( COL_BLACK, Rectangle( Point(), aMask.GetSizePixel() ) ) ); 2436 //ImplRegionInfo aInfo; 2437 //sal_Bool bRgnRect = aWorkRgn.ImplGetFirstRect( aInfo, nWorkX, nWorkY, nWorkWidth, nWorkHeight ); 2438 // 2439 //while( bRgnRect ) 2440 //{ 2441 // const Point aMapPt( pMapX[ nWorkX ], pMapY[ nWorkY ] ); 2442 // const Size aMapSz( pMapX[ nWorkX + nWorkWidth ] - aMapPt.X(), pMapY[ nWorkY + nWorkHeight ] - aMapPt.Y() ); 2443 // 2444 // DrawRect( Rectangle( aMapPt, aMapSz ) ); 2445 // bRgnRect = aWorkRgn.ImplGetNextRect( aInfo, nWorkX, nWorkY, nWorkWidth, nWorkHeight ); 2446 //} 2447 2448 Pop(); 2449 delete[] pMapX; 2450 delete[] pMapY; 2451 mbMap = bOldMap; 2452 mpMetaFile = pOldMetaFile; 2453 } 2454 } 2455