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