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