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