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