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