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