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 // #124580# the correct DestSize needs to be calculated based on MaxXY values 829 const Point aDestPt(basegfx::fround(aTranslate.getX()), basegfx::fround(aTranslate.getY())); 830 const Size aDestSize( 831 basegfx::fround(aScale.getX() + aTranslate.getX()) - aDestPt.X(), 832 basegfx::fround(aScale.getY() + aTranslate.getY()) - aDestPt.Y()); 833 834 DrawBitmapEx(aDestPt, aDestSize, rBitmapEx); 835 return; 836 } 837 838 // we have rotation,shear or mirror, check if some crazy mode needs the 839 // created transformed bitmap 840 const bool bInvert(ROP_INVERT == meRasterOp); 841 const bool bBitmapChangedColor(mnDrawMode & (DRAWMODE_BLACKBITMAP | DRAWMODE_WHITEBITMAP | DRAWMODE_GRAYBITMAP | DRAWMODE_GHOSTEDBITMAP)); 842 const bool bMetafile(mpMetaFile); 843 const bool bPrinter(OUTDEV_PRINTER == meOutDevType); 844 bool bDone(false); 845 const basegfx::B2DHomMatrix aFullTransform(GetViewTransformation() * rTransformation); 846 const bool bTryDirectPaint(!bInvert && !bBitmapChangedColor && !bMetafile && !bPrinter); 847 848 if(!bForceToOwnTransformer && bTryDirectPaint) 849 { 850 // try to paint directly 851 const basegfx::B2DPoint aNull(aFullTransform * basegfx::B2DPoint(0.0, 0.0)); 852 const basegfx::B2DPoint aTopX(aFullTransform * basegfx::B2DPoint(1.0, 0.0)); 853 const basegfx::B2DPoint aTopY(aFullTransform * basegfx::B2DPoint(0.0, 1.0)); 854 SalBitmap* pSalSrcBmp = rBitmapEx.GetBitmap().ImplGetImpBitmap()->ImplGetSalBitmap(); 855 SalBitmap* pSalAlphaBmp = 0; 856 857 if(rBitmapEx.IsTransparent()) 858 { 859 if(rBitmapEx.IsAlpha()) 860 { 861 pSalAlphaBmp = rBitmapEx.GetAlpha().ImplGetImpBitmap()->ImplGetSalBitmap(); 862 } 863 else 864 { 865 pSalAlphaBmp = rBitmapEx.GetMask().ImplGetImpBitmap()->ImplGetSalBitmap(); 866 } 867 } 868 869 bDone = mpGraphics->DrawTransformedBitmap( 870 aNull, 871 aTopX, 872 aTopY, 873 *pSalSrcBmp, 874 pSalAlphaBmp, 875 this); 876 } 877 878 if(!bDone) 879 { 880 // take the fallback when no rotate and shear, but mirror (else we would have done this above) 881 if(!bForceToOwnTransformer && !bRotated && !bSheared) 882 { 883 // with no rotation or shear it can be mapped to DrawBitmapEx 884 // do *not* execute the mirroring here, it's done in the fallback 885 // #124580# the correct DestSize needs to be calculated based on MaxXY values 886 const Point aDestPt(basegfx::fround(aTranslate.getX()), basegfx::fround(aTranslate.getY())); 887 const Size aDestSize( 888 basegfx::fround(aScale.getX() + aTranslate.getX()) - aDestPt.X(), 889 basegfx::fround(aScale.getY() + aTranslate.getY()) - aDestPt.Y()); 890 891 DrawBitmapEx(aDestPt, aDestSize, rBitmapEx); 892 return; 893 } 894 895 // fallback; create transformed bitmap the hard way (back-transform 896 // the pixels) and paint 897 basegfx::B2DRange aVisibleRange(0.0, 0.0, 1.0, 1.0); 898 899 // limit maximum area to something looking good for non-pixel-based targets (metafile, printer) 900 // by using a fixed minimum (allow at least, but no need to utilize) for good smooting and an area 901 // dependent of original size for good quality when e.g. rotated/sheared. Still, limit to a maximum 902 // to avoid crashes/ressource problems (ca. 1500x3000 here) 903 const Size& rOriginalSizePixel(rBitmapEx.GetSizePixel()); 904 const double fOrigArea(rOriginalSizePixel.Width() * rOriginalSizePixel.Height() * 0.5); 905 const double fOrigAreaScaled(bSheared || bRotated ? fOrigArea * 1.44 : fOrigArea); 906 double fMaximumArea(std::min(4500000.0, std::max(1000000.0, fOrigAreaScaled))); 907 908 if(!bMetafile && !bPrinter) 909 { 910 // limit TargetRange to existing pixels (if pixel device) 911 // first get discrete range of object 912 basegfx::B2DRange aFullPixelRange(aVisibleRange); 913 914 aFullPixelRange.transform(aFullTransform); 915 916 if(basegfx::fTools::equalZero(aFullPixelRange.getWidth()) || basegfx::fTools::equalZero(aFullPixelRange.getHeight())) 917 { 918 // object is outside of visible area 919 return; 920 } 921 922 // now get discrete target pixels; start with OutDev pixel size and evtl. 923 // intersect with active clipping area 924 basegfx::B2DRange aOutPixel( 925 0.0, 926 0.0, 927 GetOutputSizePixel().Width(), 928 GetOutputSizePixel().Height()); 929 930 if(IsClipRegion()) 931 { 932 const Rectangle aRegionRectangle(GetActiveClipRegion().GetBoundRect()); 933 934 aOutPixel.intersect( // caution! Range from rectangle, one too much (!) 935 basegfx::B2DRange( 936 aRegionRectangle.Left(), 937 aRegionRectangle.Top(), 938 aRegionRectangle.Right() + 1, 939 aRegionRectangle.Bottom() + 1)); 940 } 941 942 if(aOutPixel.isEmpty()) 943 { 944 // no active output area 945 return; 946 } 947 948 // if aFullPixelRange is not completely inside of aOutPixel, 949 // reduction of target pixels is possible 950 basegfx::B2DRange aVisiblePixelRange(aFullPixelRange); 951 952 if(!aOutPixel.isInside(aFullPixelRange)) 953 { 954 aVisiblePixelRange.intersect(aOutPixel); 955 956 if(aVisiblePixelRange.isEmpty()) 957 { 958 // nothing in visible part, reduces to nothing 959 return; 960 } 961 962 // aVisiblePixelRange contains the reduced output area in 963 // discrete coordinates. To make it useful everywhere, make it relative to 964 // the object range 965 basegfx::B2DHomMatrix aMakeVisibleRangeRelative; 966 967 aVisibleRange = aVisiblePixelRange; 968 aMakeVisibleRangeRelative.translate( 969 -aFullPixelRange.getMinX(), 970 -aFullPixelRange.getMinY()); 971 aMakeVisibleRangeRelative.scale( 972 1.0 / aFullPixelRange.getWidth(), 973 1.0 / aFullPixelRange.getHeight()); 974 aVisibleRange.transform(aMakeVisibleRangeRelative); 975 } 976 977 // for pixel devices, do *not* limit size, else OutputDevice::ImplDrawAlpha 978 // will create another, badly scaled bitmap to do the job. Nonetheless, do a 979 // maximum clipping of something big (1600x1280x2). Add 1.0 to avoid rounding 980 // errors in rough estimations 981 const double fNewMaxArea(aVisiblePixelRange.getWidth() * aVisiblePixelRange.getHeight()); 982 983 fMaximumArea = std::min(4096000.0, fNewMaxArea + 1.0); 984 } 985 986 if(!aVisibleRange.isEmpty()) 987 { 988 static bool bDoSmoothAtAll(true); 989 BitmapEx aTransformed(rBitmapEx); 990 991 // #122923# when the result needs an alpha channel due to being rotated or sheared 992 // and thus uncovering areas, add these channels so that the own transformer (used 993 // in getTransformed) also creates a transformed alpha channel 994 if(!aTransformed.IsTransparent() && (bSheared || bRotated)) 995 { 996 // parts will be uncovered, extend aTransformed with a mask bitmap 997 const Bitmap aContent(aTransformed.GetBitmap()); 998 #if defined(MACOSX) 999 AlphaMask aMaskBmp(aContent.GetSizePixel()); 1000 aMaskBmp.Erase(0); 1001 #else 1002 Bitmap aMaskBmp(aContent.GetSizePixel(), 1); 1003 aMaskBmp.Erase(Color(COL_BLACK)); // #122758# Initialize to non-transparent 1004 #endif 1005 aTransformed = BitmapEx(aContent, aMaskBmp); 1006 } 1007 1008 aTransformed = aTransformed.getTransformed( 1009 aFullTransform, 1010 aVisibleRange, 1011 fMaximumArea, 1012 bDoSmoothAtAll); 1013 basegfx::B2DRange aTargetRange(0.0, 0.0, 1.0, 1.0); 1014 1015 // get logic object target range 1016 aTargetRange.transform(rTransformation); 1017 1018 // get from unified/relative VisibleRange to logoc one 1019 aVisibleRange.transform( 1020 basegfx::tools::createScaleTranslateB2DHomMatrix( 1021 aTargetRange.getRange(), 1022 aTargetRange.getMinimum())); 1023 1024 // extract point and size; do not remove size, the bitmap may have been prepared reduced by purpose 1025 // #124580# the correct DestSize needs to be calculated based on MaxXY values 1026 const Point aDestPt(basegfx::fround(aVisibleRange.getMinX()), basegfx::fround(aVisibleRange.getMinY())); 1027 const Size aDestSize( 1028 basegfx::fround(aVisibleRange.getMaxX()) - aDestPt.X(), 1029 basegfx::fround(aVisibleRange.getMaxY()) - aDestPt.Y()); 1030 1031 DrawBitmapEx(aDestPt, aDestSize, aTransformed); 1032 } 1033 } 1034 } 1035 1036 // ------------------------------------------------------------------ 1037 1038 void OutputDevice::ImplDrawBitmapEx( const Point& rDestPt, const Size& rDestSize, 1039 const Point& rSrcPtPixel, const Size& rSrcSizePixel, 1040 const BitmapEx& rBitmapEx, const sal_uLong nAction ) 1041 { 1042 DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); 1043 OSL_ENSURE(TRANSPARENT_NONE != rBitmapEx.GetTransparentType(), "ImplDrawBitmapEx not needed, no transparency in BitmapEx (!)"); 1044 1045 if ( mnDrawMode & DRAWMODE_NOBITMAP ) 1046 return; 1047 1048 if ( ROP_INVERT == meRasterOp ) 1049 { 1050 DrawRect( Rectangle( rDestPt, rDestSize ) ); 1051 return; 1052 } 1053 1054 BitmapEx aBmpEx( rBitmapEx ); 1055 1056 if ( mnDrawMode & ( DRAWMODE_BLACKBITMAP | DRAWMODE_WHITEBITMAP | 1057 DRAWMODE_GRAYBITMAP | DRAWMODE_GHOSTEDBITMAP ) ) 1058 { 1059 if ( mnDrawMode & ( DRAWMODE_BLACKBITMAP | DRAWMODE_WHITEBITMAP ) ) 1060 { 1061 Bitmap aColorBmp( aBmpEx.GetSizePixel(), ( mnDrawMode & DRAWMODE_GHOSTEDBITMAP ) ? 4 : 1 ); 1062 sal_uInt8 cCmpVal; 1063 1064 if ( mnDrawMode & DRAWMODE_BLACKBITMAP ) 1065 cCmpVal = ( mnDrawMode & DRAWMODE_GHOSTEDBITMAP ) ? 0x80 : 0; 1066 else 1067 cCmpVal = 255; 1068 1069 aColorBmp.Erase( Color( cCmpVal, cCmpVal, cCmpVal ) ); 1070 1071 if( aBmpEx.IsAlpha() ) 1072 { 1073 // Create one-bit mask out of alpha channel, by 1074 // thresholding it at alpha=0.5. As 1075 // DRAWMODE_BLACK/WHITEBITMAP requires monochrome 1076 // output, having alpha-induced grey levels is not 1077 // acceptable. 1078 Bitmap aMask( aBmpEx.GetAlpha().GetBitmap() ); 1079 aMask.MakeMono( 128 ); 1080 aBmpEx = BitmapEx( aColorBmp, aMask ); 1081 } 1082 else 1083 { 1084 aBmpEx = BitmapEx( aColorBmp, aBmpEx.GetMask() ); 1085 } 1086 } 1087 else if( !!aBmpEx ) 1088 { 1089 if ( mnDrawMode & DRAWMODE_GRAYBITMAP ) 1090 aBmpEx.Convert( BMP_CONVERSION_8BIT_GREYS ); 1091 1092 if ( mnDrawMode & DRAWMODE_GHOSTEDBITMAP ) 1093 aBmpEx.Convert( BMP_CONVERSION_GHOSTED ); 1094 } 1095 } 1096 1097 if ( mpMetaFile ) 1098 { 1099 switch( nAction ) 1100 { 1101 case( META_BMPEX_ACTION ): 1102 mpMetaFile->AddAction( new MetaBmpExAction( rDestPt, aBmpEx ) ); 1103 break; 1104 1105 case( META_BMPEXSCALE_ACTION ): 1106 mpMetaFile->AddAction( new MetaBmpExScaleAction( rDestPt, rDestSize, aBmpEx ) ); 1107 break; 1108 1109 case( META_BMPEXSCALEPART_ACTION ): 1110 mpMetaFile->AddAction( new MetaBmpExScalePartAction( rDestPt, rDestSize, 1111 rSrcPtPixel, rSrcSizePixel, aBmpEx ) ); 1112 break; 1113 } 1114 } 1115 1116 OUTDEV_INIT(); 1117 1118 if( OUTDEV_PRINTER == meOutDevType ) 1119 { 1120 if( aBmpEx.IsAlpha() ) 1121 { 1122 // #107169# For true alpha bitmaps, no longer masking the 1123 // bitmap, but perform a full alpha blend against a white 1124 // background here. 1125 Bitmap aBmp( aBmpEx.GetBitmap() ); 1126 aBmp.Blend( aBmpEx.GetAlpha(), Color( COL_WHITE) ); 1127 DrawBitmap( rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel, aBmp ); 1128 } 1129 else 1130 { 1131 Bitmap aBmp( aBmpEx.GetBitmap() ), aMask( aBmpEx.GetMask() ); 1132 aBmp.Replace( aMask, Color( COL_WHITE ) ); 1133 ImplPrintTransparent( aBmp, aMask, rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel ); 1134 } 1135 1136 return; 1137 } 1138 1139 if(aBmpEx.IsAlpha()) 1140 { 1141 ImplDrawAlpha( aBmpEx.GetBitmap(), aBmpEx.GetAlpha(), rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel ); 1142 return; 1143 } 1144 1145 if( !( !aBmpEx ) ) 1146 { 1147 SalTwoRect aPosAry; 1148 1149 aPosAry.mnSrcX = rSrcPtPixel.X(); 1150 aPosAry.mnSrcY = rSrcPtPixel.Y(); 1151 aPosAry.mnSrcWidth = rSrcSizePixel.Width(); 1152 aPosAry.mnSrcHeight = rSrcSizePixel.Height(); 1153 aPosAry.mnDestX = ImplLogicXToDevicePixel( rDestPt.X() ); 1154 aPosAry.mnDestY = ImplLogicYToDevicePixel( rDestPt.Y() ); 1155 aPosAry.mnDestWidth = ImplLogicWidthToDevicePixel( rDestSize.Width() ); 1156 aPosAry.mnDestHeight = ImplLogicHeightToDevicePixel( rDestSize.Height() ); 1157 1158 const sal_uLong nMirrFlags = ImplAdjustTwoRect( aPosAry, aBmpEx.GetSizePixel() ); 1159 1160 if( aPosAry.mnSrcWidth && aPosAry.mnSrcHeight && aPosAry.mnDestWidth && aPosAry.mnDestHeight ) 1161 { 1162 1163 if( nMirrFlags ) 1164 aBmpEx.Mirror( nMirrFlags ); 1165 1166 const SalBitmap* pSalSrcBmp = aBmpEx.ImplGetBitmapImpBitmap()->ImplGetSalBitmap(); 1167 const ImpBitmap* pMaskBmp = aBmpEx.ImplGetMaskImpBitmap(); 1168 1169 if ( pMaskBmp ) 1170 { 1171 SalBitmap* pSalAlphaBmp = pMaskBmp->ImplGetSalBitmap(); 1172 bool bTryDirectPaint(pSalSrcBmp && pSalAlphaBmp); 1173 1174 if(bTryDirectPaint) 1175 { 1176 // only paint direct when no scaling and no MapMode, else the 1177 // more expensive conversions may be done for short-time Bitmap/BitmapEx 1178 // used for buffering only 1179 if(!IsMapMode() && aPosAry.mnSrcWidth == aPosAry.mnDestWidth && aPosAry.mnSrcHeight == aPosAry.mnDestHeight) 1180 { 1181 bTryDirectPaint = false; 1182 } 1183 } 1184 1185 if(bTryDirectPaint && mpGraphics->DrawAlphaBitmap(aPosAry, *pSalSrcBmp, *pSalAlphaBmp, this)) 1186 { 1187 // tried to paint as alpha directly. If tis worked, we are done (except 1188 // alpha, see below) 1189 } 1190 else 1191 { 1192 // #4919452# reduce operation area to bounds of 1193 // cliprect. since masked transparency involves 1194 // creation of a large vdev and copying the screen 1195 // content into that (slooow read from framebuffer), 1196 // that should considerably increase performance for 1197 // large bitmaps and small clippings. 1198 1199 // Note that this optimisation is a workaround for a 1200 // Writer peculiarity, namely, to decompose background 1201 // graphics into myriads of disjunct, tiny 1202 // rectangles. That otherwise kills us here, since for 1203 // transparent output, SAL always prepares the whole 1204 // bitmap, if aPosAry contains the whole bitmap (and 1205 // it's _not_ to blame for that). 1206 1207 // Note the call to ImplPixelToDevicePixel(), since 1208 // aPosAry already contains the mnOutOff-offsets, they 1209 // also have to be applied to the region 1210 Rectangle aClipRegionBounds( ImplPixelToDevicePixel(maRegion).GetBoundRect() ); 1211 1212 // TODO: Also respect scaling (that's a bit tricky, 1213 // since the source points have to move fractional 1214 // amounts (which is not possible, thus has to be 1215 // emulated by increases copy area) 1216 // const double nScaleX( aPosAry.mnDestWidth / aPosAry.mnSrcWidth ); 1217 // const double nScaleY( aPosAry.mnDestHeight / aPosAry.mnSrcHeight ); 1218 1219 // for now, only identity scales allowed 1220 if( !aClipRegionBounds.IsEmpty() && 1221 aPosAry.mnDestWidth == aPosAry.mnSrcWidth && 1222 aPosAry.mnDestHeight == aPosAry.mnSrcHeight ) 1223 { 1224 // now intersect dest rect with clip region 1225 aClipRegionBounds.Intersection( Rectangle( aPosAry.mnDestX, 1226 aPosAry.mnDestY, 1227 aPosAry.mnDestX + aPosAry.mnDestWidth - 1, 1228 aPosAry.mnDestY + aPosAry.mnDestHeight - 1 ) ); 1229 1230 // Note: I could theoretically optimize away the 1231 // DrawBitmap below, if the region is empty 1232 // here. Unfortunately, cannot rule out that 1233 // somebody relies on the side effects. 1234 if( !aClipRegionBounds.IsEmpty() ) 1235 { 1236 aPosAry.mnSrcX += aClipRegionBounds.Left() - aPosAry.mnDestX; 1237 aPosAry.mnSrcY += aClipRegionBounds.Top() - aPosAry.mnDestY; 1238 aPosAry.mnSrcWidth = aClipRegionBounds.GetWidth(); 1239 aPosAry.mnSrcHeight = aClipRegionBounds.GetHeight(); 1240 1241 aPosAry.mnDestX = aClipRegionBounds.Left(); 1242 aPosAry.mnDestY = aClipRegionBounds.Top(); 1243 aPosAry.mnDestWidth = aClipRegionBounds.GetWidth(); 1244 aPosAry.mnDestHeight = aClipRegionBounds.GetHeight(); 1245 } 1246 } 1247 1248 mpGraphics->DrawBitmap( aPosAry, *pSalSrcBmp, 1249 *pMaskBmp->ImplGetSalBitmap(), 1250 this ); 1251 } 1252 1253 // #110958# Paint mask to alpha channel. Luckily, the 1254 // black and white representation of the mask maps to 1255 // the alpha channel 1256 1257 // #i25167# Restrict mask painting to _opaque_ areas 1258 // of the mask, otherwise we spoil areas where no 1259 // bitmap content was ever visible. Interestingly 1260 // enough, this can be achieved by taking the mask as 1261 // the transparency mask of itself 1262 if( mpAlphaVDev ) 1263 mpAlphaVDev->DrawBitmapEx( rDestPt, 1264 rDestSize, 1265 BitmapEx( aBmpEx.GetMask(), 1266 aBmpEx.GetMask() ) ); 1267 } 1268 else 1269 { 1270 mpGraphics->DrawBitmap( aPosAry, *pSalSrcBmp, this ); 1271 1272 if( mpAlphaVDev ) 1273 { 1274 // #i32109#: Make bitmap area opaque 1275 mpAlphaVDev->ImplFillOpaqueRectangle( Rectangle(rDestPt, rDestSize) ); 1276 } 1277 } 1278 } 1279 } 1280 } 1281 1282 // ------------------------------------------------------------------ 1283 1284 void OutputDevice::DrawMask( const Point& rDestPt, 1285 const Bitmap& rBitmap, const Color& rMaskColor ) 1286 { 1287 DBG_TRACE( "OutputDevice::DrawMask()" ); 1288 1289 if( ImplIsRecordLayout() ) 1290 return; 1291 1292 const Size aSizePix( rBitmap.GetSizePixel() ); 1293 ImplDrawMask( rDestPt, PixelToLogic( aSizePix ), Point(), aSizePix, rBitmap, rMaskColor, META_MASK_ACTION ); 1294 1295 if( mpAlphaVDev ) 1296 { 1297 const Bitmap& rMask( rBitmap.CreateMask( rMaskColor ) ); 1298 1299 // #i25167# Restrict mask painting to _opaque_ areas 1300 // of the mask, otherwise we spoil areas where no 1301 // bitmap content was ever visible. Interestingly 1302 // enough, this can be achieved by taking the mask as 1303 // the transparency mask of itself 1304 mpAlphaVDev->DrawBitmapEx( rDestPt, 1305 PixelToLogic( aSizePix ), 1306 BitmapEx( rMask, rMask ) ); 1307 } 1308 } 1309 1310 // ------------------------------------------------------------------ 1311 1312 void OutputDevice::DrawMask( const Point& rDestPt, const Size& rDestSize, 1313 const Bitmap& rBitmap, const Color& rMaskColor ) 1314 { 1315 DBG_TRACE( "OutputDevice::DrawMask( Size )" ); 1316 1317 if( ImplIsRecordLayout() ) 1318 return; 1319 1320 ImplDrawMask( rDestPt, rDestSize, Point(), rBitmap.GetSizePixel(), rBitmap, rMaskColor, META_MASKSCALE_ACTION ); 1321 1322 // TODO: Use mask here 1323 if( mpAlphaVDev ) 1324 { 1325 const Bitmap& rMask( rBitmap.CreateMask( rMaskColor ) ); 1326 1327 // #i25167# Restrict mask painting to _opaque_ areas 1328 // of the mask, otherwise we spoil areas where no 1329 // bitmap content was ever visible. Interestingly 1330 // enough, this can be achieved by taking the mask as 1331 // the transparency mask of itself 1332 mpAlphaVDev->DrawBitmapEx( rDestPt, 1333 rDestSize, 1334 BitmapEx( rMask, rMask ) ); 1335 } 1336 } 1337 1338 // ------------------------------------------------------------------ 1339 1340 void OutputDevice::DrawMask( const Point& rDestPt, const Size& rDestSize, 1341 const Point& rSrcPtPixel, const Size& rSrcSizePixel, 1342 const Bitmap& rBitmap, const Color& rMaskColor ) 1343 { 1344 DBG_TRACE( "OutputDevice::DrawMask( Point, Size )" ); 1345 1346 if( ImplIsRecordLayout() ) 1347 return; 1348 1349 ImplDrawMask( rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel, rBitmap, rMaskColor, META_MASKSCALEPART_ACTION ); 1350 1351 // TODO: Use mask here 1352 if( mpAlphaVDev ) 1353 { 1354 const Bitmap& rMask( rBitmap.CreateMask( rMaskColor ) ); 1355 1356 // #i25167# Restrict mask painting to _opaque_ areas 1357 // of the mask, otherwise we spoil areas where no 1358 // bitmap content was ever visible. Interestingly 1359 // enough, this can be achieved by taking the mask as 1360 // the transparency mask of itself 1361 mpAlphaVDev->DrawBitmapEx( rDestPt, 1362 rDestSize, 1363 rSrcPtPixel, 1364 rSrcSizePixel, 1365 BitmapEx( rMask, rMask ) ); 1366 } 1367 } 1368 1369 // ------------------------------------------------------------------ 1370 1371 void OutputDevice::ImplDrawMask( const Point& rDestPt, const Size& rDestSize, 1372 const Point& rSrcPtPixel, const Size& rSrcSizePixel, 1373 const Bitmap& rBitmap, const Color& rMaskColor, 1374 const sal_uLong nAction ) 1375 { 1376 DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); 1377 1378 if( ROP_INVERT == meRasterOp ) 1379 { 1380 DrawRect( Rectangle( rDestPt, rDestSize ) ); 1381 return; 1382 } 1383 1384 if ( mpMetaFile ) 1385 { 1386 switch( nAction ) 1387 { 1388 case( META_MASK_ACTION ): 1389 mpMetaFile->AddAction( new MetaMaskAction( rDestPt, 1390 rBitmap, rMaskColor ) ); 1391 break; 1392 1393 case( META_MASKSCALE_ACTION ): 1394 mpMetaFile->AddAction( new MetaMaskScaleAction( rDestPt, 1395 rDestSize, rBitmap, rMaskColor ) ); 1396 break; 1397 1398 case( META_MASKSCALEPART_ACTION ): 1399 mpMetaFile->AddAction( new MetaMaskScalePartAction( rDestPt, rDestSize, 1400 rSrcPtPixel, rSrcSizePixel, rBitmap, rMaskColor ) ); 1401 break; 1402 } 1403 } 1404 1405 OUTDEV_INIT(); 1406 1407 if ( OUTDEV_PRINTER == meOutDevType ) 1408 { 1409 ImplPrintMask( rBitmap, rMaskColor, rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel ); 1410 return; 1411 } 1412 1413 const ImpBitmap* pImpBmp = rBitmap.ImplGetImpBitmap(); 1414 if ( pImpBmp ) 1415 { 1416 SalTwoRect aPosAry; 1417 1418 aPosAry.mnSrcX = rSrcPtPixel.X(); 1419 aPosAry.mnSrcY = rSrcPtPixel.Y(); 1420 aPosAry.mnSrcWidth = rSrcSizePixel.Width(); 1421 aPosAry.mnSrcHeight = rSrcSizePixel.Height(); 1422 aPosAry.mnDestX = ImplLogicXToDevicePixel( rDestPt.X() ); 1423 aPosAry.mnDestY = ImplLogicYToDevicePixel( rDestPt.Y() ); 1424 aPosAry.mnDestWidth = ImplLogicWidthToDevicePixel( rDestSize.Width() ); 1425 aPosAry.mnDestHeight = ImplLogicHeightToDevicePixel( rDestSize.Height() ); 1426 1427 // spiegeln via Koordinaten wollen wir nicht 1428 const sal_uLong nMirrFlags = ImplAdjustTwoRect( aPosAry, pImpBmp->ImplGetSize() ); 1429 1430 // check if output is necessary 1431 if( aPosAry.mnSrcWidth && aPosAry.mnSrcHeight && aPosAry.mnDestWidth && aPosAry.mnDestHeight ) 1432 { 1433 1434 if( nMirrFlags ) 1435 { 1436 Bitmap aTmp( rBitmap ); 1437 aTmp.Mirror( nMirrFlags ); 1438 mpGraphics->DrawMask( aPosAry, *aTmp.ImplGetImpBitmap()->ImplGetSalBitmap(), 1439 ImplColorToSal( rMaskColor ) , this); 1440 } 1441 else 1442 mpGraphics->DrawMask( aPosAry, *pImpBmp->ImplGetSalBitmap(), 1443 ImplColorToSal( rMaskColor ), this ); 1444 1445 } 1446 } 1447 } 1448 1449 // ------------------------------------------------------------------ 1450 1451 void OutputDevice::DrawImage( const Point& rPos, const Image& rImage, sal_uInt16 nStyle ) 1452 { 1453 DBG_ASSERT( GetOutDevType() != OUTDEV_PRINTER, "DrawImage(): Images can't be drawn on any mprinter" ); 1454 1455 if( !rImage.mpImplData || ImplIsRecordLayout() ) 1456 return; 1457 1458 switch( rImage.mpImplData->meType ) 1459 { 1460 case IMAGETYPE_BITMAP: 1461 DrawBitmap( rPos, *static_cast< Bitmap* >( rImage.mpImplData->mpData ) ); 1462 break; 1463 1464 case IMAGETYPE_IMAGE: 1465 { 1466 ImplImageData* pData = static_cast< ImplImageData* >( rImage.mpImplData->mpData ); 1467 1468 if( !pData->mpImageBitmap ) 1469 { 1470 const Size aSize( pData->maBmpEx.GetSizePixel() ); 1471 1472 pData->mpImageBitmap = new ImplImageBmp; 1473 pData->mpImageBitmap->Create( pData->maBmpEx, aSize.Width(), aSize.Height(), 1 ); 1474 } 1475 1476 pData->mpImageBitmap->Draw( 0, this, rPos, nStyle ); 1477 } 1478 break; 1479 1480 default: 1481 break; 1482 } 1483 } 1484 1485 // ------------------------------------------------------------------ 1486 1487 void OutputDevice::DrawImage( const Point& rPos, const Size& rSize, 1488 const Image& rImage, sal_uInt16 nStyle ) 1489 { 1490 DBG_ASSERT( GetOutDevType() != OUTDEV_PRINTER, "DrawImage(): Images can't be drawn on any mprinter" ); 1491 1492 if( rImage.mpImplData && !ImplIsRecordLayout() ) 1493 { 1494 switch( rImage.mpImplData->meType ) 1495 { 1496 case IMAGETYPE_BITMAP: 1497 DrawBitmap( rPos, rSize, *static_cast< Bitmap* >( rImage.mpImplData->mpData ) ); 1498 break; 1499 1500 case IMAGETYPE_IMAGE: 1501 { 1502 ImplImageData* pData = static_cast< ImplImageData* >( rImage.mpImplData->mpData ); 1503 1504 if ( !pData->mpImageBitmap ) 1505 { 1506 const Size aSize( pData->maBmpEx.GetSizePixel() ); 1507 1508 pData->mpImageBitmap = new ImplImageBmp; 1509 pData->mpImageBitmap->Create( pData->maBmpEx, aSize.Width(), aSize.Height(), 1 ); 1510 } 1511 1512 pData->mpImageBitmap->Draw( 0, this, rPos, nStyle, &rSize ); 1513 } 1514 break; 1515 1516 default: 1517 break; 1518 } 1519 } 1520 } 1521 1522 // ------------------------------------------------------------------ 1523 1524 Bitmap OutputDevice::GetBitmap( const Point& rSrcPt, const Size& rSize ) const 1525 { 1526 DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); 1527 OSL_ENSURE(OUTDEV_PRINTER != GetOutDevType(), "OutputDevice::GetBitmap with sorce type OUTDEV_PRINTER should not be used (!)"); 1528 1529 Bitmap aBmp; 1530 long nX = ImplLogicXToDevicePixel( rSrcPt.X() ); 1531 long nY = ImplLogicYToDevicePixel( rSrcPt.Y() ); 1532 long nWidth = ImplLogicWidthToDevicePixel( rSize.Width() ); 1533 long nHeight = ImplLogicHeightToDevicePixel( rSize.Height() ); 1534 1535 if ( mpGraphics || ( (OutputDevice*) this )->ImplGetGraphics() ) 1536 { 1537 if ( nWidth > 0 && nHeight > 0 && nX <= (mnOutWidth + mnOutOffX) && nY <= (mnOutHeight + mnOutOffY)) 1538 { 1539 Rectangle aRect( Point( nX, nY ), Size( nWidth, nHeight ) ); 1540 sal_Bool bClipped = sal_False; 1541 1542 // X-Koordinate ausserhalb des Bereichs? 1543 if ( nX < mnOutOffX ) 1544 { 1545 nWidth -= ( mnOutOffX - nX ); 1546 nX = mnOutOffX; 1547 bClipped = sal_True; 1548 } 1549 1550 // Y-Koordinate ausserhalb des Bereichs? 1551 if ( nY < mnOutOffY ) 1552 { 1553 nHeight -= ( mnOutOffY - nY ); 1554 nY = mnOutOffY; 1555 bClipped = sal_True; 1556 } 1557 1558 // Breite ausserhalb des Bereichs? 1559 if ( (nWidth + nX) > (mnOutWidth + mnOutOffX) ) 1560 { 1561 nWidth = mnOutOffX + mnOutWidth - nX; 1562 bClipped = sal_True; 1563 } 1564 1565 // Hoehe ausserhalb des Bereichs? 1566 if ( (nHeight + nY) > (mnOutHeight + mnOutOffY) ) 1567 { 1568 nHeight = mnOutOffY + mnOutHeight - nY; 1569 bClipped = sal_True; 1570 } 1571 1572 if ( bClipped ) 1573 { 1574 // Falls auf den sichtbaren Bereich geclipped wurde, 1575 // muessen wir eine Bitmap in der rchtigen Groesse 1576 // erzeugen, in die die geclippte Bitmap an die angepasste 1577 // Position kopiert wird 1578 VirtualDevice aVDev( *this ); 1579 1580 if ( aVDev.SetOutputSizePixel( aRect.GetSize() ) ) 1581 { 1582 if ( ((OutputDevice*)&aVDev)->mpGraphics || ((OutputDevice*)&aVDev)->ImplGetGraphics() ) 1583 { 1584 SalTwoRect aPosAry; 1585 1586 aPosAry.mnSrcX = nX; 1587 aPosAry.mnSrcY = nY; 1588 aPosAry.mnSrcWidth = nWidth; 1589 aPosAry.mnSrcHeight = nHeight; 1590 aPosAry.mnDestX = ( aRect.Left() < mnOutOffX ) ? ( mnOutOffX - aRect.Left() ) : 0L; 1591 aPosAry.mnDestY = ( aRect.Top() < mnOutOffY ) ? ( mnOutOffY - aRect.Top() ) : 0L; 1592 aPosAry.mnDestWidth = nWidth; 1593 aPosAry.mnDestHeight = nHeight; 1594 1595 if ( (nWidth > 0) && (nHeight > 0) ) 1596 { 1597 (((OutputDevice*)&aVDev)->mpGraphics)->CopyBits( aPosAry, mpGraphics, this, this ); 1598 } 1599 else 1600 { 1601 OSL_ENSURE(false, "CopyBits with negative width or height (!)"); 1602 } 1603 1604 aBmp = aVDev.GetBitmap( Point(), aVDev.GetOutputSizePixel() ); 1605 } 1606 else 1607 bClipped = sal_False; 1608 } 1609 else 1610 bClipped = sal_False; 1611 } 1612 1613 if ( !bClipped ) 1614 { 1615 SalBitmap* pSalBmp = mpGraphics->GetBitmap( nX, nY, nWidth, nHeight, this ); 1616 1617 if( pSalBmp ) 1618 { 1619 ImpBitmap* pImpBmp = new ImpBitmap; 1620 pImpBmp->ImplSetSalBitmap( pSalBmp ); 1621 aBmp.ImplSetImpBitmap( pImpBmp ); 1622 } 1623 } 1624 } 1625 } 1626 1627 return aBmp; 1628 } 1629 1630 // ------------------------------------------------------------------ 1631 1632 BitmapEx OutputDevice::GetBitmapEx( const Point& rSrcPt, const Size& rSize ) const 1633 { 1634 DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); 1635 1636 // #110958# Extract alpha value from VDev, if any 1637 if( mpAlphaVDev ) 1638 { 1639 Bitmap aAlphaBitmap( mpAlphaVDev->GetBitmap( rSrcPt, rSize ) ); 1640 1641 // ensure 8 bit alpha 1642 if( aAlphaBitmap.GetBitCount() > 8 ) 1643 aAlphaBitmap.Convert( BMP_CONVERSION_8BIT_GREYS ); 1644 1645 return BitmapEx(GetBitmap( rSrcPt, rSize ), AlphaMask( aAlphaBitmap ) ); 1646 } 1647 else 1648 return GetBitmap( rSrcPt, rSize ); 1649 } 1650 1651 // ------------------------------------------------------------------ 1652 1653 void OutputDevice::ImplGetFrameBitmap( const Point& rDestPt, const Size& rSize, 1654 Bitmap& rBitmap ) const 1655 { 1656 DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); 1657 1658 sal_Bool bOldMap = mbMap; 1659 ((OutputDevice*)this)->mbMap = sal_False; 1660 rBitmap = GetBitmap( rDestPt, rSize ); 1661 ((OutputDevice*)this)->mbMap = bOldMap; 1662 } 1663 1664 // ------------------------------------------------------------------ 1665 1666 Color OutputDevice::GetPixel( const Point& rPt ) const 1667 { 1668 DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); 1669 1670 Color aColor; 1671 1672 if ( mpGraphics || ((OutputDevice*)this)->ImplGetGraphics() ) 1673 { 1674 if ( mbInitClipRegion ) 1675 ((OutputDevice*)this)->ImplInitClipRegion(); 1676 1677 if ( !mbOutputClipped ) 1678 { 1679 const long nX = ImplLogicXToDevicePixel( rPt.X() ); 1680 const long nY = ImplLogicYToDevicePixel( rPt.Y() ); 1681 const SalColor aSalCol = mpGraphics->GetPixel( nX, nY, this ); 1682 aColor.SetRed( SALCOLOR_RED( aSalCol ) ); 1683 aColor.SetGreen( SALCOLOR_GREEN( aSalCol ) ); 1684 aColor.SetBlue( SALCOLOR_BLUE( aSalCol ) ); 1685 } 1686 } 1687 return aColor; 1688 } 1689 1690 // ------------------------------------------------------------------ 1691 1692 Color* OutputDevice::GetPixel( const Polygon& rPts ) const 1693 { 1694 DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); 1695 1696 Color* pColors = NULL; 1697 const sal_uInt16 nSize = rPts.GetSize(); 1698 1699 if( nSize ) 1700 { 1701 if ( mpGraphics || ((OutputDevice*)this)->ImplGetGraphics() ) 1702 { 1703 if ( mbInitClipRegion ) 1704 ((OutputDevice*)this)->ImplInitClipRegion(); 1705 1706 if ( !mbOutputClipped ) 1707 { 1708 pColors = new Color[ nSize ]; 1709 1710 for( sal_uInt16 i = 0; i < nSize; i++ ) 1711 { 1712 Color& rCol = pColors[ i ]; 1713 const Point& rPt = rPts[ i ]; 1714 const SalColor aSalCol( mpGraphics->GetPixel( ImplLogicXToDevicePixel( rPt.X() ), 1715 ImplLogicYToDevicePixel( rPt.Y() ) , this) ); 1716 1717 rCol.SetRed( SALCOLOR_RED( aSalCol ) ); 1718 rCol.SetGreen( SALCOLOR_GREEN( aSalCol ) ); 1719 rCol.SetBlue( SALCOLOR_BLUE( aSalCol ) ); 1720 } 1721 } 1722 } 1723 } 1724 1725 return pColors; 1726 } 1727 1728 // ----------------------------------------------------------------------- 1729 1730 void OutputDevice::DrawPixel( const Point& rPt ) 1731 { 1732 DBG_TRACE( "OutputDevice::DrawPixel()" ); 1733 DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); 1734 1735 if ( mpMetaFile ) 1736 mpMetaFile->AddAction( new MetaPointAction( rPt ) ); 1737 1738 if ( !IsDeviceOutputNecessary() || !mbLineColor || ImplIsRecordLayout() ) 1739 return; 1740 1741 Point aPt = ImplLogicToDevicePixel( rPt ); 1742 1743 // we need a graphics 1744 if ( !mpGraphics ) 1745 { 1746 if ( !ImplGetGraphics() ) 1747 return; 1748 } 1749 1750 if ( mbInitClipRegion ) 1751 ImplInitClipRegion(); 1752 if ( mbOutputClipped ) 1753 return; 1754 1755 if ( mbInitLineColor ) 1756 ImplInitLineColor(); 1757 1758 mpGraphics->DrawPixel( aPt.X(), aPt.Y(), this ); 1759 1760 if( mpAlphaVDev ) 1761 mpAlphaVDev->DrawPixel( rPt ); 1762 } 1763 1764 // ----------------------------------------------------------------------- 1765 1766 void OutputDevice::DrawPixel( const Point& rPt, const Color& rColor ) 1767 { 1768 DBG_TRACE( "OutputDevice::DrawPixel()" ); 1769 DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); 1770 1771 Color aColor( rColor ); 1772 1773 if( mnDrawMode & ( DRAWMODE_BLACKLINE | DRAWMODE_WHITELINE | 1774 DRAWMODE_GRAYLINE | DRAWMODE_GHOSTEDLINE | 1775 DRAWMODE_SETTINGSLINE ) ) 1776 { 1777 if( !ImplIsColorTransparent( aColor ) ) 1778 { 1779 if( mnDrawMode & DRAWMODE_BLACKLINE ) 1780 { 1781 aColor = Color( COL_BLACK ); 1782 } 1783 else if( mnDrawMode & DRAWMODE_WHITELINE ) 1784 { 1785 aColor = Color( COL_WHITE ); 1786 } 1787 else if( mnDrawMode & DRAWMODE_GRAYLINE ) 1788 { 1789 const sal_uInt8 cLum = aColor.GetLuminance(); 1790 aColor = Color( cLum, cLum, cLum ); 1791 } 1792 else if( mnDrawMode & DRAWMODE_SETTINGSLINE ) 1793 { 1794 aColor = GetSettings().GetStyleSettings().GetFontColor(); 1795 } 1796 1797 if( mnDrawMode & DRAWMODE_GHOSTEDLINE ) 1798 { 1799 aColor = Color( ( aColor.GetRed() >> 1 ) | 0x80, 1800 ( aColor.GetGreen() >> 1 ) | 0x80, 1801 ( aColor.GetBlue() >> 1 ) | 0x80 ); 1802 } 1803 } 1804 } 1805 1806 if ( mpMetaFile ) 1807 mpMetaFile->AddAction( new MetaPixelAction( rPt, aColor ) ); 1808 1809 if ( !IsDeviceOutputNecessary() || ImplIsColorTransparent( aColor ) || ImplIsRecordLayout() ) 1810 return; 1811 1812 Point aPt = ImplLogicToDevicePixel( rPt ); 1813 1814 // we need a graphics 1815 if ( !mpGraphics ) 1816 { 1817 if ( !ImplGetGraphics() ) 1818 return; 1819 } 1820 1821 if ( mbInitClipRegion ) 1822 ImplInitClipRegion(); 1823 if ( mbOutputClipped ) 1824 return; 1825 1826 mpGraphics->DrawPixel( aPt.X(), aPt.Y(), ImplColorToSal( aColor ), this ); 1827 1828 if( mpAlphaVDev ) 1829 mpAlphaVDev->DrawPixel( rPt ); 1830 } 1831 1832 // ----------------------------------------------------------------------- 1833 1834 void OutputDevice::DrawPixel( const Polygon& rPts, const Color* pColors ) 1835 { 1836 if ( !pColors ) 1837 DrawPixel( rPts, GetLineColor() ); 1838 else 1839 { 1840 DBG_TRACE( "OutputDevice::DrawPixel()" ); 1841 DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); 1842 DBG_ASSERT( pColors, "OutputDevice::DrawPixel: No color array specified" ); 1843 1844 const sal_uInt16 nSize = rPts.GetSize(); 1845 1846 if ( nSize ) 1847 { 1848 if ( mpMetaFile ) 1849 for ( sal_uInt16 i = 0; i < nSize; i++ ) 1850 mpMetaFile->AddAction( new MetaPixelAction( rPts[ i ], pColors[ i ] ) ); 1851 1852 if ( !IsDeviceOutputNecessary() || ImplIsRecordLayout() ) 1853 return; 1854 1855 // we need a graphics 1856 if ( mpGraphics || ImplGetGraphics() ) 1857 { 1858 if ( mbInitClipRegion ) 1859 ImplInitClipRegion(); 1860 1861 if ( mbOutputClipped ) 1862 return; 1863 1864 for ( sal_uInt16 i = 0; i < nSize; i++ ) 1865 { 1866 const Point aPt( ImplLogicToDevicePixel( rPts[ i ] ) ); 1867 mpGraphics->DrawPixel( aPt.X(), aPt.Y(), ImplColorToSal( pColors[ i ] ), this ); 1868 } 1869 } 1870 } 1871 } 1872 1873 if( mpAlphaVDev ) 1874 mpAlphaVDev->DrawPixel( rPts, pColors ); 1875 } 1876 1877 // ----------------------------------------------------------------------- 1878 1879 void OutputDevice::DrawPixel( const Polygon& rPts, const Color& rColor ) 1880 { 1881 if( rColor != COL_TRANSPARENT && ! ImplIsRecordLayout() ) 1882 { 1883 const sal_uInt16 nSize = rPts.GetSize(); 1884 Color* pColArray = new Color[ nSize ]; 1885 1886 for( sal_uInt16 i = 0; i < nSize; i++ ) 1887 pColArray[ i ] = rColor; 1888 1889 DrawPixel( rPts, pColArray ); 1890 delete[] pColArray; 1891 } 1892 1893 if( mpAlphaVDev ) 1894 mpAlphaVDev->DrawPixel( rPts, rColor ); 1895 } 1896 1897 // ------------------------------------------------------------------------ 1898 1899 namespace 1900 { 1901 sal_uInt8 lcl_calcColor( const sal_uInt8 nSourceColor, const sal_uInt8 nSourceOpaq, const sal_uInt8 nDestColor ) 1902 { 1903 int c = ( (int)nDestColor * ( 255 - nSourceOpaq ) ) 1904 + (int)nSourceOpaq * (int)nSourceColor; 1905 return sal_uInt8( c / 255 ); 1906 } 1907 } 1908 1909 // ------------------------------------------------------------------------ 1910 1911 Bitmap OutputDevice::ImplBlendWithAlpha( Bitmap aBmp, 1912 BitmapReadAccess* pP, 1913 BitmapReadAccess* pA, 1914 const Rectangle& aDstRect, 1915 const sal_Int32 nOffY, 1916 const sal_Int32 nDstHeight, 1917 const sal_Int32 nOffX, 1918 const sal_Int32 nDstWidth, 1919 const long* pMapX, 1920 const long* pMapY ) 1921 { 1922 BitmapColor aDstCol,aSrcCol; 1923 Bitmap res; 1924 int nX, nOutX, nY, nOutY; 1925 1926 OSL_ENSURE(mpAlphaVDev, 1927 "ImplBlendWithAlpha(): call me only with valid alpha VDev!" ); 1928 1929 sal_Bool bOldMapMode( mpAlphaVDev->IsMapModeEnabled() ); 1930 mpAlphaVDev->EnableMapMode(sal_False); 1931 1932 Bitmap aAlphaBitmap( mpAlphaVDev->GetBitmap( aDstRect.TopLeft(), aDstRect.GetSize() ) ); 1933 BitmapWriteAccess* pAlphaW = aAlphaBitmap.AcquireWriteAccess(); 1934 1935 if( GetBitCount() <= 8 ) 1936 { 1937 Bitmap aDither( aBmp.GetSizePixel(), 8 ); 1938 BitmapColor aIndex( 0 ); 1939 BitmapReadAccess* pB = aBmp.AcquireReadAccess(); 1940 BitmapWriteAccess* pW = aDither.AcquireWriteAccess(); 1941 1942 if( pB && pP && pA && pW && pAlphaW ) 1943 { 1944 for( nY = 0, nOutY = nOffY; nY < nDstHeight; nY++, nOutY++ ) 1945 { 1946 const long nMapY = pMapY[ nY ]; 1947 const long nModY = ( nOutY & 0x0FL ) << 4L; 1948 1949 for( nX = 0, nOutX = nOffX; nX < nDstWidth; nX++, nOutX++ ) 1950 { 1951 const long nMapX = pMapX[ nX ]; 1952 const sal_uLong nD = nVCLDitherLut[ nModY | ( nOutX & 0x0FL ) ]; 1953 1954 aSrcCol = pP->GetColor( nMapY, nMapX ); 1955 aDstCol = pB->GetColor( nY, nX ); 1956 const sal_uInt8 nSrcOpaq = 255 - pA->GetPixelIndex( nMapY, nMapX ); 1957 const sal_uInt8 nDstOpaq = 255 - pAlphaW->GetPixelIndex( nY, nX ); 1958 1959 aDstCol.SetRed( lcl_calcColor( aSrcCol.GetRed(), nSrcOpaq, aDstCol.GetRed() ) ); 1960 aDstCol.SetBlue( lcl_calcColor( aSrcCol.GetBlue(), nSrcOpaq, aDstCol.GetBlue() ) ); 1961 aDstCol.SetGreen( lcl_calcColor( aSrcCol.GetGreen(), nSrcOpaq, aDstCol.GetGreen() ) ); 1962 1963 aIndex.SetIndex( (sal_uInt8) ( nVCLRLut[ ( nVCLLut[ aDstCol.GetRed() ] + nD ) >> 16UL ] + 1964 nVCLGLut[ ( nVCLLut[ aDstCol.GetGreen() ] + nD ) >> 16UL ] + 1965 nVCLBLut[ ( nVCLLut[ aDstCol.GetBlue() ] + nD ) >> 16UL ] ) ); 1966 pW->SetPixel( nY, nX, aIndex ); 1967 1968 // Have to perform the compositing 'algebra' in 1969 // the inverse alpha space (with 255 meaning 1970 // opaque), otherwise, transitivity is not 1971 // achieved. 1972 const sal_uInt8 nSrcAlpha = 255-COLOR_CHANNEL_MERGE( 255, (sal_uInt8)nDstOpaq, nSrcOpaq ); 1973 1974 aIndex.SetIndex( (sal_uInt8) ( nVCLRLut[ ( nVCLLut[ nSrcAlpha ] + nD ) >> 16UL ] + 1975 nVCLGLut[ ( nVCLLut[ nSrcAlpha ] + nD ) >> 16UL ] + 1976 nVCLBLut[ ( nVCLLut[ nSrcAlpha ] + nD ) >> 16UL ] ) ); 1977 pAlphaW->SetPixel( nY, nX, aIndex ); 1978 } 1979 } 1980 } 1981 1982 aBmp.ReleaseAccess( pB ); 1983 aDither.ReleaseAccess( pW ); 1984 res = aDither; 1985 } 1986 else 1987 { 1988 BitmapWriteAccess* pB = aBmp.AcquireWriteAccess(); 1989 if( pP && pA && pB ) 1990 { 1991 for( nY = 0; nY < nDstHeight; nY++ ) 1992 { 1993 const long nMapY = pMapY[ nY ]; 1994 1995 for( nX = 0; nX < nDstWidth; nX++ ) 1996 { 1997 const long nMapX = pMapX[ nX ]; 1998 1999 aSrcCol = pP->GetColor( nMapY, nMapX ); 2000 aDstCol = pB->GetColor( nY, nX ); 2001 const sal_uInt8 nSrcOpaq = 255 - pA->GetPixelIndex( nMapY, nMapX ); 2002 const sal_uInt8 nDstOpaq = 255 - pAlphaW->GetPixelIndex( nY, nX ); 2003 2004 aDstCol.SetRed( lcl_calcColor( aSrcCol.GetRed(), nSrcOpaq, aDstCol.GetRed() ) ); 2005 aDstCol.SetBlue( lcl_calcColor( aSrcCol.GetBlue(), nSrcOpaq, aDstCol.GetBlue() ) ); 2006 aDstCol.SetGreen( lcl_calcColor( aSrcCol.GetGreen(), nSrcOpaq, aDstCol.GetGreen() ) ); 2007 2008 pB->SetPixel( nY, nX, aDstCol ); 2009 2010 // Have to perform the compositing 'algebra' in 2011 // the inverse alpha space (with 255 meaning 2012 // opaque), otherwise, transitivity is not 2013 // achieved. 2014 const sal_uInt8 nSrcAlpha = 255-COLOR_CHANNEL_MERGE( 255, (sal_uInt8)nDstOpaq, nSrcOpaq ); 2015 2016 pAlphaW->SetPixel( nY, nX, Color(nSrcAlpha, nSrcAlpha, nSrcAlpha) ); 2017 } 2018 } 2019 } 2020 2021 aBmp.ReleaseAccess( pB ); 2022 res = aBmp; 2023 } 2024 2025 aAlphaBitmap.ReleaseAccess( pAlphaW ); 2026 mpAlphaVDev->DrawBitmap( aDstRect.TopLeft(), aAlphaBitmap ); 2027 mpAlphaVDev->EnableMapMode( bOldMapMode ); 2028 2029 return res; 2030 } 2031 2032 // ------------------------------------------------------------------------ 2033 2034 Bitmap OutputDevice::ImplBlend( Bitmap aBmp, 2035 BitmapReadAccess* pP, 2036 BitmapReadAccess* pA, 2037 const sal_Int32 nOffY, 2038 const sal_Int32 nDstHeight, 2039 const sal_Int32 nOffX, 2040 const sal_Int32 nDstWidth, 2041 const Rectangle& aBmpRect, 2042 const Size& aOutSz, 2043 const bool bHMirr, 2044 const bool bVMirr, 2045 const long* pMapX, 2046 const long* pMapY ) 2047 { 2048 BitmapColor aDstCol; 2049 Bitmap res; 2050 int nX, nOutX, nY, nOutY; 2051 2052 if( GetBitCount() <= 8 ) 2053 { 2054 Bitmap aDither( aBmp.GetSizePixel(), 8 ); 2055 BitmapColor aIndex( 0 ); 2056 BitmapReadAccess* pB = aBmp.AcquireReadAccess(); 2057 BitmapWriteAccess* pW = aDither.AcquireWriteAccess(); 2058 2059 if( pB && pP && pA && pW ) 2060 { 2061 for( nY = 0, nOutY = nOffY; nY < nDstHeight; nY++, nOutY++ ) 2062 { 2063 const long nMapY = pMapY[ nY ]; 2064 const long nModY = ( nOutY & 0x0FL ) << 4L; 2065 2066 for( nX = 0, nOutX = nOffX; nX < nDstWidth; nX++, nOutX++ ) 2067 { 2068 const long nMapX = pMapX[ nX ]; 2069 const sal_uLong nD = nVCLDitherLut[ nModY | ( nOutX & 0x0FL ) ]; 2070 2071 aDstCol = pB->GetColor( nY, nX ); 2072 aDstCol.Merge( pP->GetColor( nMapY, nMapX ), pA->GetPixelIndex( nMapY, nMapX ) ); 2073 aIndex.SetIndex( (sal_uInt8) ( nVCLRLut[ ( nVCLLut[ aDstCol.GetRed() ] + nD ) >> 16UL ] + 2074 nVCLGLut[ ( nVCLLut[ aDstCol.GetGreen() ] + nD ) >> 16UL ] + 2075 nVCLBLut[ ( nVCLLut[ aDstCol.GetBlue() ] + nD ) >> 16UL ] ) ); 2076 pW->SetPixel( nY, nX, aIndex ); 2077 } 2078 } 2079 } 2080 2081 aBmp.ReleaseAccess( pB ); 2082 aDither.ReleaseAccess( pW ); 2083 res = aDither; 2084 } 2085 else 2086 { 2087 BitmapWriteAccess* pB = aBmp.AcquireWriteAccess(); 2088 2089 bool bFastBlend = false; 2090 if( pP && pA && pB ) 2091 { 2092 SalTwoRect aTR; 2093 aTR.mnSrcX = aBmpRect.Left(); 2094 aTR.mnSrcY = aBmpRect.Top(); 2095 aTR.mnSrcWidth = aBmpRect.GetWidth(); 2096 aTR.mnSrcHeight = aBmpRect.GetHeight(); 2097 aTR.mnDestX = nOffX; 2098 aTR.mnDestY = nOffY; 2099 aTR.mnDestWidth = aOutSz.Width(); 2100 aTR.mnDestHeight= aOutSz.Height(); 2101 2102 if( !bHMirr || !bVMirr ) 2103 bFastBlend = ImplFastBitmapBlending( *pB,*pP,*pA, aTR ); 2104 } 2105 2106 if( pP && pA && pB && !bFastBlend ) 2107 { 2108 switch( pP->GetScanlineFormat() ) 2109 { 2110 case( BMP_FORMAT_8BIT_PAL ): 2111 { 2112 for( nY = 0; nY < nDstHeight; nY++ ) 2113 { 2114 const long nMapY = pMapY[ nY ]; 2115 Scanline pPScan = pP->GetScanline( nMapY ); 2116 Scanline pAScan = pA->GetScanline( nMapY ); 2117 2118 for( nX = 0; nX < nDstWidth; nX++ ) 2119 { 2120 const long nMapX = pMapX[ nX ]; 2121 aDstCol = pB->GetPixel( nY, nX ); 2122 pB->SetPixel( nY, nX, aDstCol.Merge( pP->GetPaletteColor( pPScan[ nMapX ] ), 2123 pAScan[ nMapX ] ) ); 2124 } 2125 } 2126 } 2127 break; 2128 2129 case( BMP_FORMAT_24BIT_TC_BGR ): 2130 { 2131 for( nY = 0; nY < nDstHeight; nY++ ) 2132 { 2133 const long nMapY = pMapY[ nY ]; 2134 Scanline pPScan = pP->GetScanline( nMapY ); 2135 Scanline pAScan = pA->GetScanline( nMapY ); 2136 2137 for( nX = 0; nX < nDstWidth; nX++ ) 2138 { 2139 const long nMapX = pMapX[ nX ]; 2140 Scanline pTmp = pPScan + nMapX * 3; 2141 2142 aDstCol = pB->GetPixel( nY, nX ); 2143 pB->SetPixel( nY, nX, aDstCol.Merge( pTmp[ 2 ], pTmp[ 1 ], pTmp[ 0 ], 2144 pAScan[ nMapX ] ) ); 2145 } 2146 } 2147 } 2148 break; 2149 2150 case( BMP_FORMAT_24BIT_TC_RGB ): 2151 { 2152 for( nY = 0; nY < nDstHeight; nY++ ) 2153 { 2154 const long nMapY = pMapY[ nY ]; 2155 Scanline pPScan = pP->GetScanline( nMapY ); 2156 Scanline pAScan = pA->GetScanline( nMapY ); 2157 2158 for( nX = 0; nX < nDstWidth; nX++ ) 2159 { 2160 const long nMapX = pMapX[ nX ]; 2161 Scanline pTmp = pPScan + nMapX * 3; 2162 2163 aDstCol = pB->GetPixel( nY, nX ); 2164 pB->SetPixel( nY, nX, aDstCol.Merge( pTmp[ 0 ], pTmp[ 1 ], pTmp[ 2 ], 2165 pAScan[ nMapX ] ) ); 2166 } 2167 } 2168 } 2169 break; 2170 2171 default: 2172 { 2173 for( nY = 0; nY < nDstHeight; nY++ ) 2174 { 2175 const long nMapY = pMapY[ nY ]; 2176 Scanline pAScan = pA->GetScanline( nMapY ); 2177 2178 for( nX = 0; nX < nDstWidth; nX++ ) 2179 { 2180 const long nMapX = pMapX[ nX ]; 2181 aDstCol = pB->GetPixel( nY, nX ); 2182 pB->SetPixel( nY, nX, aDstCol.Merge( pP->GetColor( nMapY, nMapX ), 2183 pAScan[ nMapX ] ) ); 2184 } 2185 } 2186 } 2187 break; 2188 } 2189 } 2190 2191 aBmp.ReleaseAccess( pB ); 2192 res = aBmp; 2193 } 2194 2195 return res; 2196 } 2197 2198 // ------------------------------------------------------------------------ 2199 2200 void OutputDevice::ImplDrawAlpha( const Bitmap& rBmp, const AlphaMask& rAlpha, 2201 const Point& rDestPt, const Size& rDestSize, 2202 const Point& rSrcPtPixel, const Size& rSrcSizePixel ) 2203 { 2204 const Point aNullPt; 2205 Point aOutPt( LogicToPixel( rDestPt ) ); 2206 Size aOutSz( LogicToPixel( rDestSize ) ); 2207 Rectangle aDstRect( aNullPt, GetOutputSizePixel() ); 2208 const sal_Bool bHMirr = aOutSz.Width() < 0, bVMirr = aOutSz.Height() < 0; 2209 2210 if( OUTDEV_WINDOW == meOutDevType ) 2211 { 2212 const Region aPaintRgn( ( (Window*) this )->GetPaintRegion() ); 2213 2214 if( !aPaintRgn.IsNull() ) 2215 aDstRect.Intersection( LogicToPixel( aPaintRgn.GetBoundRect() ) ); 2216 } 2217 2218 if( bHMirr ) 2219 { 2220 aOutSz.Width() = -aOutSz.Width(); 2221 aOutPt.X() -= ( aOutSz.Width() - 1L ); 2222 } 2223 2224 if( bVMirr ) 2225 { 2226 aOutSz.Height() = -aOutSz.Height(); 2227 aOutPt.Y() -= ( aOutSz.Height() - 1L ); 2228 } 2229 2230 if( !aDstRect.Intersection( Rectangle( aOutPt, aOutSz ) ).IsEmpty() ) 2231 { 2232 bool bNativeAlpha = false; 2233 static const char* pDisableNative = getenv( "SAL_DISABLE_NATIVE_ALPHA"); 2234 // #i83087# Naturally, system alpha blending cannot work with 2235 // separate alpha VDev 2236 bool bTryDirectPaint(!mpAlphaVDev && !pDisableNative && !bHMirr && !bVMirr); 2237 2238 #ifdef WNT 2239 if(bTryDirectPaint) 2240 { 2241 // only paint direct when no scaling and no MapMode, else the 2242 // more expensive conversions may be done for short-time Bitmap/BitmapEx 2243 // used for buffering only 2244 if(!IsMapMode() && rSrcSizePixel.Width() == aOutSz.Width() && rSrcSizePixel.Height() == aOutSz.Height()) 2245 { 2246 bTryDirectPaint = false; 2247 } 2248 } 2249 #endif 2250 2251 if(bTryDirectPaint) 2252 { 2253 Point aRelPt = aOutPt + Point( mnOutOffX, mnOutOffY ); 2254 SalTwoRect aTR = { 2255 rSrcPtPixel.X(), rSrcPtPixel.Y(), 2256 rSrcSizePixel.Width(), rSrcSizePixel.Height(), 2257 aRelPt.X(), aRelPt.Y(), 2258 aOutSz.Width(), aOutSz.Height() 2259 }; 2260 SalBitmap* pSalSrcBmp = rBmp.ImplGetImpBitmap()->ImplGetSalBitmap(); 2261 SalBitmap* pSalAlphaBmp = rAlpha.ImplGetImpBitmap()->ImplGetSalBitmap(); 2262 bNativeAlpha = mpGraphics->DrawAlphaBitmap( aTR, *pSalSrcBmp, *pSalAlphaBmp, this ); 2263 } 2264 2265 VirtualDevice* pOldVDev = mpAlphaVDev; 2266 2267 Rectangle aBmpRect( aNullPt, rBmp.GetSizePixel() ); 2268 if( !bNativeAlpha 2269 && !aBmpRect.Intersection( Rectangle( rSrcPtPixel, rSrcSizePixel ) ).IsEmpty() ) 2270 { 2271 GDIMetaFile* pOldMetaFile = mpMetaFile; mpMetaFile = NULL; 2272 const sal_Bool bOldMap = mbMap; mbMap = sal_False; 2273 Bitmap aBmp( GetBitmap( aDstRect.TopLeft(), aDstRect.GetSize() ) ); 2274 2275 // #109044# The generated bitmap need not necessarily be 2276 // of aDstRect dimensions, it's internally clipped to 2277 // window bounds. Thus, we correct the dest size here, 2278 // since we later use it (in nDstWidth/Height) for pixel 2279 // access) 2280 // #i38887# reading from screen may sometimes fail 2281 if( aBmp.ImplGetImpBitmap() ) 2282 aDstRect.SetSize( aBmp.GetSizePixel() ); 2283 2284 BitmapColor aDstCol; 2285 const long nSrcWidth = aBmpRect.GetWidth(), nSrcHeight = aBmpRect.GetHeight(); 2286 const long nDstWidth = aDstRect.GetWidth(), nDstHeight = aDstRect.GetHeight(); 2287 const long nOutWidth = aOutSz.Width(), nOutHeight = aOutSz.Height(); 2288 // calculate offset in original bitmap 2289 // in RTL case this is a little more complicated since the contents of the 2290 // bitmap is not mirrored (it never is), however the paint region and bmp region 2291 // are in mirrored coordinates, so the intersection of (aOutPt,aOutSz) with these 2292 // is content wise somewhere else and needs to take mirroring into account 2293 const long nOffX = IsRTLEnabled() 2294 ? aOutSz.Width() - aDstRect.GetWidth() - (aDstRect.Left() - aOutPt.X()) 2295 : aDstRect.Left() - aOutPt.X(), 2296 nOffY = aDstRect.Top() - aOutPt.Y(); 2297 long nX, nOutX, nY, nOutY; 2298 long nMirrOffX = 0; 2299 long nMirrOffY = 0; 2300 long* pMapX = new long[ nDstWidth ]; 2301 long* pMapY = new long[ nDstHeight ]; 2302 2303 // create horizontal mapping table 2304 if( bHMirr ) 2305 nMirrOffX = ( aBmpRect.Left() << 1 ) + nSrcWidth - 1; 2306 2307 for( nX = 0L, nOutX = nOffX; nX < nDstWidth; nX++, nOutX++ ) 2308 { 2309 pMapX[ nX ] = aBmpRect.Left() + nOutX * nSrcWidth / nOutWidth; 2310 if( bHMirr ) 2311 pMapX[ nX ] = nMirrOffX - pMapX[ nX ]; 2312 } 2313 2314 // create vertical mapping table 2315 if( bVMirr ) 2316 nMirrOffY = ( aBmpRect.Top() << 1 ) + nSrcHeight - 1; 2317 2318 for( nY = 0L, nOutY = nOffY; nY < nDstHeight; nY++, nOutY++ ) 2319 { 2320 pMapY[ nY ] = aBmpRect.Top() + nOutY * nSrcHeight / nOutHeight; 2321 2322 if( bVMirr ) 2323 pMapY[ nY ] = nMirrOffY - pMapY[ nY ]; 2324 } 2325 2326 BitmapReadAccess* pP = ( (Bitmap&) rBmp ).AcquireReadAccess(); 2327 BitmapReadAccess* pA = ( (AlphaMask&) rAlpha ).AcquireReadAccess(); 2328 2329 DBG_ASSERT( pA->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL || 2330 pA->GetScanlineFormat() == BMP_FORMAT_8BIT_TC_MASK, 2331 "OutputDevice::ImplDrawAlpha(): non-8bit alpha no longer supported!" ); 2332 2333 // #i38887# reading from screen may sometimes fail 2334 if( aBmp.ImplGetImpBitmap() ) 2335 { 2336 Bitmap aTmp; 2337 2338 if( mpAlphaVDev ) 2339 { 2340 aTmp = ImplBlendWithAlpha( 2341 aBmp,pP,pA, 2342 aDstRect, 2343 nOffY,nDstHeight, 2344 nOffX,nDstWidth, 2345 pMapX,pMapY ); 2346 } 2347 else 2348 { 2349 aTmp = ImplBlend( 2350 aBmp,pP,pA, 2351 nOffY,nDstHeight, 2352 nOffX,nDstWidth, 2353 aBmpRect,aOutSz, 2354 bHMirr,bVMirr, 2355 pMapX,pMapY ); 2356 } 2357 2358 // #110958# Disable alpha VDev, we're doing the necessary 2359 // stuff explicitely furher below 2360 if( mpAlphaVDev ) 2361 mpAlphaVDev = NULL; 2362 2363 DrawBitmap( aDstRect.TopLeft(), 2364 aTmp ); 2365 2366 // #110958# Enable alpha VDev again 2367 mpAlphaVDev = pOldVDev; 2368 } 2369 2370 ( (Bitmap&) rBmp ).ReleaseAccess( pP ); 2371 ( (AlphaMask&) rAlpha ).ReleaseAccess( pA ); 2372 2373 delete[] pMapX; 2374 delete[] pMapY; 2375 mbMap = bOldMap; 2376 mpMetaFile = pOldMetaFile; 2377 } 2378 } 2379 } 2380 2381 // ------------------------------------------------------------------------ 2382 2383 void OutputDevice::ImplPrintTransparent( const Bitmap& rBmp, const Bitmap& rMask, 2384 const Point& rDestPt, const Size& rDestSize, 2385 const Point& rSrcPtPixel, const Size& rSrcSizePixel ) 2386 { 2387 Point aPt; 2388 Point aDestPt( LogicToPixel( rDestPt ) ); 2389 Size aDestSz( LogicToPixel( rDestSize ) ); 2390 Rectangle aSrcRect( rSrcPtPixel, rSrcSizePixel ); 2391 2392 aSrcRect.Justify(); 2393 2394 if( !rBmp.IsEmpty() && aSrcRect.GetWidth() && aSrcRect.GetHeight() && aDestSz.Width() && aDestSz.Height() ) 2395 { 2396 Bitmap aPaint( rBmp ), aMask( rMask ); 2397 sal_uLong nMirrFlags = 0UL; 2398 2399 if( aMask.GetBitCount() > 1 ) 2400 aMask.Convert( BMP_CONVERSION_1BIT_THRESHOLD ); 2401 2402 // mirrored horizontically 2403 if( aDestSz.Width() < 0L ) 2404 { 2405 aDestSz.Width() = -aDestSz.Width(); 2406 aDestPt.X() -= ( aDestSz.Width() - 1L ); 2407 nMirrFlags |= BMP_MIRROR_HORZ; 2408 } 2409 2410 // mirrored vertically 2411 if( aDestSz.Height() < 0L ) 2412 { 2413 aDestSz.Height() = -aDestSz.Height(); 2414 aDestPt.Y() -= ( aDestSz.Height() - 1L ); 2415 nMirrFlags |= BMP_MIRROR_VERT; 2416 } 2417 2418 // source cropped? 2419 if( aSrcRect != Rectangle( aPt, aPaint.GetSizePixel() ) ) 2420 { 2421 aPaint.Crop( aSrcRect ); 2422 aMask.Crop( aSrcRect ); 2423 } 2424 2425 // destination mirrored 2426 if( nMirrFlags ) 2427 { 2428 aPaint.Mirror( nMirrFlags ); 2429 aMask.Mirror( nMirrFlags ); 2430 } 2431 2432 // we always want to have a mask 2433 if( aMask.IsEmpty() ) 2434 { 2435 aMask = Bitmap( aSrcRect.GetSize(), 1 ); 2436 aMask.Erase( Color( COL_BLACK ) ); 2437 } 2438 2439 // do painting 2440 const long nSrcWidth = aSrcRect.GetWidth(), nSrcHeight = aSrcRect.GetHeight(); 2441 long nX, nY; // , nWorkX, nWorkY, nWorkWidth, nWorkHeight; 2442 long* pMapX = new long[ nSrcWidth + 1 ]; 2443 long* pMapY = new long[ nSrcHeight + 1 ]; 2444 const sal_Bool bOldMap = mbMap; 2445 2446 mbMap = sal_False; 2447 2448 // create forward mapping tables 2449 for( nX = 0L; nX <= nSrcWidth; nX++ ) 2450 pMapX[ nX ] = aDestPt.X() + FRound( (double) aDestSz.Width() * nX / nSrcWidth ); 2451 2452 for( nY = 0L; nY <= nSrcHeight; nY++ ) 2453 pMapY[ nY ] = aDestPt.Y() + FRound( (double) aDestSz.Height() * nY / nSrcHeight ); 2454 2455 // walk through all rectangles of mask 2456 const Region aWorkRgn(aMask.CreateRegion(COL_BLACK, Rectangle(Point(), aMask.GetSizePixel()))); 2457 RectangleVector aRectangles; 2458 aWorkRgn.GetRegionRectangles(aRectangles); 2459 2460 for(RectangleVector::const_iterator aRectIter(aRectangles.begin()); aRectIter != aRectangles.end(); aRectIter++) 2461 { 2462 const Point aMapPt(pMapX[aRectIter->Left()], pMapY[aRectIter->Top()]); 2463 const Size aMapSz( 2464 pMapX[aRectIter->Right() + 1] - aMapPt.X(), // pMapX[L + W] -> L + ((R - L) + 1) -> R + 1 2465 pMapY[aRectIter->Bottom() + 1] - aMapPt.Y()); // same for Y 2466 Bitmap aBandBmp(aPaint); 2467 2468 aBandBmp.Crop(*aRectIter); 2469 ImplDrawBitmap(aMapPt, aMapSz, Point(), aBandBmp.GetSizePixel(), aBandBmp, META_BMPSCALEPART_ACTION); 2470 } 2471 2472 //Region aWorkRgn( aMask.CreateRegion( COL_BLACK, Rectangle( Point(), aMask.GetSizePixel() ) ) ); 2473 //ImplRegionInfo aInfo; 2474 //sal_Bool bRgnRect = aWorkRgn.ImplGetFirstRect( aInfo, nWorkX, nWorkY, nWorkWidth, nWorkHeight ); 2475 // 2476 //while( bRgnRect ) 2477 //{ 2478 // Bitmap aBandBmp( aPaint ); 2479 // const Rectangle aBandRect( Point( nWorkX, nWorkY ), Size( nWorkWidth, nWorkHeight ) ); 2480 // const Point aMapPt( pMapX[ nWorkX ], pMapY[ nWorkY ] ); 2481 // const Size aMapSz( pMapX[ nWorkX + nWorkWidth ] - aMapPt.X(), pMapY[ nWorkY + nWorkHeight ] - aMapPt.Y() ); 2482 // 2483 // aBandBmp.Crop( aBandRect ); 2484 // ImplDrawBitmap( aMapPt, aMapSz, Point(), aBandBmp.GetSizePixel(), aBandBmp, META_BMPSCALEPART_ACTION ); 2485 // bRgnRect = aWorkRgn.ImplGetNextRect( aInfo, nWorkX, nWorkY, nWorkWidth, nWorkHeight ); 2486 //} 2487 2488 mbMap = bOldMap; 2489 2490 delete[] pMapX; 2491 delete[] pMapY; 2492 } 2493 } 2494 2495 // ------------------------------------------------------------------------ 2496 2497 void OutputDevice::ImplPrintMask( const Bitmap& rMask, const Color& rMaskColor, 2498 const Point& rDestPt, const Size& rDestSize, 2499 const Point& rSrcPtPixel, const Size& rSrcSizePixel ) 2500 { 2501 Point aPt; 2502 Point aDestPt( LogicToPixel( rDestPt ) ); 2503 Size aDestSz( LogicToPixel( rDestSize ) ); 2504 Rectangle aSrcRect( rSrcPtPixel, rSrcSizePixel ); 2505 2506 aSrcRect.Justify(); 2507 2508 if( !rMask.IsEmpty() && aSrcRect.GetWidth() && aSrcRect.GetHeight() && aDestSz.Width() && aDestSz.Height() ) 2509 { 2510 Bitmap aMask( rMask ); 2511 sal_uLong nMirrFlags = 0UL; 2512 2513 if( aMask.GetBitCount() > 1 ) 2514 aMask.Convert( BMP_CONVERSION_1BIT_THRESHOLD ); 2515 2516 // mirrored horizontically 2517 if( aDestSz.Width() < 0L ) 2518 { 2519 aDestSz.Width() = -aDestSz.Width(); 2520 aDestPt.X() -= ( aDestSz.Width() - 1L ); 2521 nMirrFlags |= BMP_MIRROR_HORZ; 2522 } 2523 2524 // mirrored vertically 2525 if( aDestSz.Height() < 0L ) 2526 { 2527 aDestSz.Height() = -aDestSz.Height(); 2528 aDestPt.Y() -= ( aDestSz.Height() - 1L ); 2529 nMirrFlags |= BMP_MIRROR_VERT; 2530 } 2531 2532 // source cropped? 2533 if( aSrcRect != Rectangle( aPt, aMask.GetSizePixel() ) ) 2534 aMask.Crop( aSrcRect ); 2535 2536 // destination mirrored 2537 if( nMirrFlags ) 2538 aMask.Mirror( nMirrFlags ); 2539 2540 // do painting 2541 const long nSrcWidth = aSrcRect.GetWidth(), nSrcHeight = aSrcRect.GetHeight(); 2542 long nX, nY; //, nWorkX, nWorkY, nWorkWidth, nWorkHeight; 2543 long* pMapX = new long[ nSrcWidth + 1 ]; 2544 long* pMapY = new long[ nSrcHeight + 1 ]; 2545 GDIMetaFile* pOldMetaFile = mpMetaFile; 2546 const sal_Bool bOldMap = mbMap; 2547 2548 mpMetaFile = NULL; 2549 mbMap = sal_False; 2550 Push( PUSH_FILLCOLOR | PUSH_LINECOLOR ); 2551 SetLineColor( rMaskColor ); 2552 SetFillColor( rMaskColor ); 2553 ImplInitLineColor(); 2554 ImplInitFillColor(); 2555 2556 // create forward mapping tables 2557 for( nX = 0L; nX <= nSrcWidth; nX++ ) 2558 pMapX[ nX ] = aDestPt.X() + FRound( (double) aDestSz.Width() * nX / nSrcWidth ); 2559 2560 for( nY = 0L; nY <= nSrcHeight; nY++ ) 2561 pMapY[ nY ] = aDestPt.Y() + FRound( (double) aDestSz.Height() * nY / nSrcHeight ); 2562 2563 // walk through all rectangles of mask 2564 const Region aWorkRgn(aMask.CreateRegion(COL_BLACK, Rectangle(Point(), aMask.GetSizePixel()))); 2565 RectangleVector aRectangles; 2566 aWorkRgn.GetRegionRectangles(aRectangles); 2567 2568 for(RectangleVector::const_iterator aRectIter(aRectangles.begin()); aRectIter != aRectangles.end(); aRectIter++) 2569 { 2570 const Point aMapPt(pMapX[aRectIter->Left()], pMapY[aRectIter->Top()]); 2571 const Size aMapSz( 2572 pMapX[aRectIter->Right() + 1] - aMapPt.X(), // pMapX[L + W] -> L + ((R - L) + 1) -> R + 1 2573 pMapY[aRectIter->Bottom() + 1] - aMapPt.Y()); // same for Y 2574 2575 DrawRect(Rectangle(aMapPt, aMapSz)); 2576 } 2577 2578 //Region aWorkRgn( aMask.CreateRegion( COL_BLACK, Rectangle( Point(), aMask.GetSizePixel() ) ) ); 2579 //ImplRegionInfo aInfo; 2580 //sal_Bool bRgnRect = aWorkRgn.ImplGetFirstRect( aInfo, nWorkX, nWorkY, nWorkWidth, nWorkHeight ); 2581 // 2582 //while( bRgnRect ) 2583 //{ 2584 // const Point aMapPt( pMapX[ nWorkX ], pMapY[ nWorkY ] ); 2585 // const Size aMapSz( pMapX[ nWorkX + nWorkWidth ] - aMapPt.X(), pMapY[ nWorkY + nWorkHeight ] - aMapPt.Y() ); 2586 // 2587 // DrawRect( Rectangle( aMapPt, aMapSz ) ); 2588 // bRgnRect = aWorkRgn.ImplGetNextRect( aInfo, nWorkX, nWorkY, nWorkWidth, nWorkHeight ); 2589 //} 2590 2591 Pop(); 2592 delete[] pMapX; 2593 delete[] pMapY; 2594 mbMap = bOldMap; 2595 mpMetaFile = pOldMetaFile; 2596 } 2597 } 2598