1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_svtools.hxx" 30 31 #include <vos/macros.hxx> 32 #include <vcl/bmpacc.hxx> 33 #include <tools/poly.hxx> 34 #include <vcl/outdev.hxx> 35 #include <vcl/window.hxx> 36 #include <vcl/gdimtf.hxx> 37 #include <vcl/metaact.hxx> 38 #include <vcl/metric.hxx> 39 #include <vcl/animate.hxx> 40 #include <vcl/alpha.hxx> 41 #include <vcl/virdev.hxx> 42 #include "grfcache.hxx" 43 #include <svtools/grfmgr.hxx> 44 45 // ----------- 46 // - defines - 47 // ----------- 48 49 #define MAX_PRINTER_EXT 1024 50 #define MAP( cVal0, cVal1, nFrac ) ((sal_uInt8)((((long)(cVal0)<<20L)+nFrac*((long)(cVal1)-(cVal0)))>>20L)) 51 #define WATERMARK_LUM_OFFSET 50 52 #define WATERMARK_CON_OFFSET -70 53 54 // ----------- 55 // - helpers - 56 // ----------- 57 58 namespace { 59 60 void muckWithBitmap( const Point& rDestPoint, 61 const Size& rDestSize, 62 const Size& rRefSize, 63 bool& o_rbNonBitmapActionEncountered ) 64 { 65 const Point aEmptyPoint; 66 67 if( aEmptyPoint != rDestPoint || 68 rDestSize != rRefSize ) 69 { 70 // non-fullscale, or offsetted bmp -> fallback to mtf 71 // rendering 72 o_rbNonBitmapActionEncountered = true; 73 } 74 } 75 76 BitmapEx muckWithBitmap( const BitmapEx& rBmpEx, 77 const Point& rSrcPoint, 78 const Size& rSrcSize, 79 const Point& rDestPoint, 80 const Size& rDestSize, 81 const Size& rRefSize, 82 bool& o_rbNonBitmapActionEncountered ) 83 { 84 BitmapEx aBmpEx; 85 86 muckWithBitmap(rDestPoint, 87 rDestSize, 88 rRefSize, 89 o_rbNonBitmapActionEncountered); 90 91 if( o_rbNonBitmapActionEncountered ) 92 return aBmpEx; 93 94 aBmpEx = rBmpEx; 95 96 if( (rSrcPoint.X() != 0 && rSrcPoint.Y() != 0) || 97 rSrcSize != rBmpEx.GetSizePixel() ) 98 { 99 // crop bitmap to given source rectangle (no 100 // need to copy and convert the whole bitmap) 101 const Rectangle aCropRect( rSrcPoint, 102 rSrcSize ); 103 aBmpEx.Crop( aCropRect ); 104 } 105 106 return aBmpEx; 107 } 108 109 } // namespace { 110 111 112 // ------------------ 113 // - GraphicManager - 114 // ------------------ 115 116 GraphicManager::GraphicManager( sal_uLong nCacheSize, sal_uLong nMaxObjCacheSize ) : 117 mpCache( new GraphicCache( *this, nCacheSize, nMaxObjCacheSize ) ) 118 { 119 } 120 121 // ----------------------------------------------------------------------------- 122 123 GraphicManager::~GraphicManager() 124 { 125 for( void* pObj = maObjList.First(); pObj; pObj = maObjList.Next() ) 126 ( (GraphicObject*) pObj )->GraphicManagerDestroyed(); 127 128 delete mpCache; 129 } 130 131 // ----------------------------------------------------------------------------- 132 133 void GraphicManager::SetMaxCacheSize( sal_uLong nNewCacheSize ) 134 { 135 mpCache->SetMaxDisplayCacheSize( nNewCacheSize ); 136 } 137 138 // ----------------------------------------------------------------------------- 139 140 sal_uLong GraphicManager::GetMaxCacheSize() const 141 { 142 return mpCache->GetMaxDisplayCacheSize(); 143 } 144 145 // ----------------------------------------------------------------------------- 146 147 void GraphicManager::SetMaxObjCacheSize( sal_uLong nNewMaxObjSize, sal_Bool bDestroyGreaterCached ) 148 { 149 mpCache->SetMaxObjDisplayCacheSize( nNewMaxObjSize, bDestroyGreaterCached ); 150 } 151 152 // ----------------------------------------------------------------------------- 153 154 sal_uLong GraphicManager::GetMaxObjCacheSize() const 155 { 156 return mpCache->GetMaxObjDisplayCacheSize(); 157 } 158 159 // ----------------------------------------------------------------------------- 160 161 sal_uLong GraphicManager::GetUsedCacheSize() const 162 { 163 return mpCache->GetUsedDisplayCacheSize(); 164 } 165 166 // ----------------------------------------------------------------------------- 167 168 sal_uLong GraphicManager::GetFreeCacheSize() const 169 { 170 return mpCache->GetFreeDisplayCacheSize(); 171 } 172 173 // ----------------------------------------------------------------------------- 174 175 void GraphicManager::SetCacheTimeout( sal_uLong nTimeoutSeconds ) 176 { 177 mpCache->SetCacheTimeout( nTimeoutSeconds ); 178 } 179 180 // ----------------------------------------------------------------------------- 181 182 sal_uLong GraphicManager::GetCacheTimeout() const 183 { 184 return mpCache->GetCacheTimeout(); 185 } 186 187 // ----------------------------------------------------------------------------- 188 189 void GraphicManager::ClearCache() 190 { 191 mpCache->ClearDisplayCache(); 192 } 193 194 // ----------------------------------------------------------------------------- 195 196 void GraphicManager::ReleaseFromCache( const GraphicObject& /*rObj*/ ) 197 { 198 // !!! 199 } 200 201 // ----------------------------------------------------------------------------- 202 203 sal_Bool GraphicManager::IsInCache( OutputDevice* pOut, const Point& rPt, 204 const Size& rSz, const GraphicObject& rObj, 205 const GraphicAttr& rAttr ) const 206 { 207 return mpCache->IsInDisplayCache( pOut, rPt, rSz, rObj, rAttr ); 208 } 209 210 // ----------------------------------------------------------------------------- 211 212 sal_Bool GraphicManager::DrawObj( OutputDevice* pOut, const Point& rPt, const Size& rSz, 213 GraphicObject& rObj, const GraphicAttr& rAttr, 214 const sal_uLong nFlags, sal_Bool& rCached ) 215 { 216 Point aPt( rPt ); 217 Size aSz( rSz ); 218 sal_Bool bRet = sal_False; 219 220 rCached = sal_False; 221 222 if( ( rObj.GetType() == GRAPHIC_BITMAP ) || ( rObj.GetType() == GRAPHIC_GDIMETAFILE ) ) 223 { 224 // create output and fill cache 225 const Size aOutSize( pOut->GetOutputSizePixel() ); 226 227 if( rObj.IsAnimated() || ( pOut->GetOutDevType() == OUTDEV_PRINTER ) || 228 ( !( nFlags & GRFMGR_DRAW_NO_SUBSTITUTE ) && 229 ( ( nFlags & GRFMGR_DRAW_SUBSTITUTE ) || 230 !( nFlags & GRFMGR_DRAW_CACHED ) || 231 ( pOut->GetConnectMetaFile() && !pOut->IsOutputEnabled() ) ) ) ) 232 { 233 // simple output of transformed graphic 234 const Graphic aGraphic( rObj.GetTransformedGraphic( &rAttr ) ); 235 236 if( aGraphic.IsSupportedGraphic() ) 237 { 238 const sal_uInt16 nRot10 = rAttr.GetRotation() % 3600; 239 240 if( nRot10 ) 241 { 242 Polygon aPoly( Rectangle( aPt, aSz ) ); 243 244 aPoly.Rotate( aPt, nRot10 ); 245 const Rectangle aRotBoundRect( aPoly.GetBoundRect() ); 246 aPt = aRotBoundRect.TopLeft(); 247 aSz = aRotBoundRect.GetSize(); 248 } 249 250 aGraphic.Draw( pOut, aPt, aSz ); 251 } 252 253 bRet = sal_True; 254 } 255 256 if( !bRet ) 257 { 258 // cached/direct drawing 259 if( !mpCache->DrawDisplayCacheObj( pOut, aPt, aSz, rObj, rAttr ) ) 260 bRet = ImplDraw( pOut, aPt, aSz, rObj, rAttr, nFlags, rCached ); 261 else 262 bRet = rCached = sal_True; 263 } 264 } 265 266 return bRet; 267 } 268 269 // ----------------------------------------------------------------------------- 270 271 void GraphicManager::ImplRegisterObj( const GraphicObject& rObj, Graphic& rSubstitute, 272 const ByteString* pID, const GraphicObject* pCopyObj ) 273 { 274 maObjList.Insert( (void*) &rObj, LIST_APPEND ); 275 mpCache->AddGraphicObject( rObj, rSubstitute, pID, pCopyObj ); 276 } 277 278 // ----------------------------------------------------------------------------- 279 280 void GraphicManager::ImplUnregisterObj( const GraphicObject& rObj ) 281 { 282 mpCache->ReleaseGraphicObject( rObj ); 283 maObjList.Remove( (void*) &rObj ); 284 } 285 286 // ----------------------------------------------------------------------------- 287 288 void GraphicManager::ImplGraphicObjectWasSwappedOut( const GraphicObject& rObj ) 289 { 290 mpCache->GraphicObjectWasSwappedOut( rObj ); 291 } 292 293 // ----------------------------------------------------------------------------- 294 295 ByteString GraphicManager::ImplGetUniqueID( const GraphicObject& rObj ) const 296 { 297 return mpCache->GetUniqueID( rObj ); 298 } 299 300 // ----------------------------------------------------------------------------- 301 302 sal_Bool GraphicManager::ImplFillSwappedGraphicObject( const GraphicObject& rObj, Graphic& rSubstitute ) 303 { 304 return( mpCache->FillSwappedGraphicObject( rObj, rSubstitute ) ); 305 } 306 307 // ----------------------------------------------------------------------------- 308 309 void GraphicManager::ImplGraphicObjectWasSwappedIn( const GraphicObject& rObj ) 310 { 311 mpCache->GraphicObjectWasSwappedIn( rObj ); 312 } 313 314 // ----------------------------------------------------------------------------- 315 316 sal_Bool GraphicManager::ImplDraw( OutputDevice* pOut, const Point& rPt, 317 const Size& rSz, GraphicObject& rObj, 318 const GraphicAttr& rAttr, 319 const sal_uLong nFlags, sal_Bool& rCached ) 320 { 321 const Graphic& rGraphic = rObj.GetGraphic(); 322 sal_Bool bRet = sal_False; 323 324 if( rGraphic.IsSupportedGraphic() && !rGraphic.IsSwapOut() ) 325 { 326 if( GRAPHIC_BITMAP == rGraphic.GetType() ) 327 { 328 const BitmapEx aSrcBmpEx( rGraphic.GetBitmapEx() ); 329 330 // #i46805# No point in caching a bitmap that is rendered 331 // via RectFill on the OutDev 332 if( !(pOut->GetDrawMode() & ( DRAWMODE_BLACKBITMAP | DRAWMODE_WHITEBITMAP )) && 333 mpCache->IsDisplayCacheable( pOut, rPt, rSz, rObj, rAttr ) ) 334 { 335 BitmapEx aDstBmpEx; 336 337 if( ImplCreateOutput( pOut, rPt, rSz, aSrcBmpEx, rAttr, nFlags, &aDstBmpEx ) ) 338 { 339 rCached = mpCache->CreateDisplayCacheObj( pOut, rPt, rSz, rObj, rAttr, aDstBmpEx ); 340 bRet = sal_True; 341 } 342 } 343 344 if( !bRet ) 345 bRet = ImplCreateOutput( pOut, rPt, rSz, aSrcBmpEx, rAttr, nFlags ); 346 } 347 else 348 { 349 const GDIMetaFile& rSrcMtf = rGraphic.GetGDIMetaFile(); 350 351 if( mpCache->IsDisplayCacheable( pOut, rPt, rSz, rObj, rAttr ) ) 352 { 353 GDIMetaFile aDstMtf; 354 BitmapEx aContainedBmpEx; 355 356 if( ImplCreateOutput( pOut, rPt, rSz, rSrcMtf, rAttr, nFlags, aDstMtf, aContainedBmpEx ) ) 357 { 358 if( !!aContainedBmpEx ) 359 { 360 // #117889# Use bitmap output method, if 361 // metafile basically contains only a single 362 // bitmap 363 BitmapEx aDstBmpEx; 364 365 if( ImplCreateOutput( pOut, rPt, rSz, aContainedBmpEx, rAttr, nFlags, &aDstBmpEx ) ) 366 { 367 rCached = mpCache->CreateDisplayCacheObj( pOut, rPt, rSz, rObj, rAttr, aDstBmpEx ); 368 bRet = sal_True; 369 } 370 } 371 else 372 { 373 rCached = mpCache->CreateDisplayCacheObj( pOut, rPt, rSz, rObj, rAttr, aDstMtf ); 374 bRet = sal_True; 375 } 376 } 377 } 378 379 if( !bRet ) 380 { 381 const Graphic aGraphic( rObj.GetTransformedGraphic( &rAttr ) ); 382 383 if( aGraphic.IsSupportedGraphic() ) 384 { 385 aGraphic.Draw( pOut, rPt, rSz ); 386 bRet = sal_True; 387 } 388 } 389 } 390 } 391 392 return bRet; 393 } 394 395 // ----------------------------------------------------------------------------- 396 397 sal_Bool GraphicManager::ImplCreateOutput( OutputDevice* pOut, 398 const Point& rPt, const Size& rSz, 399 const BitmapEx& rBmpEx, const GraphicAttr& rAttr, 400 const sal_uLong nFlags, BitmapEx* pBmpEx ) 401 { 402 sal_uInt16 nRot10 = rAttr.GetRotation() % 3600; 403 Point aOutPtPix; 404 Size aOutSzPix; 405 Size aUnrotatedSzPix( pOut->LogicToPixel( rSz ) ); 406 sal_Bool bRet = sal_False; 407 408 if( nRot10 ) 409 { 410 Polygon aPoly( Rectangle( rPt, rSz ) ); 411 412 aPoly.Rotate( rPt, nRot10 ); 413 const Rectangle aRotBoundRect( aPoly.GetBoundRect() ); 414 aOutPtPix = pOut->LogicToPixel( aRotBoundRect.TopLeft() ); 415 aOutSzPix = pOut->LogicToPixel( aRotBoundRect.GetSize() ); 416 } 417 else 418 { 419 aOutPtPix = pOut->LogicToPixel( rPt ); 420 aOutSzPix = aUnrotatedSzPix; 421 } 422 423 if( aUnrotatedSzPix.Width() && aUnrotatedSzPix.Height() ) 424 { 425 BitmapEx aBmpEx( rBmpEx ); 426 BitmapEx aOutBmpEx; 427 Point aOutPt; 428 Size aOutSz; 429 const Size& rBmpSzPix = rBmpEx.GetSizePixel(); 430 const long nW = rBmpSzPix.Width(); 431 const long nH = rBmpSzPix.Height(); 432 const long nNewW = aUnrotatedSzPix.Width(); 433 const long nNewH = aUnrotatedSzPix.Height(); 434 double fTmp; 435 long* pMapIX = new long[ nNewW ]; 436 long* pMapFX = new long[ nNewW ]; 437 long* pMapIY = new long[ nNewH ]; 438 long* pMapFY = new long[ nNewH ]; 439 long nStartX = -1, nStartY = -1, nEndX = -1, nEndY = -1; 440 long nX, nY, nTmp, nTmpX, nTmpY; 441 sal_Bool bHMirr = ( rAttr.GetMirrorFlags() & BMP_MIRROR_HORZ ) != 0; 442 sal_Bool bVMirr = ( rAttr.GetMirrorFlags() & BMP_MIRROR_VERT ) != 0; 443 444 if( nFlags & GRFMGR_DRAW_BILINEAR ) 445 { 446 const double fRevScaleX = ( nNewW > 1L ) ? ( (double) ( nW - 1L ) / ( nNewW - 1L ) ) : 0.0; 447 const double fRevScaleY = ( nNewH > 1L ) ? ( (double) ( nH - 1L ) / ( nNewH - 1L ) ) : 0.0; 448 449 // create horizontal mapping table 450 for( nX = 0L, nTmpX = nW - 1L, nTmp = nW - 2L; nX < nNewW; nX++ ) 451 { 452 fTmp = nX * fRevScaleX; 453 454 if( bHMirr ) 455 fTmp = nTmpX - fTmp; 456 457 pMapFX[ nX ] = (long) ( ( fTmp - ( pMapIX[ nX ] = MinMax( (long) fTmp, 0, nTmp ) ) ) * 1048576. ); 458 } 459 460 // create vertical mapping table 461 for( nY = 0L, nTmpY = nH - 1L, nTmp = nH - 2L; nY < nNewH; nY++ ) 462 { 463 fTmp = nY * fRevScaleY; 464 465 if( bVMirr ) 466 fTmp = nTmpY - fTmp; 467 468 pMapFY[ nY ] = (long) ( ( fTmp - ( pMapIY[ nY ] = MinMax( (long) fTmp, 0, nTmp ) ) ) * 1048576. ); 469 } 470 } 471 else 472 { 473 // #98290# Use a different mapping for non-interpolating mode, to avoid missing rows/columns 474 const double fRevScaleX = ( nNewW > 1L ) ? ( (double) nW / nNewW ) : 0.0; 475 const double fRevScaleY = ( nNewH > 1L ) ? ( (double) nH / nNewH ) : 0.0; 476 477 // create horizontal mapping table 478 for( nX = 0L, nTmpX = nW - 1L, nTmp = nW - 2L; nX < nNewW; nX++ ) 479 { 480 fTmp = nX * fRevScaleX; 481 482 if( bHMirr ) 483 fTmp = nTmpX - fTmp; 484 485 // #98290# Do not use round to zero, otherwise last column will be missing 486 pMapIX[ nX ] = MinMax( (long) fTmp, 0, nTmp ); 487 pMapFX[ nX ] = fTmp >= nTmp+1 ? 1048576 : 0; 488 } 489 490 // create vertical mapping table 491 for( nY = 0L, nTmpY = nH - 1L, nTmp = nH - 2L; nY < nNewH; nY++ ) 492 { 493 fTmp = nY * fRevScaleY; 494 495 if( bVMirr ) 496 fTmp = nTmpY - fTmp; 497 498 // #98290# Do not use round to zero, otherwise last row will be missing 499 pMapIY[ nY ] = MinMax( (long) fTmp, 0, nTmp ); 500 pMapFY[ nY ] = fTmp >= nTmp+1 ? 1048576 : 0; 501 } 502 } 503 504 // calculate output sizes 505 if( !pBmpEx ) 506 { 507 Point aPt; 508 Rectangle aOutRect( aPt, pOut->GetOutputSizePixel() ); 509 Rectangle aBmpRect( aOutPtPix, aOutSzPix ); 510 511 if( pOut->GetOutDevType() == OUTDEV_WINDOW ) 512 { 513 const Region aPaintRgn( ( (Window*) pOut )->GetPaintRegion() ); 514 if( !aPaintRgn.IsNull() ) 515 aOutRect.Intersection( pOut->LogicToPixel( aPaintRgn.GetBoundRect() ) ); 516 } 517 518 aOutRect.Intersection( aBmpRect ); 519 520 if( !aOutRect.IsEmpty() ) 521 { 522 aOutPt = pOut->PixelToLogic( aOutRect.TopLeft() ); 523 aOutSz = pOut->PixelToLogic( aOutRect.GetSize() ); 524 nStartX = aOutRect.Left() - aBmpRect.Left(); 525 nStartY = aOutRect.Top() - aBmpRect.Top(); 526 nEndX = aOutRect.Right() - aBmpRect.Left(); 527 nEndY = aOutRect.Bottom() - aBmpRect.Top(); 528 } 529 else 530 nStartX = -1L; // invalid 531 } 532 else 533 { 534 aOutPt = pOut->PixelToLogic( aOutPtPix ); 535 aOutSz = pOut->PixelToLogic( aOutSzPix ); 536 nStartX = nStartY = 0; 537 nEndX = aOutSzPix.Width() - 1L; 538 nEndY = aOutSzPix.Height() - 1L; 539 } 540 541 // do transformation 542 if( nStartX >= 0L ) 543 { 544 const sal_Bool bSimple = ( 1 == nW || 1 == nH ); 545 546 if( nRot10 ) 547 { 548 if( bSimple ) 549 { 550 bRet = ( aOutBmpEx = aBmpEx ).Scale( aUnrotatedSzPix ); 551 552 if( bRet ) 553 aOutBmpEx.Rotate( nRot10, COL_TRANSPARENT ); 554 } 555 else 556 { 557 bRet = ImplCreateRotatedScaled( aBmpEx, 558 nRot10, aOutSzPix, aUnrotatedSzPix, 559 pMapIX, pMapFX, pMapIY, pMapFY, nStartX, nEndX, nStartY, nEndY, 560 aOutBmpEx ); 561 } 562 } 563 else 564 { 565 // #105229# Don't scale if output size equals bitmap size 566 // #107226# Copy through only if we're not mirroring 567 if( !bHMirr && !bVMirr && aOutSzPix == rBmpSzPix ) 568 { 569 // #107226# Use original dimensions when just copying through 570 aOutPt = pOut->PixelToLogic( aOutPtPix ); 571 aOutSz = pOut->PixelToLogic( aOutSzPix ); 572 aOutBmpEx = aBmpEx; 573 bRet = sal_True; 574 } 575 else 576 { 577 if( bSimple ) 578 bRet = ( aOutBmpEx = aBmpEx ).Scale( Size( nEndX - nStartX + 1, nEndY - nStartY + 1 ) ); 579 else 580 { 581 bRet = ImplCreateScaled( aBmpEx, 582 pMapIX, pMapFX, pMapIY, pMapFY, 583 nStartX, nEndX, nStartY, nEndY, 584 aOutBmpEx ); 585 } 586 } 587 } 588 589 if( bRet ) 590 { 591 // attribute adjustment if neccessary 592 if( rAttr.IsSpecialDrawMode() || rAttr.IsAdjusted() || rAttr.IsTransparent() ) 593 ImplAdjust( aOutBmpEx, rAttr, ADJUSTMENT_DRAWMODE | ADJUSTMENT_COLORS | ADJUSTMENT_TRANSPARENCY ); 594 595 // OutDev adjustment if neccessary 596 if( pOut->GetOutDevType() != OUTDEV_PRINTER && pOut->GetBitCount() <= 8 && aOutBmpEx.GetBitCount() >= 8 ) 597 aOutBmpEx.Dither( BMP_DITHER_MATRIX ); 598 } 599 } 600 601 // delete lookup tables 602 delete[] pMapIX; 603 delete[] pMapFX; 604 delete[] pMapIY; 605 delete[] pMapFY; 606 607 // create output 608 if( bRet ) 609 { 610 if( !pBmpEx ) 611 pOut->DrawBitmapEx( aOutPt, aOutSz, aOutBmpEx ); 612 else 613 { 614 if( !rAttr.IsTransparent() && !aOutBmpEx.IsAlpha() ) 615 aOutBmpEx = BitmapEx( aOutBmpEx.GetBitmap().CreateDisplayBitmap( pOut ), aOutBmpEx.GetMask() ); 616 617 pOut->DrawBitmapEx( aOutPt, aOutSz, *pBmpEx = aOutBmpEx ); 618 } 619 } 620 } 621 622 return bRet; 623 } 624 625 // ----------------------------------------------------------------------------- 626 627 sal_Bool GraphicManager::ImplCreateOutput( OutputDevice* pOut, 628 const Point& rPt, const Size& rSz, 629 const GDIMetaFile& rMtf, const GraphicAttr& rAttr, 630 const sal_uLong /*nFlags*/, GDIMetaFile& rOutMtf, BitmapEx& rOutBmpEx ) 631 { 632 const Size aNewSize( rMtf.GetPrefSize() ); 633 634 rOutMtf = rMtf; 635 636 // #117889# count bitmap actions, and flag actions that paint, but 637 // are no bitmaps. 638 sal_Int32 nNumBitmaps(0); 639 bool bNonBitmapActionEncountered(false); 640 if( aNewSize.Width() && aNewSize.Height() && rSz.Width() && rSz.Height() ) 641 { 642 const double fGrfWH = (double) aNewSize.Width() / aNewSize.Height(); 643 const double fOutWH = (double) rSz.Width() / rSz.Height(); 644 645 const double fScaleX = fOutWH / fGrfWH; 646 const double fScaleY = 1.0; 647 648 const MapMode& rPrefMapMode( rMtf.GetPrefMapMode() ); 649 const Size& rSizePix( pOut->LogicToPixel( aNewSize, 650 rPrefMapMode ) ); 651 652 // taking care of font width default if scaling metafile. 653 // #117889# use existing metafile scan, to determine whether 654 // the metafile basically displays a single bitmap. Note that 655 // the solution, as implemented here, is quite suboptimal (the 656 // cases where a mtf consisting basically of a single bitmap, 657 // that fail to pass the test below, are probably frequent). A 658 // better solution would involve FSAA, but that's currently 659 // expensive, and might trigger bugs on display drivers, if 660 // VDevs get bigger than the actual screen. 661 sal_uInt32 nCurPos; 662 MetaAction* pAct; 663 for( nCurPos = 0, pAct = (MetaAction*)rOutMtf.FirstAction(); pAct; 664 pAct = (MetaAction*)rOutMtf.NextAction(), nCurPos++ ) 665 { 666 MetaAction* pModAct = NULL; 667 switch( pAct->GetType() ) 668 { 669 case META_FONT_ACTION: 670 { 671 MetaFontAction* pA = (MetaFontAction*)pAct; 672 Font aFont( pA->GetFont() ); 673 if ( !aFont.GetWidth() ) 674 { 675 FontMetric aFontMetric( pOut->GetFontMetric( aFont ) ); 676 aFont.SetWidth( aFontMetric.GetWidth() ); 677 pModAct = new MetaFontAction( aFont ); 678 } 679 } 680 // FALLTHROUGH intended 681 case META_NULL_ACTION: 682 // FALLTHROUGH intended 683 684 // OutDev state changes (which don't affect bitmap 685 // output) 686 case META_LINECOLOR_ACTION: 687 // FALLTHROUGH intended 688 case META_FILLCOLOR_ACTION: 689 // FALLTHROUGH intended 690 case META_TEXTCOLOR_ACTION: 691 // FALLTHROUGH intended 692 case META_TEXTFILLCOLOR_ACTION: 693 // FALLTHROUGH intended 694 case META_TEXTALIGN_ACTION: 695 // FALLTHROUGH intended 696 case META_TEXTLINECOLOR_ACTION: 697 // FALLTHROUGH intended 698 case META_TEXTLINE_ACTION: 699 // FALLTHROUGH intended 700 case META_PUSH_ACTION: 701 // FALLTHROUGH intended 702 case META_POP_ACTION: 703 // FALLTHROUGH intended 704 case META_LAYOUTMODE_ACTION: 705 // FALLTHROUGH intended 706 case META_TEXTLANGUAGE_ACTION: 707 // FALLTHROUGH intended 708 case META_COMMENT_ACTION: 709 break; 710 711 // bitmap output methods 712 case META_BMP_ACTION: 713 if( !nNumBitmaps && !bNonBitmapActionEncountered ) 714 { 715 MetaBmpAction* pAction = (MetaBmpAction*)pAct; 716 717 rOutBmpEx = BitmapEx( pAction->GetBitmap() ); 718 muckWithBitmap( pOut->LogicToPixel( pAction->GetPoint(), 719 rPrefMapMode ), 720 pAction->GetBitmap().GetSizePixel(), 721 rSizePix, 722 bNonBitmapActionEncountered ); 723 ++nNumBitmaps; 724 } 725 break; 726 727 case META_BMPSCALE_ACTION: 728 if( !nNumBitmaps && !bNonBitmapActionEncountered ) 729 { 730 MetaBmpScaleAction* pAction = (MetaBmpScaleAction*)pAct; 731 732 rOutBmpEx = BitmapEx( pAction->GetBitmap() ); 733 muckWithBitmap( pOut->LogicToPixel( pAction->GetPoint(), 734 rPrefMapMode ), 735 pOut->LogicToPixel( pAction->GetSize(), 736 rPrefMapMode ), 737 rSizePix, 738 bNonBitmapActionEncountered ); 739 ++nNumBitmaps; 740 } 741 break; 742 743 case META_BMPSCALEPART_ACTION: 744 if( !nNumBitmaps && !bNonBitmapActionEncountered ) 745 { 746 MetaBmpScalePartAction* pAction = (MetaBmpScalePartAction*)pAct; 747 748 rOutBmpEx = muckWithBitmap( BitmapEx( pAction->GetBitmap() ), 749 pAction->GetSrcPoint(), 750 pAction->GetSrcSize(), 751 pOut->LogicToPixel( pAction->GetDestPoint(), 752 rPrefMapMode ), 753 pOut->LogicToPixel( pAction->GetDestSize(), 754 rPrefMapMode ), 755 rSizePix, 756 bNonBitmapActionEncountered ); 757 ++nNumBitmaps; 758 } 759 break; 760 761 case META_BMPEX_ACTION: 762 if( !nNumBitmaps && !bNonBitmapActionEncountered ) 763 { 764 MetaBmpExAction* pAction = (MetaBmpExAction*)pAct; 765 766 rOutBmpEx = pAction->GetBitmapEx(); 767 muckWithBitmap( pOut->LogicToPixel( pAction->GetPoint(), 768 rPrefMapMode ), 769 pAction->GetBitmapEx().GetSizePixel(), 770 rSizePix, 771 bNonBitmapActionEncountered ); 772 ++nNumBitmaps; 773 } 774 break; 775 776 case META_BMPEXSCALE_ACTION: 777 if( !nNumBitmaps && !bNonBitmapActionEncountered ) 778 { 779 MetaBmpExScaleAction* pAction = (MetaBmpExScaleAction*)pAct; 780 781 rOutBmpEx = pAction->GetBitmapEx(); 782 muckWithBitmap( pOut->LogicToPixel( pAction->GetPoint(), 783 rPrefMapMode ), 784 pOut->LogicToPixel( pAction->GetSize(), 785 rPrefMapMode ), 786 rSizePix, 787 bNonBitmapActionEncountered ); 788 ++nNumBitmaps; 789 } 790 break; 791 792 case META_BMPEXSCALEPART_ACTION: 793 if( !nNumBitmaps && !bNonBitmapActionEncountered ) 794 { 795 MetaBmpExScalePartAction* pAction = (MetaBmpExScalePartAction*)pAct; 796 797 rOutBmpEx = muckWithBitmap( pAction->GetBitmapEx(), 798 pAction->GetSrcPoint(), 799 pAction->GetSrcSize(), 800 pOut->LogicToPixel( pAction->GetDestPoint(), 801 rPrefMapMode ), 802 pOut->LogicToPixel( pAction->GetDestSize(), 803 rPrefMapMode ), 804 rSizePix, 805 bNonBitmapActionEncountered ); 806 ++nNumBitmaps; 807 } 808 break; 809 810 // these actions actually output something (that's 811 // different from a bitmap) 812 case META_RASTEROP_ACTION: 813 if( ((MetaRasterOpAction*)pAct)->GetRasterOp() == ROP_OVERPAINT ) 814 break; 815 // FALLTHROUGH intended 816 case META_PIXEL_ACTION: 817 // FALLTHROUGH intended 818 case META_POINT_ACTION: 819 // FALLTHROUGH intended 820 case META_LINE_ACTION: 821 // FALLTHROUGH intended 822 case META_RECT_ACTION: 823 // FALLTHROUGH intended 824 case META_ROUNDRECT_ACTION: 825 // FALLTHROUGH intended 826 case META_ELLIPSE_ACTION: 827 // FALLTHROUGH intended 828 case META_ARC_ACTION: 829 // FALLTHROUGH intended 830 case META_PIE_ACTION: 831 // FALLTHROUGH intended 832 case META_CHORD_ACTION: 833 // FALLTHROUGH intended 834 case META_POLYLINE_ACTION: 835 // FALLTHROUGH intended 836 case META_POLYGON_ACTION: 837 // FALLTHROUGH intended 838 case META_POLYPOLYGON_ACTION: 839 // FALLTHROUGH intended 840 841 case META_TEXT_ACTION: 842 // FALLTHROUGH intended 843 case META_TEXTARRAY_ACTION: 844 // FALLTHROUGH intended 845 case META_STRETCHTEXT_ACTION: 846 // FALLTHROUGH intended 847 case META_TEXTRECT_ACTION: 848 // FALLTHROUGH intended 849 850 case META_MASK_ACTION: 851 // FALLTHROUGH intended 852 case META_MASKSCALE_ACTION: 853 // FALLTHROUGH intended 854 case META_MASKSCALEPART_ACTION: 855 // FALLTHROUGH intended 856 857 case META_GRADIENT_ACTION: 858 // FALLTHROUGH intended 859 case META_HATCH_ACTION: 860 // FALLTHROUGH intended 861 case META_WALLPAPER_ACTION: 862 // FALLTHROUGH intended 863 864 case META_TRANSPARENT_ACTION: 865 // FALLTHROUGH intended 866 case META_EPS_ACTION: 867 // FALLTHROUGH intended 868 case META_FLOATTRANSPARENT_ACTION: 869 // FALLTHROUGH intended 870 case META_GRADIENTEX_ACTION: 871 // FALLTHROUGH intended 872 case META_RENDERGRAPHIC_ACTION: 873 // FALLTHROUGH intended 874 875 // OutDev state changes that _do_ affect bitmap 876 // output 877 case META_CLIPREGION_ACTION: 878 // FALLTHROUGH intended 879 case META_ISECTRECTCLIPREGION_ACTION: 880 // FALLTHROUGH intended 881 case META_ISECTREGIONCLIPREGION_ACTION: 882 // FALLTHROUGH intended 883 case META_MOVECLIPREGION_ACTION: 884 // FALLTHROUGH intended 885 886 case META_MAPMODE_ACTION: 887 // FALLTHROUGH intended 888 case META_REFPOINT_ACTION: 889 // FALLTHROUGH intended 890 default: 891 bNonBitmapActionEncountered = true; 892 break; 893 } 894 if ( pModAct ) 895 { 896 rOutMtf.ReplaceAction( pModAct, nCurPos ); 897 pAct->Delete(); 898 } 899 else 900 { 901 if( pAct->GetRefCount() > 1 ) 902 { 903 rOutMtf.ReplaceAction( pModAct = pAct->Clone(), nCurPos ); 904 pAct->Delete(); 905 } 906 else 907 pModAct = pAct; 908 } 909 pModAct->Scale( fScaleX, fScaleY ); 910 } 911 rOutMtf.SetPrefSize( Size( FRound( aNewSize.Width() * fScaleX ), 912 FRound( aNewSize.Height() * fScaleY ) ) ); 913 } 914 915 if( nNumBitmaps != 1 || bNonBitmapActionEncountered ) 916 { 917 if( rAttr.IsSpecialDrawMode() || rAttr.IsAdjusted() || rAttr.IsMirrored() || rAttr.IsRotated() || rAttr.IsTransparent() ) 918 ImplAdjust( rOutMtf, rAttr, ADJUSTMENT_ALL ); 919 920 ImplDraw( pOut, rPt, rSz, rOutMtf, rAttr ); 921 rOutBmpEx = BitmapEx(); 922 } 923 924 return sal_True; 925 } 926 927 // ----------------------------------------------------------------------------- 928 929 sal_Bool GraphicManager::ImplCreateScaled( const BitmapEx& rBmpEx, 930 long* pMapIX, long* pMapFX, long* pMapIY, long* pMapFY, 931 long nStartX, long nEndX, long nStartY, long nEndY, 932 BitmapEx& rOutBmpEx ) 933 { 934 Bitmap aBmp( rBmpEx.GetBitmap() ); 935 Bitmap aOutBmp; 936 BitmapReadAccess* pAcc = aBmp.AcquireReadAccess(); 937 BitmapWriteAccess* pWAcc; 938 BitmapColor aCol0, aCol1, aColRes; 939 const long nDstW = nEndX - nStartX + 1L; 940 const long nDstH = nEndY - nStartY + 1L; 941 long nX, nY, nTmpX, nTmpY, nTmpFX, nTmpFY; 942 long nXDst, nYDst; 943 sal_uInt8 cR0, cG0, cB0, cR1, cG1, cB1; 944 sal_Bool bRet = sal_False; 945 946 DBG_ASSERT( aBmp.GetSizePixel() == rBmpEx.GetSizePixel(), 947 "GraphicManager::ImplCreateScaled(): bmp size inconsistent" ); 948 949 if( pAcc ) 950 { 951 aOutBmp = Bitmap( Size( nDstW, nDstH ), 24 ); 952 pWAcc = aOutBmp.AcquireWriteAccess(); 953 954 if( pWAcc ) 955 { 956 if( pAcc->HasPalette() ) 957 { 958 if( pAcc->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL ) 959 { 960 Scanline pLine0, pLine1; 961 962 for( nY = nStartY, nYDst = 0L; nY <= nEndY; nY++, nYDst++ ) 963 { 964 nTmpY = pMapIY[ nY ]; nTmpFY = pMapFY[ nY ]; 965 pLine0 = pAcc->GetScanline( nTmpY ); 966 pLine1 = pAcc->GetScanline( ++nTmpY ); 967 968 for( nX = nStartX, nXDst = 0L; nX <= nEndX; nX++ ) 969 { 970 nTmpX = pMapIX[ nX ]; nTmpFX = pMapFX[ nX ]; 971 972 const BitmapColor& rCol0 = pAcc->GetPaletteColor( pLine0[ nTmpX ] ); 973 const BitmapColor& rCol2 = pAcc->GetPaletteColor( pLine1[ nTmpX ] ); 974 const BitmapColor& rCol1 = pAcc->GetPaletteColor( pLine0[ ++nTmpX ] ); 975 const BitmapColor& rCol3 = pAcc->GetPaletteColor( pLine1[ nTmpX ] ); 976 977 cR0 = MAP( rCol0.GetRed(), rCol1.GetRed(), nTmpFX ); 978 cG0 = MAP( rCol0.GetGreen(), rCol1.GetGreen(), nTmpFX ); 979 cB0 = MAP( rCol0.GetBlue(), rCol1.GetBlue(), nTmpFX ); 980 981 cR1 = MAP( rCol2.GetRed(), rCol3.GetRed(), nTmpFX ); 982 cG1 = MAP( rCol2.GetGreen(), rCol3.GetGreen(), nTmpFX ); 983 cB1 = MAP( rCol2.GetBlue(), rCol3.GetBlue(), nTmpFX ); 984 985 aColRes.SetRed( MAP( cR0, cR1, nTmpFY ) ); 986 aColRes.SetGreen( MAP( cG0, cG1, nTmpFY ) ); 987 aColRes.SetBlue( MAP( cB0, cB1, nTmpFY ) ); 988 pWAcc->SetPixel( nYDst, nXDst++, aColRes ); 989 } 990 } 991 } 992 else 993 { 994 for( nY = nStartY, nYDst = 0L; nY <= nEndY; nY++, nYDst++ ) 995 { 996 nTmpY = pMapIY[ nY ], nTmpFY = pMapFY[ nY ]; 997 998 for( nX = nStartX, nXDst = 0L; nX <= nEndX; nX++ ) 999 { 1000 nTmpX = pMapIX[ nX ]; nTmpFX = pMapFX[ nX ]; 1001 1002 aCol0 = pAcc->GetPaletteColor( pAcc->GetPixel( nTmpY, nTmpX ) ); 1003 aCol1 = pAcc->GetPaletteColor( pAcc->GetPixel( nTmpY, ++nTmpX ) ); 1004 cR0 = MAP( aCol0.GetRed(), aCol1.GetRed(), nTmpFX ); 1005 cG0 = MAP( aCol0.GetGreen(), aCol1.GetGreen(), nTmpFX ); 1006 cB0 = MAP( aCol0.GetBlue(), aCol1.GetBlue(), nTmpFX ); 1007 1008 aCol1 = pAcc->GetPaletteColor( pAcc->GetPixel( ++nTmpY, nTmpX ) ); 1009 aCol0 = pAcc->GetPaletteColor( pAcc->GetPixel( nTmpY--, --nTmpX ) ); 1010 cR1 = MAP( aCol0.GetRed(), aCol1.GetRed(), nTmpFX ); 1011 cG1 = MAP( aCol0.GetGreen(), aCol1.GetGreen(), nTmpFX ); 1012 cB1 = MAP( aCol0.GetBlue(), aCol1.GetBlue(), nTmpFX ); 1013 1014 aColRes.SetRed( MAP( cR0, cR1, nTmpFY ) ); 1015 aColRes.SetGreen( MAP( cG0, cG1, nTmpFY ) ); 1016 aColRes.SetBlue( MAP( cB0, cB1, nTmpFY ) ); 1017 pWAcc->SetPixel( nYDst, nXDst++, aColRes ); 1018 } 1019 } 1020 } 1021 } 1022 else 1023 { 1024 if( pAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_BGR ) 1025 { 1026 Scanline pLine0, pLine1, pTmp0, pTmp1; 1027 long nOff; 1028 1029 for( nY = nStartY, nYDst = 0L; nY <= nEndY; nY++, nYDst++ ) 1030 { 1031 nTmpY = pMapIY[ nY ]; nTmpFY = pMapFY[ nY ]; 1032 pLine0 = pAcc->GetScanline( nTmpY ); 1033 pLine1 = pAcc->GetScanline( ++nTmpY ); 1034 1035 for( nX = nStartX, nXDst = 0L; nX <= nEndX; nX++ ) 1036 { 1037 nOff = 3L * ( nTmpX = pMapIX[ nX ] ); 1038 nTmpFX = pMapFX[ nX ]; 1039 1040 pTmp1 = ( pTmp0 = pLine0 + nOff ) + 3L; 1041 cB0 = MAP( *pTmp0, *pTmp1, nTmpFX ); pTmp0++; pTmp1++; 1042 cG0 = MAP( *pTmp0, *pTmp1, nTmpFX ); pTmp0++; pTmp1++; 1043 cR0 = MAP( *pTmp0, *pTmp1, nTmpFX ); 1044 1045 pTmp1 = ( pTmp0 = pLine1 + nOff ) + 3L; 1046 cB1 = MAP( *pTmp0, *pTmp1, nTmpFX ); pTmp0++; pTmp1++; 1047 cG1 = MAP( *pTmp0, *pTmp1, nTmpFX ); pTmp0++; pTmp1++; 1048 cR1 = MAP( *pTmp0, *pTmp1, nTmpFX ); 1049 1050 aColRes.SetRed( MAP( cR0, cR1, nTmpFY ) ); 1051 aColRes.SetGreen( MAP( cG0, cG1, nTmpFY ) ); 1052 aColRes.SetBlue( MAP( cB0, cB1, nTmpFY ) ); 1053 pWAcc->SetPixel( nYDst, nXDst++, aColRes ); 1054 } 1055 } 1056 } 1057 else if( pAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_RGB ) 1058 { 1059 Scanline pLine0, pLine1, pTmp0, pTmp1; 1060 long nOff; 1061 1062 for( nY = nStartY, nYDst = 0L; nY <= nEndY; nY++, nYDst++ ) 1063 { 1064 nTmpY = pMapIY[ nY ]; nTmpFY = pMapFY[ nY ]; 1065 pLine0 = pAcc->GetScanline( nTmpY ); 1066 pLine1 = pAcc->GetScanline( ++nTmpY ); 1067 1068 for( nX = nStartX, nXDst = 0L; nX <= nEndX; nX++ ) 1069 { 1070 nOff = 3L * ( nTmpX = pMapIX[ nX ] ); 1071 nTmpFX = pMapFX[ nX ]; 1072 1073 pTmp1 = ( pTmp0 = pLine0 + nOff ) + 3L; 1074 cR0 = MAP( *pTmp0, *pTmp1, nTmpFX ); pTmp0++; pTmp1++; 1075 cG0 = MAP( *pTmp0, *pTmp1, nTmpFX ); pTmp0++; pTmp1++; 1076 cB0 = MAP( *pTmp0, *pTmp1, nTmpFX ); 1077 1078 pTmp1 = ( pTmp0 = pLine1 + nOff ) + 3L; 1079 cR1 = MAP( *pTmp0, *pTmp1, nTmpFX ); pTmp0++; pTmp1++; 1080 cG1 = MAP( *pTmp0, *pTmp1, nTmpFX ); pTmp0++; pTmp1++; 1081 cB1 = MAP( *pTmp0, *pTmp1, nTmpFX ); 1082 1083 aColRes.SetRed( MAP( cR0, cR1, nTmpFY ) ); 1084 aColRes.SetGreen( MAP( cG0, cG1, nTmpFY ) ); 1085 aColRes.SetBlue( MAP( cB0, cB1, nTmpFY ) ); 1086 pWAcc->SetPixel( nYDst, nXDst++, aColRes ); 1087 } 1088 } 1089 } 1090 else 1091 { 1092 for( nY = nStartY, nYDst = 0L; nY <= nEndY; nY++, nYDst++ ) 1093 { 1094 nTmpY = pMapIY[ nY ]; nTmpFY = pMapFY[ nY ]; 1095 1096 for( nX = nStartX, nXDst = 0L; nX <= nEndX; nX++ ) 1097 { 1098 nTmpX = pMapIX[ nX ]; nTmpFX = pMapFX[ nX ]; 1099 1100 aCol0 = pAcc->GetPixel( nTmpY, nTmpX ); 1101 aCol1 = pAcc->GetPixel( nTmpY, ++nTmpX ); 1102 cR0 = MAP( aCol0.GetRed(), aCol1.GetRed(), nTmpFX ); 1103 cG0 = MAP( aCol0.GetGreen(), aCol1.GetGreen(), nTmpFX ); 1104 cB0 = MAP( aCol0.GetBlue(), aCol1.GetBlue(), nTmpFX ); 1105 1106 aCol1 = pAcc->GetPixel( ++nTmpY, nTmpX ); 1107 aCol0 = pAcc->GetPixel( nTmpY--, --nTmpX ); 1108 cR1 = MAP( aCol0.GetRed(), aCol1.GetRed(), nTmpFX ); 1109 cG1 = MAP( aCol0.GetGreen(), aCol1.GetGreen(), nTmpFX ); 1110 cB1 = MAP( aCol0.GetBlue(), aCol1.GetBlue(), nTmpFX ); 1111 1112 aColRes.SetRed( MAP( cR0, cR1, nTmpFY ) ); 1113 aColRes.SetGreen( MAP( cG0, cG1, nTmpFY ) ); 1114 aColRes.SetBlue( MAP( cB0, cB1, nTmpFY ) ); 1115 pWAcc->SetPixel( nYDst, nXDst++, aColRes ); 1116 } 1117 } 1118 } 1119 } 1120 1121 aOutBmp.ReleaseAccess( pWAcc ); 1122 bRet = sal_True; 1123 } 1124 1125 aBmp.ReleaseAccess( pAcc ); 1126 } 1127 1128 if( bRet && rBmpEx.IsTransparent() ) 1129 { 1130 bRet = sal_False; 1131 1132 if( rBmpEx.IsAlpha() ) 1133 { 1134 DBG_ASSERT( rBmpEx.GetAlpha().GetSizePixel() == rBmpEx.GetSizePixel(), 1135 "GraphicManager::ImplCreateScaled(): alpha mask size inconsistent" ); 1136 1137 AlphaMask aAlpha( rBmpEx.GetAlpha() ); 1138 AlphaMask aOutAlpha; 1139 1140 pAcc = aAlpha.AcquireReadAccess(); 1141 1142 if( pAcc ) 1143 { 1144 aOutAlpha = AlphaMask( Size( nDstW, nDstH ) ); 1145 pWAcc = aOutAlpha.AcquireWriteAccess(); 1146 1147 if( pWAcc ) 1148 { 1149 if( pAcc->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL && 1150 pWAcc->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL ) 1151 { 1152 Scanline pLine0, pLine1, pLineW; 1153 1154 for( nY = nStartY, nYDst = 0L; nY <= nEndY; nY++, nYDst++ ) 1155 { 1156 nTmpY = pMapIY[ nY ]; nTmpFY = pMapFY[ nY ]; 1157 pLine0 = pAcc->GetScanline( nTmpY ); 1158 pLine1 = pAcc->GetScanline( ++nTmpY ); 1159 pLineW = pWAcc->GetScanline( nYDst ); 1160 1161 for( nX = nStartX, nXDst = 0L; nX <= nEndX; nX++, nXDst++ ) 1162 { 1163 nTmpX = pMapIX[ nX ]; nTmpFX = pMapFX[ nX ]; 1164 1165 const long nAlpha0 = pLine0[ nTmpX ]; 1166 const long nAlpha2 = pLine1[ nTmpX ]; 1167 const long nAlpha1 = pLine0[ ++nTmpX ]; 1168 const long nAlpha3 = pLine1[ nTmpX ]; 1169 const long n0 = MAP( nAlpha0, nAlpha1, nTmpFX ); 1170 const long n1 = MAP( nAlpha2, nAlpha3, nTmpFX ); 1171 1172 *pLineW++ = MAP( n0, n1, nTmpFY ); 1173 } 1174 } 1175 } 1176 else 1177 { 1178 BitmapColor aAlphaValue( 0 ); 1179 1180 for( nY = nStartY, nYDst = 0L; nY <= nEndY; nY++, nYDst++ ) 1181 { 1182 nTmpY = pMapIY[ nY ], nTmpFY = pMapFY[ nY ]; 1183 1184 for( nX = nStartX, nXDst = 0L; nX <= nEndX; nX++ ) 1185 { 1186 nTmpX = pMapIX[ nX ]; nTmpFX = pMapFX[ nX ]; 1187 1188 long nAlpha0 = pAcc->GetPixel( nTmpY, nTmpX ).GetIndex(); 1189 long nAlpha1 = pAcc->GetPixel( nTmpY, ++nTmpX ).GetIndex(); 1190 const long n0 = MAP( nAlpha0, nAlpha1, nTmpFX ); 1191 1192 nAlpha1 = pAcc->GetPixel( ++nTmpY, nTmpX ).GetIndex(); 1193 nAlpha0 = pAcc->GetPixel( nTmpY--, --nTmpX ).GetIndex(); 1194 const long n1 = MAP( nAlpha0, nAlpha1, nTmpFX ); 1195 1196 aAlphaValue.SetIndex( MAP( n0, n1, nTmpFY ) ); 1197 pWAcc->SetPixel( nYDst, nXDst++, aAlphaValue ); 1198 } 1199 } 1200 } 1201 1202 aOutAlpha.ReleaseAccess( pWAcc ); 1203 bRet = sal_True; 1204 } 1205 1206 aAlpha.ReleaseAccess( pAcc ); 1207 1208 if( bRet ) 1209 rOutBmpEx = BitmapEx( aOutBmp, aOutAlpha ); 1210 } 1211 } 1212 else 1213 { 1214 DBG_ASSERT( rBmpEx.GetMask().GetSizePixel() == rBmpEx.GetSizePixel(), 1215 "GraphicManager::ImplCreateScaled(): mask size inconsistent" ); 1216 1217 Bitmap aMsk( rBmpEx.GetMask() ); 1218 Bitmap aOutMsk; 1219 1220 pAcc = aMsk.AcquireReadAccess(); 1221 1222 if( pAcc ) 1223 { 1224 // #i40115# Use the same palette for destination 1225 // bitmap. Otherwise, we'd have to color-map even the 1226 // case below, when both masks are one bit deep. 1227 if( pAcc->HasPalette() ) 1228 aOutMsk = Bitmap( Size( nDstW, nDstH ), 1229 1, 1230 &pAcc->GetPalette() ); 1231 else 1232 aOutMsk = Bitmap( Size( nDstW, nDstH ), 1 ); 1233 1234 pWAcc = aOutMsk.AcquireWriteAccess(); 1235 1236 if( pWAcc ) 1237 { 1238 long* pMapLX = new long[ nDstW ]; 1239 long* pMapLY = new long[ nDstH ]; 1240 1241 // create new horizontal mapping table 1242 for( nX = 0UL, nTmpX = nStartX; nX < nDstW; nTmpX++ ) 1243 pMapLX[ nX++ ] = FRound( (double) pMapIX[ nTmpX ] + pMapFX[ nTmpX ] / 1048576. ); 1244 1245 // create new vertical mapping table 1246 for( nY = 0UL, nTmpY = nStartY; nY < nDstH; nTmpY++ ) 1247 pMapLY[ nY++ ] = FRound( (double) pMapIY[ nTmpY ] + pMapFY[ nTmpY ] / 1048576. ); 1248 1249 // do normal scaling 1250 if( pAcc->GetScanlineFormat() == BMP_FORMAT_1BIT_MSB_PAL && 1251 pWAcc->GetScanlineFormat() == BMP_FORMAT_1BIT_MSB_PAL ) 1252 { 1253 // optimized 1254 for( nY = 0; nY < nDstH; nY++ ) 1255 { 1256 Scanline pSrc = pAcc->GetScanline( pMapLY[ nY ] ); 1257 Scanline pDst = pWAcc->GetScanline( nY ); 1258 1259 for( nX = 0L; nX < nDstW; nX++ ) 1260 { 1261 const long nSrcX = pMapLX[ nX ]; 1262 1263 if( pSrc[ nSrcX >> 3 ] & ( 1 << ( 7 - ( nSrcX & 7 ) ) ) ) 1264 pDst[ nX >> 3 ] |= 1 << ( 7 - ( nX & 7 ) ); 1265 else 1266 pDst[ nX >> 3 ] &= ~( 1 << ( 7 - ( nX & 7 ) ) ); 1267 } 1268 } 1269 } 1270 else 1271 { 1272 const BitmapColor aB( pAcc->GetBestMatchingColor( Color( COL_BLACK ) ) ); 1273 const BitmapColor aWB( pWAcc->GetBestMatchingColor( Color( COL_BLACK ) ) ); 1274 const BitmapColor aWW( pWAcc->GetBestMatchingColor( Color( COL_WHITE ) ) ); 1275 1276 if( pAcc->HasPalette() ) 1277 { 1278 for( nY = 0L; nY < nDstH; nY++ ) 1279 { 1280 for( nX = 0L; nX < nDstW; nX++ ) 1281 { 1282 if( pAcc->GetPaletteColor( (sal_uInt8) pAcc->GetPixel( pMapLY[ nY ], pMapLX[ nX ] ) ) == aB ) 1283 pWAcc->SetPixel( nY, nX, aWB ); 1284 else 1285 pWAcc->SetPixel( nY, nX, aWW ); 1286 } 1287 } 1288 } 1289 else 1290 { 1291 for( nY = 0L; nY < nDstH; nY++ ) 1292 { 1293 for( nX = 0L; nX < nDstW; nX++ ) 1294 { 1295 if( pAcc->GetPixel( pMapLY[ nY ], pMapLX[ nX ] ) == aB ) 1296 pWAcc->SetPixel( nY, nX, aWB ); 1297 else 1298 pWAcc->SetPixel( nY, nX, aWW ); 1299 } 1300 } 1301 } 1302 } 1303 1304 delete[] pMapLX; 1305 delete[] pMapLY; 1306 aOutMsk.ReleaseAccess( pWAcc ); 1307 bRet = sal_True; 1308 } 1309 1310 aMsk.ReleaseAccess( pAcc ); 1311 1312 if( bRet ) 1313 rOutBmpEx = BitmapEx( aOutBmp, aOutMsk ); 1314 } 1315 } 1316 1317 if( !bRet ) 1318 rOutBmpEx = aOutBmp; 1319 } 1320 else 1321 rOutBmpEx = aOutBmp; 1322 1323 return bRet; 1324 } 1325 1326 // ----------------------------------------------------------------------------- 1327 1328 sal_Bool GraphicManager::ImplCreateRotatedScaled( const BitmapEx& rBmpEx, 1329 sal_uInt16 nRot10, const Size& /*rOutSzPix*/, const Size& rUnrotatedSzPix, 1330 long* pMapIX, long* pMapFX, long* pMapIY, long* pMapFY, 1331 long nStartX, long nEndX, long nStartY, long nEndY, 1332 BitmapEx& rOutBmpEx ) 1333 { 1334 Point aPt; 1335 Bitmap aBmp( rBmpEx.GetBitmap() ); 1336 Bitmap aOutBmp; 1337 BitmapReadAccess* pAcc = aBmp.AcquireReadAccess(); 1338 BitmapWriteAccess* pWAcc; 1339 Polygon aPoly( Rectangle( aPt, rUnrotatedSzPix ) ); aPoly.Rotate( Point(), nRot10 ); 1340 Rectangle aNewBound( aPoly.GetBoundRect() ); 1341 const double fCosAngle = cos( nRot10 * F_PI1800 ), fSinAngle = sin( nRot10 * F_PI1800 ); 1342 double fTmp; 1343 const long nDstW = nEndX - nStartX + 1L; 1344 const long nDstH = nEndY - nStartY + 1L; 1345 const long nUnRotW = rUnrotatedSzPix.Width(); 1346 const long nUnRotH = rUnrotatedSzPix.Height(); 1347 long* pCosX = new long[ nDstW ]; 1348 long* pSinX = new long[ nDstW ]; 1349 long* pCosY = new long[ nDstH ]; 1350 long* pSinY = new long[ nDstH ]; 1351 long nX, nY, nTmpX, nTmpY, nTmpFX, nTmpFY, nUnRotX, nUnRotY, nSinY, nCosY; 1352 sal_uInt8 cR0, cG0, cB0, cR1, cG1, cB1; 1353 sal_Bool bRet = sal_False; 1354 1355 // create horizontal mapping table 1356 for( nX = 0L, nTmpX = aNewBound.Left() + nStartX; nX < nDstW; nX++ ) 1357 { 1358 pCosX[ nX ] = FRound( fCosAngle * ( fTmp = nTmpX++ << 8 ) ); 1359 pSinX[ nX ] = FRound( fSinAngle * fTmp ); 1360 } 1361 1362 // create vertical mapping table 1363 for( nY = 0L, nTmpY = aNewBound.Top() + nStartY; nY < nDstH; nY++ ) 1364 { 1365 pCosY[ nY ] = FRound( fCosAngle * ( fTmp = nTmpY++ << 8 ) ); 1366 pSinY[ nY ] = FRound( fSinAngle * fTmp ); 1367 } 1368 1369 if( pAcc ) 1370 { 1371 aOutBmp = Bitmap( Size( nDstW, nDstH ), 24 ); 1372 pWAcc = aOutBmp.AcquireWriteAccess(); 1373 1374 if( pWAcc ) 1375 { 1376 BitmapColor aColRes; 1377 1378 if( pAcc->HasPalette() ) 1379 { 1380 for( nY = 0; nY < nDstH; nY++ ) 1381 { 1382 nSinY = pSinY[ nY ]; 1383 nCosY = pCosY[ nY ]; 1384 1385 for( nX = 0; nX < nDstW; nX++ ) 1386 { 1387 nUnRotX = ( pCosX[ nX ] - nSinY ) >> 8; 1388 nUnRotY = ( pSinX[ nX ] + nCosY ) >> 8; 1389 1390 if( ( nUnRotX >= 0L ) && ( nUnRotX < nUnRotW ) && 1391 ( nUnRotY >= 0L ) && ( nUnRotY < nUnRotH ) ) 1392 { 1393 nTmpX = pMapIX[ nUnRotX ]; nTmpFX = pMapFX[ nUnRotX ]; 1394 nTmpY = pMapIY[ nUnRotY ], nTmpFY = pMapFY[ nUnRotY ]; 1395 1396 const BitmapColor& rCol0 = pAcc->GetPaletteColor( pAcc->GetPixel( nTmpY, nTmpX ) ); 1397 const BitmapColor& rCol1 = pAcc->GetPaletteColor( pAcc->GetPixel( nTmpY, ++nTmpX ) ); 1398 cR0 = MAP( rCol0.GetRed(), rCol1.GetRed(), nTmpFX ); 1399 cG0 = MAP( rCol0.GetGreen(), rCol1.GetGreen(), nTmpFX ); 1400 cB0 = MAP( rCol0.GetBlue(), rCol1.GetBlue(), nTmpFX ); 1401 1402 const BitmapColor& rCol3 = pAcc->GetPaletteColor( pAcc->GetPixel( ++nTmpY, nTmpX ) ); 1403 const BitmapColor& rCol2 = pAcc->GetPaletteColor( pAcc->GetPixel( nTmpY, --nTmpX ) ); 1404 cR1 = MAP( rCol2.GetRed(), rCol3.GetRed(), nTmpFX ); 1405 cG1 = MAP( rCol2.GetGreen(), rCol3.GetGreen(), nTmpFX ); 1406 cB1 = MAP( rCol2.GetBlue(), rCol3.GetBlue(), nTmpFX ); 1407 1408 aColRes.SetRed( MAP( cR0, cR1, nTmpFY ) ); 1409 aColRes.SetGreen( MAP( cG0, cG1, nTmpFY ) ); 1410 aColRes.SetBlue( MAP( cB0, cB1, nTmpFY ) ); 1411 pWAcc->SetPixel( nY, nX, aColRes ); 1412 } 1413 } 1414 } 1415 } 1416 else 1417 { 1418 BitmapColor aCol0, aCol1; 1419 1420 for( nY = 0; nY < nDstH; nY++ ) 1421 { 1422 nSinY = pSinY[ nY ]; 1423 nCosY = pCosY[ nY ]; 1424 1425 for( nX = 0; nX < nDstW; nX++ ) 1426 { 1427 nUnRotX = ( pCosX[ nX ] - nSinY ) >> 8; 1428 nUnRotY = ( pSinX[ nX ] + nCosY ) >> 8; 1429 1430 if( ( nUnRotX >= 0L ) && ( nUnRotX < nUnRotW ) && 1431 ( nUnRotY >= 0L ) && ( nUnRotY < nUnRotH ) ) 1432 { 1433 nTmpX = pMapIX[ nUnRotX ]; nTmpFX = pMapFX[ nUnRotX ]; 1434 nTmpY = pMapIY[ nUnRotY ], nTmpFY = pMapFY[ nUnRotY ]; 1435 1436 aCol0 = pAcc->GetPixel( nTmpY, nTmpX ); 1437 aCol1 = pAcc->GetPixel( nTmpY, ++nTmpX ); 1438 cR0 = MAP( aCol0.GetRed(), aCol1.GetRed(), nTmpFX ); 1439 cG0 = MAP( aCol0.GetGreen(), aCol1.GetGreen(), nTmpFX ); 1440 cB0 = MAP( aCol0.GetBlue(), aCol1.GetBlue(), nTmpFX ); 1441 1442 aCol1 = pAcc->GetPixel( ++nTmpY, nTmpX ); 1443 aCol0 = pAcc->GetPixel( nTmpY, --nTmpX ); 1444 cR1 = MAP( aCol0.GetRed(), aCol1.GetRed(), nTmpFX ); 1445 cG1 = MAP( aCol0.GetGreen(), aCol1.GetGreen(), nTmpFX ); 1446 cB1 = MAP( aCol0.GetBlue(), aCol1.GetBlue(), nTmpFX ); 1447 1448 aColRes.SetRed( MAP( cR0, cR1, nTmpFY ) ); 1449 aColRes.SetGreen( MAP( cG0, cG1, nTmpFY ) ); 1450 aColRes.SetBlue( MAP( cB0, cB1, nTmpFY ) ); 1451 pWAcc->SetPixel( nY, nX, aColRes ); 1452 } 1453 } 1454 } 1455 } 1456 1457 aOutBmp.ReleaseAccess( pWAcc ); 1458 bRet = sal_True; 1459 } 1460 1461 aBmp.ReleaseAccess( pAcc ); 1462 } 1463 1464 // mask processing 1465 if( bRet && ( rBmpEx.IsTransparent() || ( nRot10 != 900 && nRot10 != 1800 && nRot10 != 2700 ) ) ) 1466 { 1467 bRet = sal_False; 1468 1469 if( rBmpEx.IsAlpha() ) 1470 { 1471 AlphaMask aAlpha( rBmpEx.GetAlpha() ); 1472 AlphaMask aOutAlpha; 1473 1474 pAcc = aAlpha.AcquireReadAccess(); 1475 1476 if( pAcc ) 1477 { 1478 aOutAlpha = AlphaMask( Size( nDstW, nDstH ) ); 1479 pWAcc = aOutAlpha.AcquireWriteAccess(); 1480 1481 if( pWAcc ) 1482 { 1483 if( pAcc->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL && 1484 pWAcc->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL ) 1485 { 1486 Scanline pLine0, pLine1, pLineW; 1487 1488 for( nY = 0; nY < nDstH; nY++ ) 1489 { 1490 nSinY = pSinY[ nY ], nCosY = pCosY[ nY ]; 1491 pLineW = pWAcc->GetScanline( nY ); 1492 1493 for( nX = 0; nX < nDstW; nX++ ) 1494 { 1495 nUnRotX = ( pCosX[ nX ] - nSinY ) >> 8; 1496 nUnRotY = ( pSinX[ nX ] + nCosY ) >> 8; 1497 1498 if( ( nUnRotX >= 0L ) && ( nUnRotX < nUnRotW ) && 1499 ( nUnRotY >= 0L ) && ( nUnRotY < nUnRotH ) ) 1500 { 1501 nTmpX = pMapIX[ nUnRotX ], nTmpFX = pMapFX[ nUnRotX ]; 1502 nTmpY = pMapIY[ nUnRotY ], nTmpFY = pMapFY[ nUnRotY ]; 1503 1504 pLine0 = pAcc->GetScanline( nTmpY++ ); 1505 pLine1 = pAcc->GetScanline( nTmpY ); 1506 1507 const long nAlpha0 = pLine0[ nTmpX ]; 1508 const long nAlpha2 = pLine1[ nTmpX++ ]; 1509 const long nAlpha1 = pLine0[ nTmpX ]; 1510 const long nAlpha3 = pLine1[ nTmpX ]; 1511 const long n0 = MAP( nAlpha0, nAlpha1, nTmpFX ); 1512 const long n1 = MAP( nAlpha2, nAlpha3, nTmpFX ); 1513 1514 *pLineW++ = MAP( n0, n1, nTmpFY ); 1515 } 1516 else 1517 *pLineW++ = 255; 1518 } 1519 } 1520 } 1521 else 1522 { 1523 const BitmapColor aTrans( pWAcc->GetBestMatchingColor( Color( COL_WHITE ) ) ); 1524 BitmapColor aAlphaVal( 0 ); 1525 1526 for( nY = 0; nY < nDstH; nY++ ) 1527 { 1528 nSinY = pSinY[ nY ], nCosY = pCosY[ nY ]; 1529 1530 for( nX = 0; nX < nDstW; nX++ ) 1531 { 1532 nUnRotX = ( pCosX[ nX ] - nSinY ) >> 8; 1533 nUnRotY = ( pSinX[ nX ] + nCosY ) >> 8; 1534 1535 if( ( nUnRotX >= 0L ) && ( nUnRotX < nUnRotW ) && 1536 ( nUnRotY >= 0L ) && ( nUnRotY < nUnRotH ) ) 1537 { 1538 nTmpX = pMapIX[ nUnRotX ]; nTmpFX = pMapFX[ nUnRotX ]; 1539 nTmpY = pMapIY[ nUnRotY ], nTmpFY = pMapFY[ nUnRotY ]; 1540 1541 const long nAlpha0 = pAcc->GetPixel( nTmpY, nTmpX ).GetIndex(); 1542 const long nAlpha1 = pAcc->GetPixel( nTmpY, ++nTmpX ).GetIndex(); 1543 const long nAlpha3 = pAcc->GetPixel( ++nTmpY, nTmpX ).GetIndex(); 1544 const long nAlpha2 = pAcc->GetPixel( nTmpY, --nTmpX ).GetIndex(); 1545 const long n0 = MAP( nAlpha0, nAlpha1, nTmpFX ); 1546 const long n1 = MAP( nAlpha2, nAlpha3, nTmpFX ); 1547 1548 aAlphaVal.SetIndex( MAP( n0, n1, nTmpFY ) ); 1549 pWAcc->SetPixel( nY, nX, aAlphaVal ); 1550 } 1551 else 1552 pWAcc->SetPixel( nY, nX, aTrans ); 1553 } 1554 } 1555 } 1556 1557 aOutAlpha.ReleaseAccess( pWAcc ); 1558 bRet = sal_True; 1559 } 1560 1561 aAlpha.ReleaseAccess( pAcc ); 1562 } 1563 1564 if( bRet ) 1565 rOutBmpEx = BitmapEx( aOutBmp, aOutAlpha ); 1566 } 1567 else 1568 { 1569 Bitmap aOutMsk( Size( nDstW, nDstH ), 1 ); 1570 pWAcc = aOutMsk.AcquireWriteAccess(); 1571 1572 if( pWAcc ) 1573 { 1574 Bitmap aMsk( rBmpEx.GetMask() ); 1575 const BitmapColor aB( pWAcc->GetBestMatchingColor( Color( COL_BLACK ) ) ); 1576 const BitmapColor aW( pWAcc->GetBestMatchingColor( Color( COL_WHITE ) ) ); 1577 BitmapReadAccess* pMAcc = NULL; 1578 1579 if( !aMsk || ( ( pMAcc = aMsk.AcquireReadAccess() ) != NULL ) ) 1580 { 1581 long* pMapLX = new long[ nUnRotW ]; 1582 long* pMapLY = new long[ nUnRotH ]; 1583 BitmapColor aTestB; 1584 1585 if( pMAcc ) 1586 aTestB = pMAcc->GetBestMatchingColor( Color( COL_BLACK ) ); 1587 1588 // create new horizontal mapping table 1589 for( nX = 0UL; nX < nUnRotW; nX++ ) 1590 pMapLX[ nX ] = FRound( (double) pMapIX[ nX ] + pMapFX[ nX ] / 1048576. ); 1591 1592 // create new vertical mapping table 1593 for( nY = 0UL; nY < nUnRotH; nY++ ) 1594 pMapLY[ nY ] = FRound( (double) pMapIY[ nY ] + pMapFY[ nY ] / 1048576. ); 1595 1596 // do mask rotation 1597 for( nY = 0; nY < nDstH; nY++ ) 1598 { 1599 nSinY = pSinY[ nY ]; 1600 nCosY = pCosY[ nY ]; 1601 1602 for( nX = 0; nX < nDstW; nX++ ) 1603 { 1604 nUnRotX = ( pCosX[ nX ] - nSinY ) >> 8; 1605 nUnRotY = ( pSinX[ nX ] + nCosY ) >> 8; 1606 1607 if( ( nUnRotX >= 0L ) && ( nUnRotX < nUnRotW ) && 1608 ( nUnRotY >= 0L ) && ( nUnRotY < nUnRotH ) ) 1609 { 1610 if( pMAcc ) 1611 { 1612 if( pMAcc->GetPixel( pMapLY[ nUnRotY ], pMapLX[ nUnRotX ] ) == aTestB ) 1613 pWAcc->SetPixel( nY, nX, aB ); 1614 else 1615 pWAcc->SetPixel( nY, nX, aW ); 1616 } 1617 else 1618 pWAcc->SetPixel( nY, nX, aB ); 1619 } 1620 else 1621 pWAcc->SetPixel( nY, nX, aW ); 1622 } 1623 } 1624 1625 delete[] pMapLX; 1626 delete[] pMapLY; 1627 1628 if( pMAcc ) 1629 aMsk.ReleaseAccess( pMAcc ); 1630 1631 bRet = sal_True; 1632 } 1633 1634 aOutMsk.ReleaseAccess( pWAcc ); 1635 } 1636 1637 if( bRet ) 1638 rOutBmpEx = BitmapEx( aOutBmp, aOutMsk ); 1639 } 1640 1641 if( !bRet ) 1642 rOutBmpEx = aOutBmp; 1643 } 1644 else 1645 rOutBmpEx = aOutBmp; 1646 1647 delete[] pSinX; 1648 delete[] pCosX; 1649 delete[] pSinY; 1650 delete[] pCosY; 1651 1652 return bRet; 1653 } 1654 1655 // ----------------------------------------------------------------------------- 1656 1657 void GraphicManager::ImplAdjust( BitmapEx& rBmpEx, const GraphicAttr& rAttr, sal_uLong nAdjustmentFlags ) 1658 { 1659 GraphicAttr aAttr( rAttr ); 1660 1661 if( ( nAdjustmentFlags & ADJUSTMENT_DRAWMODE ) && aAttr.IsSpecialDrawMode() ) 1662 { 1663 switch( aAttr.GetDrawMode() ) 1664 { 1665 case( GRAPHICDRAWMODE_MONO ): 1666 rBmpEx.Convert( BMP_CONVERSION_1BIT_THRESHOLD ); 1667 break; 1668 1669 case( GRAPHICDRAWMODE_GREYS ): 1670 rBmpEx.Convert( BMP_CONVERSION_8BIT_GREYS ); 1671 break; 1672 1673 case( GRAPHICDRAWMODE_WATERMARK ): 1674 { 1675 aAttr.SetLuminance( aAttr.GetLuminance() + WATERMARK_LUM_OFFSET ); 1676 aAttr.SetContrast( aAttr.GetContrast() + WATERMARK_CON_OFFSET ); 1677 } 1678 break; 1679 1680 default: 1681 break; 1682 } 1683 } 1684 1685 if( ( nAdjustmentFlags & ADJUSTMENT_COLORS ) && aAttr.IsAdjusted() ) 1686 { 1687 rBmpEx.Adjust( aAttr.GetLuminance(), aAttr.GetContrast(), 1688 aAttr.GetChannelR(), aAttr.GetChannelG(), aAttr.GetChannelB(), 1689 aAttr.GetGamma(), aAttr.IsInvert() ); 1690 } 1691 1692 if( ( nAdjustmentFlags & ADJUSTMENT_MIRROR ) && aAttr.IsMirrored() ) 1693 { 1694 rBmpEx.Mirror( aAttr.GetMirrorFlags() ); 1695 } 1696 1697 if( ( nAdjustmentFlags & ADJUSTMENT_ROTATE ) && aAttr.IsRotated() ) 1698 { 1699 rBmpEx.Rotate( aAttr.GetRotation(), Color( COL_TRANSPARENT ) ); 1700 } 1701 1702 if( ( nAdjustmentFlags & ADJUSTMENT_TRANSPARENCY ) && aAttr.IsTransparent() ) 1703 { 1704 AlphaMask aAlpha; 1705 sal_uInt8 cTrans = aAttr.GetTransparency(); 1706 1707 if( !rBmpEx.IsTransparent() ) 1708 aAlpha = AlphaMask( rBmpEx.GetSizePixel(), &cTrans ); 1709 else if( !rBmpEx.IsAlpha() ) 1710 { 1711 aAlpha = rBmpEx.GetMask(); 1712 aAlpha.Replace( 0, cTrans ); 1713 } 1714 else 1715 { 1716 aAlpha = rBmpEx.GetAlpha(); 1717 BitmapWriteAccess* pA = aAlpha.AcquireWriteAccess(); 1718 1719 if( pA ) 1720 { 1721 sal_uLong nTrans = cTrans, nNewTrans; 1722 const long nWidth = pA->Width(), nHeight = pA->Height(); 1723 1724 if( pA->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL ) 1725 { 1726 for( long nY = 0; nY < nHeight; nY++ ) 1727 { 1728 Scanline pAScan = pA->GetScanline( nY ); 1729 1730 for( long nX = 0; nX < nWidth; nX++ ) 1731 { 1732 nNewTrans = nTrans + *pAScan; 1733 *pAScan++ = (sal_uInt8) ( ( nNewTrans & 0xffffff00 ) ? 255 : nNewTrans ); 1734 } 1735 } 1736 } 1737 else 1738 { 1739 BitmapColor aAlphaValue( 0 ); 1740 1741 for( long nY = 0; nY < nHeight; nY++ ) 1742 { 1743 for( long nX = 0; nX < nWidth; nX++ ) 1744 { 1745 nNewTrans = nTrans + pA->GetPixel( nY, nX ).GetIndex(); 1746 aAlphaValue.SetIndex( (sal_uInt8) ( ( nNewTrans & 0xffffff00 ) ? 255 : nNewTrans ) ); 1747 pA->SetPixel( nY, nX, aAlphaValue ); 1748 } 1749 } 1750 } 1751 1752 aAlpha.ReleaseAccess( pA ); 1753 } 1754 } 1755 1756 rBmpEx = BitmapEx( rBmpEx.GetBitmap(), aAlpha ); 1757 } 1758 } 1759 1760 // ----------------------------------------------------------------------------- 1761 1762 void GraphicManager::ImplAdjust( GDIMetaFile& rMtf, const GraphicAttr& rAttr, sal_uLong nAdjustmentFlags ) 1763 { 1764 GraphicAttr aAttr( rAttr ); 1765 1766 if( ( nAdjustmentFlags & ADJUSTMENT_DRAWMODE ) && aAttr.IsSpecialDrawMode() ) 1767 { 1768 switch( aAttr.GetDrawMode() ) 1769 { 1770 case( GRAPHICDRAWMODE_MONO ): 1771 rMtf.Convert( MTF_CONVERSION_1BIT_THRESHOLD ); 1772 break; 1773 1774 case( GRAPHICDRAWMODE_GREYS ): 1775 rMtf.Convert( MTF_CONVERSION_8BIT_GREYS ); 1776 break; 1777 1778 case( GRAPHICDRAWMODE_WATERMARK ): 1779 { 1780 aAttr.SetLuminance( aAttr.GetLuminance() + WATERMARK_LUM_OFFSET ); 1781 aAttr.SetContrast( aAttr.GetContrast() + WATERMARK_CON_OFFSET ); 1782 } 1783 break; 1784 1785 default: 1786 break; 1787 } 1788 } 1789 1790 if( ( nAdjustmentFlags & ADJUSTMENT_COLORS ) && aAttr.IsAdjusted() ) 1791 { 1792 rMtf.Adjust( aAttr.GetLuminance(), aAttr.GetContrast(), 1793 aAttr.GetChannelR(), aAttr.GetChannelG(), aAttr.GetChannelB(), 1794 aAttr.GetGamma(), aAttr.IsInvert() ); 1795 } 1796 1797 if( ( nAdjustmentFlags & ADJUSTMENT_MIRROR ) && aAttr.IsMirrored() ) 1798 { 1799 rMtf.Mirror( aAttr.GetMirrorFlags() ); 1800 } 1801 1802 if( ( nAdjustmentFlags & ADJUSTMENT_ROTATE ) && aAttr.IsRotated() ) 1803 { 1804 rMtf.Rotate( aAttr.GetRotation() ); 1805 } 1806 1807 if( ( nAdjustmentFlags & ADJUSTMENT_TRANSPARENCY ) && aAttr.IsTransparent() ) 1808 { 1809 DBG_WARNING( "Missing implementation: Mtf-Transparency" ); 1810 } 1811 } 1812 1813 // ----------------------------------------------------------------------------- 1814 1815 void GraphicManager::ImplAdjust( Animation& rAnimation, const GraphicAttr& rAttr, sal_uLong nAdjustmentFlags ) 1816 { 1817 GraphicAttr aAttr( rAttr ); 1818 1819 if( ( nAdjustmentFlags & ADJUSTMENT_DRAWMODE ) && aAttr.IsSpecialDrawMode() ) 1820 { 1821 switch( aAttr.GetDrawMode() ) 1822 { 1823 case( GRAPHICDRAWMODE_MONO ): 1824 rAnimation.Convert( BMP_CONVERSION_1BIT_THRESHOLD ); 1825 break; 1826 1827 case( GRAPHICDRAWMODE_GREYS ): 1828 rAnimation.Convert( BMP_CONVERSION_8BIT_GREYS ); 1829 break; 1830 1831 case( GRAPHICDRAWMODE_WATERMARK ): 1832 { 1833 aAttr.SetLuminance( aAttr.GetLuminance() + WATERMARK_LUM_OFFSET ); 1834 aAttr.SetContrast( aAttr.GetContrast() + WATERMARK_CON_OFFSET ); 1835 } 1836 break; 1837 1838 default: 1839 break; 1840 } 1841 } 1842 1843 if( ( nAdjustmentFlags & ADJUSTMENT_COLORS ) && aAttr.IsAdjusted() ) 1844 { 1845 rAnimation.Adjust( aAttr.GetLuminance(), aAttr.GetContrast(), 1846 aAttr.GetChannelR(), aAttr.GetChannelG(), aAttr.GetChannelB(), 1847 aAttr.GetGamma(), aAttr.IsInvert() ); 1848 } 1849 1850 if( ( nAdjustmentFlags & ADJUSTMENT_MIRROR ) && aAttr.IsMirrored() ) 1851 { 1852 rAnimation.Mirror( aAttr.GetMirrorFlags() ); 1853 } 1854 1855 if( ( nAdjustmentFlags & ADJUSTMENT_ROTATE ) && aAttr.IsRotated() ) 1856 { 1857 DBG_ERROR( "Missing implementation: Animation-Rotation" ); 1858 } 1859 1860 if( ( nAdjustmentFlags & ADJUSTMENT_TRANSPARENCY ) && aAttr.IsTransparent() ) 1861 { 1862 DBG_ERROR( "Missing implementation: Animation-Transparency" ); 1863 } 1864 } 1865 1866 // ----------------------------------------------------------------------------- 1867 1868 void GraphicManager::ImplDraw( OutputDevice* pOut, const Point& rPt, const Size& rSz, 1869 const GDIMetaFile& rMtf, const GraphicAttr& rAttr ) 1870 { 1871 sal_uInt16 nRot10 = rAttr.GetRotation() % 3600; 1872 Point aOutPt( rPt ); 1873 Size aOutSz( rSz ); 1874 1875 if( nRot10 ) 1876 { 1877 Polygon aPoly( Rectangle( aOutPt, aOutSz ) ); 1878 1879 aPoly.Rotate( aOutPt, nRot10 ); 1880 const Rectangle aRotBoundRect( aPoly.GetBoundRect() ); 1881 aOutPt = aRotBoundRect.TopLeft(); 1882 aOutSz = aRotBoundRect.GetSize(); 1883 } 1884 1885 pOut->Push( PUSH_CLIPREGION ); 1886 pOut->IntersectClipRegion( Rectangle( aOutPt, aOutSz ) ); 1887 1888 ( (GDIMetaFile&) rMtf ).WindStart(); 1889 ( (GDIMetaFile&) rMtf ).Play( pOut, aOutPt, aOutSz ); 1890 ( (GDIMetaFile&) rMtf ).WindStart(); 1891 1892 pOut->Pop(); 1893 } 1894 1895 // ----------------------------------------------------------------------------- 1896 1897 struct ImplTileInfo 1898 { 1899 ImplTileInfo() : aTileTopLeft(), aNextTileTopLeft(), aTileSizePixel(), nTilesEmptyX(0), nTilesEmptyY(0) {} 1900 1901 Point aTileTopLeft; // top, left position of the rendered tile 1902 Point aNextTileTopLeft; // top, left position for next recursion 1903 // level's tile 1904 Size aTileSizePixel; // size of the generated tile (might 1905 // differ from 1906 // aNextTileTopLeft-aTileTopLeft, because 1907 // this is nExponent*prevTileSize. The 1908 // generated tile is always nExponent 1909 // times the previous tile, such that it 1910 // can be used in the next stage. The 1911 // required area coverage is often 1912 // less. The extraneous area covered is 1913 // later overwritten by the next stage) 1914 int nTilesEmptyX; // number of original tiles empty right of 1915 // this tile. This counts from 1916 // aNextTileTopLeft, i.e. the additional 1917 // area covered by aTileSizePixel is not 1918 // considered here. This is for 1919 // unification purposes, as the iterative 1920 // calculation of the next level's empty 1921 // tiles has to be based on this value. 1922 int nTilesEmptyY; // as above, for Y 1923 }; 1924 1925 1926 bool GraphicObject::ImplRenderTempTile( VirtualDevice& rVDev, int nExponent, 1927 int nNumTilesX, int nNumTilesY, 1928 const Size& rTileSizePixel, 1929 const GraphicAttr* pAttr, sal_uLong nFlags ) 1930 { 1931 if( nExponent <= 1 ) 1932 return false; 1933 1934 // determine MSB factor 1935 int nMSBFactor( 1 ); 1936 while( nNumTilesX / nMSBFactor != 0 || 1937 nNumTilesY / nMSBFactor != 0 ) 1938 { 1939 nMSBFactor *= nExponent; 1940 } 1941 1942 // one less 1943 nMSBFactor /= nExponent; 1944 1945 ImplTileInfo aTileInfo; 1946 1947 // #105229# Switch off mapping (converting to logic and back to 1948 // pixel might cause roundoff errors) 1949 sal_Bool bOldMap( rVDev.IsMapModeEnabled() ); 1950 rVDev.EnableMapMode( sal_False ); 1951 1952 bool bRet( ImplRenderTileRecursive( rVDev, nExponent, nMSBFactor, nNumTilesX, nNumTilesY, 1953 nNumTilesX, nNumTilesY, rTileSizePixel, pAttr, nFlags, aTileInfo ) ); 1954 1955 rVDev.EnableMapMode( bOldMap ); 1956 1957 return bRet; 1958 } 1959 1960 // ----------------------------------------------------------------------------- 1961 1962 // define for debug drawings 1963 //#define DBG_TEST 1964 1965 // see header comment. this works similar to base conversion of a 1966 // number, i.e. if the exponent is 10, then the number for every tile 1967 // size is given by the decimal place of the corresponding decimal 1968 // representation. 1969 bool GraphicObject::ImplRenderTileRecursive( VirtualDevice& rVDev, int nExponent, int nMSBFactor, 1970 int nNumOrigTilesX, int nNumOrigTilesY, 1971 int nRemainderTilesX, int nRemainderTilesY, 1972 const Size& rTileSizePixel, const GraphicAttr* pAttr, 1973 sal_uLong nFlags, ImplTileInfo& rTileInfo ) 1974 { 1975 // gets loaded with our tile bitmap 1976 GraphicObject aTmpGraphic; 1977 1978 // stores a flag that renders the zero'th tile position 1979 // (i.e. (0,0)+rCurrPos) only if we're at the bottom of the 1980 // recursion stack. All other position already have that tile 1981 // rendered, because the lower levels painted their generated tile 1982 // there. 1983 bool bNoFirstTileDraw( false ); 1984 1985 // what's left when we're done with our tile size 1986 const int nNewRemainderX( nRemainderTilesX % nMSBFactor ); 1987 const int nNewRemainderY( nRemainderTilesY % nMSBFactor ); 1988 1989 // gets filled out from the recursive call with info of what's 1990 // been generated 1991 ImplTileInfo aTileInfo; 1992 1993 // current output position while drawing 1994 Point aCurrPos; 1995 int nX, nY; 1996 1997 // check for recursion's end condition: LSB place reached? 1998 if( nMSBFactor == 1 ) 1999 { 2000 aTmpGraphic = *this; 2001 2002 // set initial tile size -> orig size 2003 aTileInfo.aTileSizePixel = rTileSizePixel; 2004 aTileInfo.nTilesEmptyX = nNumOrigTilesX; 2005 aTileInfo.nTilesEmptyY = nNumOrigTilesY; 2006 } 2007 else if( ImplRenderTileRecursive( rVDev, nExponent, nMSBFactor/nExponent, 2008 nNumOrigTilesX, nNumOrigTilesY, 2009 nNewRemainderX, nNewRemainderY, 2010 rTileSizePixel, pAttr, nFlags, aTileInfo ) ) 2011 { 2012 // extract generated tile -> see comment on the first loop below 2013 BitmapEx aTileBitmap( rVDev.GetBitmap( aTileInfo.aTileTopLeft, aTileInfo.aTileSizePixel ) ); 2014 2015 aTmpGraphic = GraphicObject( aTileBitmap ); 2016 2017 // fill stripes left over from upstream levels: 2018 // 2019 // x0000 2020 // 0 2021 // 0 2022 // 0 2023 // 0 2024 // 2025 // where x denotes the place filled by our recursive predecessors 2026 2027 // check whether we have to fill stripes here. Although not 2028 // obvious, there is one case where we can skip this step: if 2029 // the previous recursion level (the one who filled our 2030 // aTileInfo) had zero area to fill, then there are no white 2031 // stripes left, naturally. This happens if the digit 2032 // associated to that level has a zero, and can be checked via 2033 // aTileTopLeft==aNextTileTopLeft. 2034 if( aTileInfo.aTileTopLeft != aTileInfo.aNextTileTopLeft ) 2035 { 2036 // now fill one row from aTileInfo.aNextTileTopLeft.X() all 2037 // the way to the right 2038 aCurrPos.X() = aTileInfo.aNextTileTopLeft.X(); 2039 aCurrPos.Y() = aTileInfo.aTileTopLeft.Y(); 2040 for( nX=0; nX < aTileInfo.nTilesEmptyX; nX += nMSBFactor ) 2041 { 2042 if( !aTmpGraphic.Draw( &rVDev, aCurrPos, aTileInfo.aTileSizePixel, pAttr, nFlags ) ) 2043 return false; 2044 2045 aCurrPos.X() += aTileInfo.aTileSizePixel.Width(); 2046 } 2047 2048 #ifdef DBG_TEST 2049 // rVDev.SetFillColor( COL_WHITE ); 2050 rVDev.SetFillColor(); 2051 rVDev.SetLineColor( Color( 255 * nExponent / nMSBFactor, 255 - 255 * nExponent / nMSBFactor, 128 - 255 * nExponent / nMSBFactor ) ); 2052 rVDev.DrawEllipse( Rectangle(aTileInfo.aNextTileTopLeft.X(), aTileInfo.aTileTopLeft.Y(), 2053 aTileInfo.aNextTileTopLeft.X() - 1 + (aTileInfo.nTilesEmptyX/nMSBFactor)*aTileInfo.aTileSizePixel.Width(), 2054 aTileInfo.aTileTopLeft.Y() + aTileInfo.aTileSizePixel.Height() - 1) ); 2055 #endif 2056 2057 // now fill one column from aTileInfo.aNextTileTopLeft.Y() all 2058 // the way to the bottom 2059 aCurrPos.X() = aTileInfo.aTileTopLeft.X(); 2060 aCurrPos.Y() = aTileInfo.aNextTileTopLeft.Y(); 2061 for( nY=0; nY < aTileInfo.nTilesEmptyY; nY += nMSBFactor ) 2062 { 2063 if( !aTmpGraphic.Draw( &rVDev, aCurrPos, aTileInfo.aTileSizePixel, pAttr, nFlags ) ) 2064 return false; 2065 2066 aCurrPos.Y() += aTileInfo.aTileSizePixel.Height(); 2067 } 2068 2069 #ifdef DBG_TEST 2070 rVDev.DrawEllipse( Rectangle(aTileInfo.aTileTopLeft.X(), aTileInfo.aNextTileTopLeft.Y(), 2071 aTileInfo.aTileTopLeft.X() + aTileInfo.aTileSizePixel.Width() - 1, 2072 aTileInfo.aNextTileTopLeft.Y() - 1 + (aTileInfo.nTilesEmptyY/nMSBFactor)*aTileInfo.aTileSizePixel.Height()) ); 2073 #endif 2074 } 2075 else 2076 { 2077 // Thought that aTileInfo.aNextTileTopLeft tile has always 2078 // been drawn already, but that's wrong: typically, 2079 // _parts_ of that tile have been drawn, since the 2080 // previous level generated the tile there. But when 2081 // aTileInfo.aNextTileTopLeft!=aTileInfo.aTileTopLeft, the 2082 // difference between these two values is missing in the 2083 // lower right corner of this first tile. So, can do that 2084 // only here. 2085 bNoFirstTileDraw = true; 2086 } 2087 } 2088 else 2089 { 2090 return false; 2091 } 2092 2093 // calc number of original tiles in our drawing area without 2094 // remainder 2095 nRemainderTilesX -= nNewRemainderX; 2096 nRemainderTilesY -= nNewRemainderY; 2097 2098 // fill tile info for calling method 2099 rTileInfo.aTileTopLeft = aTileInfo.aNextTileTopLeft; 2100 rTileInfo.aNextTileTopLeft = Point( rTileInfo.aTileTopLeft.X() + rTileSizePixel.Width()*nRemainderTilesX, 2101 rTileInfo.aTileTopLeft.Y() + rTileSizePixel.Height()*nRemainderTilesY ); 2102 rTileInfo.aTileSizePixel = Size( rTileSizePixel.Width()*nMSBFactor*nExponent, 2103 rTileSizePixel.Height()*nMSBFactor*nExponent ); 2104 rTileInfo.nTilesEmptyX = aTileInfo.nTilesEmptyX - nRemainderTilesX; 2105 rTileInfo.nTilesEmptyY = aTileInfo.nTilesEmptyY - nRemainderTilesY; 2106 2107 // init output position 2108 aCurrPos = aTileInfo.aNextTileTopLeft; 2109 2110 // fill our drawing area. Fill possibly more, to create the next 2111 // bigger tile size -> see bitmap extraction above. This does no 2112 // harm, since everything right or below our actual area is 2113 // overdrawn by our caller. Just in case we're in the last level, 2114 // we don't draw beyond the right or bottom border. 2115 for( nY=0; nY < aTileInfo.nTilesEmptyY && nY < nExponent*nMSBFactor; nY += nMSBFactor ) 2116 { 2117 aCurrPos.X() = aTileInfo.aNextTileTopLeft.X(); 2118 2119 for( nX=0; nX < aTileInfo.nTilesEmptyX && nX < nExponent*nMSBFactor; nX += nMSBFactor ) 2120 { 2121 if( bNoFirstTileDraw ) 2122 bNoFirstTileDraw = false; // don't draw first tile position 2123 else if( !aTmpGraphic.Draw( &rVDev, aCurrPos, aTileInfo.aTileSizePixel, pAttr, nFlags ) ) 2124 return false; 2125 2126 aCurrPos.X() += aTileInfo.aTileSizePixel.Width(); 2127 } 2128 2129 aCurrPos.Y() += aTileInfo.aTileSizePixel.Height(); 2130 } 2131 2132 #ifdef DBG_TEST 2133 // rVDev.SetFillColor( COL_WHITE ); 2134 rVDev.SetFillColor(); 2135 rVDev.SetLineColor( Color( 255 * nExponent / nMSBFactor, 255 - 255 * nExponent / nMSBFactor, 128 - 255 * nExponent / nMSBFactor ) ); 2136 rVDev.DrawRect( Rectangle((rTileInfo.aTileTopLeft.X())*rTileSizePixel.Width(), 2137 (rTileInfo.aTileTopLeft.Y())*rTileSizePixel.Height(), 2138 (rTileInfo.aNextTileTopLeft.X())*rTileSizePixel.Width()-1, 2139 (rTileInfo.aNextTileTopLeft.Y())*rTileSizePixel.Height()-1) ); 2140 #endif 2141 2142 return true; 2143 } 2144 2145 // ----------------------------------------------------------------------------- 2146 2147 bool GraphicObject::ImplDrawTiled( OutputDevice* pOut, const Rectangle& rArea, const Size& rSizePixel, 2148 const Size& rOffset, const GraphicAttr* pAttr, sal_uLong nFlags, int nTileCacheSize1D ) 2149 { 2150 // how many tiles to generate per recursion step 2151 enum{ SubdivisionExponent=2 }; 2152 2153 const MapMode aOutMapMode( pOut->GetMapMode() ); 2154 const MapMode aMapMode( aOutMapMode.GetMapUnit(), Point(), aOutMapMode.GetScaleX(), aOutMapMode.GetScaleY() ); 2155 bool bRet( false ); 2156 2157 // #i42643# Casting to Int64, to avoid integer overflow for 2158 // huge-DPI output devices 2159 if( GetGraphic().GetType() == GRAPHIC_BITMAP && 2160 static_cast<sal_Int64>(rSizePixel.Width()) * rSizePixel.Height() < 2161 static_cast<sal_Int64>(nTileCacheSize1D)*nTileCacheSize1D ) 2162 { 2163 // First combine very small bitmaps into a larger tile 2164 // =================================================== 2165 2166 VirtualDevice aVDev; 2167 const int nNumTilesInCacheX( (nTileCacheSize1D + rSizePixel.Width()-1) / rSizePixel.Width() ); 2168 const int nNumTilesInCacheY( (nTileCacheSize1D + rSizePixel.Height()-1) / rSizePixel.Height() ); 2169 2170 aVDev.SetOutputSizePixel( Size( nNumTilesInCacheX*rSizePixel.Width(), 2171 nNumTilesInCacheY*rSizePixel.Height() ) ); 2172 aVDev.SetMapMode( aMapMode ); 2173 2174 // draw bitmap content 2175 if( ImplRenderTempTile( aVDev, SubdivisionExponent, nNumTilesInCacheX, 2176 nNumTilesInCacheY, rSizePixel, pAttr, nFlags ) ) 2177 { 2178 BitmapEx aTileBitmap( aVDev.GetBitmap( Point(0,0), aVDev.GetOutputSize() ) ); 2179 2180 // draw alpha content, if any 2181 if( IsTransparent() ) 2182 { 2183 GraphicObject aAlphaGraphic; 2184 2185 if( GetGraphic().IsAlpha() ) 2186 aAlphaGraphic.SetGraphic( GetGraphic().GetBitmapEx().GetAlpha().GetBitmap() ); 2187 else 2188 aAlphaGraphic.SetGraphic( GetGraphic().GetBitmapEx().GetMask() ); 2189 2190 if( aAlphaGraphic.ImplRenderTempTile( aVDev, SubdivisionExponent, nNumTilesInCacheX, 2191 nNumTilesInCacheY, rSizePixel, pAttr, nFlags ) ) 2192 { 2193 // Combine bitmap and alpha/mask 2194 if( GetGraphic().IsAlpha() ) 2195 aTileBitmap = BitmapEx( aTileBitmap.GetBitmap(), 2196 AlphaMask( aVDev.GetBitmap( Point(0,0), aVDev.GetOutputSize() ) ) ); 2197 else 2198 aTileBitmap = BitmapEx( aTileBitmap.GetBitmap(), 2199 aVDev.GetBitmap( Point(0,0), aVDev.GetOutputSize() ).CreateMask( Color(COL_WHITE) ) ); 2200 } 2201 } 2202 2203 // paint generated tile 2204 GraphicObject aTmpGraphic( aTileBitmap ); 2205 bRet = aTmpGraphic.ImplDrawTiled( pOut, rArea, 2206 aTileBitmap.GetSizePixel(), 2207 rOffset, pAttr, nFlags, nTileCacheSize1D ); 2208 } 2209 } 2210 else 2211 { 2212 const Size aOutOffset( pOut->LogicToPixel( rOffset, aOutMapMode ) ); 2213 const Rectangle aOutArea( pOut->LogicToPixel( rArea, aOutMapMode ) ); 2214 2215 // number of invisible (because out-of-area) tiles 2216 int nInvisibleTilesX; 2217 int nInvisibleTilesY; 2218 2219 // round towards -infty for negative offset 2220 if( aOutOffset.Width() < 0 ) 2221 nInvisibleTilesX = (aOutOffset.Width() - rSizePixel.Width() + 1) / rSizePixel.Width(); 2222 else 2223 nInvisibleTilesX = aOutOffset.Width() / rSizePixel.Width(); 2224 2225 // round towards -infty for negative offset 2226 if( aOutOffset.Height() < 0 ) 2227 nInvisibleTilesY = (aOutOffset.Height() - rSizePixel.Height() + 1) / rSizePixel.Height(); 2228 else 2229 nInvisibleTilesY = aOutOffset.Height() / rSizePixel.Height(); 2230 2231 // origin from where to 'virtually' start drawing in pixel 2232 const Point aOutOrigin( pOut->LogicToPixel( Point( rArea.Left() - rOffset.Width(), 2233 rArea.Top() - rOffset.Height() ) ) ); 2234 // position in pixel from where to really start output 2235 const Point aOutStart( aOutOrigin.X() + nInvisibleTilesX*rSizePixel.Width(), 2236 aOutOrigin.Y() + nInvisibleTilesY*rSizePixel.Height() ); 2237 2238 pOut->Push( PUSH_CLIPREGION ); 2239 pOut->IntersectClipRegion( rArea ); 2240 2241 // Paint all tiles 2242 // =============== 2243 2244 bRet = ImplDrawTiled( *pOut, aOutStart, 2245 (aOutArea.GetWidth() + aOutArea.Left() - aOutStart.X() + rSizePixel.Width() - 1) / rSizePixel.Width(), 2246 (aOutArea.GetHeight() + aOutArea.Top() - aOutStart.Y() + rSizePixel.Height() - 1) / rSizePixel.Height(), 2247 rSizePixel, pAttr, nFlags ); 2248 2249 pOut->Pop(); 2250 } 2251 2252 return bRet; 2253 } 2254 2255 // ----------------------------------------------------------------------------- 2256 2257 bool GraphicObject::ImplDrawTiled( OutputDevice& rOut, const Point& rPosPixel, 2258 int nNumTilesX, int nNumTilesY, 2259 const Size& rTileSizePixel, const GraphicAttr* pAttr, sal_uLong nFlags ) 2260 { 2261 Point aCurrPos( rPosPixel ); 2262 Size aTileSizeLogic( rOut.PixelToLogic( rTileSizePixel ) ); 2263 int nX, nY; 2264 2265 // #107607# Use logical coordinates for metafile playing, too 2266 bool bDrawInPixel( rOut.GetConnectMetaFile() == NULL && GRAPHIC_BITMAP == GetType() ); 2267 sal_Bool bRet( sal_False ); 2268 2269 // #105229# Switch off mapping (converting to logic and back to 2270 // pixel might cause roundoff errors) 2271 sal_Bool bOldMap( rOut.IsMapModeEnabled() ); 2272 2273 if( bDrawInPixel ) 2274 rOut.EnableMapMode( sal_False ); 2275 2276 for( nY=0; nY < nNumTilesY; ++nY ) 2277 { 2278 aCurrPos.X() = rPosPixel.X(); 2279 2280 for( nX=0; nX < nNumTilesX; ++nX ) 2281 { 2282 // #105229# work with pixel coordinates here, mapping is disabled! 2283 // #104004# don't disable mapping for metafile recordings 2284 // #108412# don't quit the loop if one draw fails 2285 2286 // update return value. This method should return true, if 2287 // at least one of the looped Draws succeeded. 2288 bRet |= Draw( &rOut, 2289 bDrawInPixel ? aCurrPos : rOut.PixelToLogic( aCurrPos ), 2290 bDrawInPixel ? rTileSizePixel : aTileSizeLogic, 2291 pAttr, nFlags ); 2292 2293 aCurrPos.X() += rTileSizePixel.Width(); 2294 } 2295 2296 aCurrPos.Y() += rTileSizePixel.Height(); 2297 } 2298 2299 if( bDrawInPixel ) 2300 rOut.EnableMapMode( bOldMap ); 2301 2302 return bRet; 2303 } 2304 2305 // ----------------------------------------------------------------------------- 2306 2307 void GraphicObject::ImplTransformBitmap( BitmapEx& rBmpEx, 2308 const GraphicAttr& rAttr, 2309 const Size& rCropLeftTop, 2310 const Size& rCropRightBottom, 2311 const Rectangle& rCropRect, 2312 const Size& rDstSize, 2313 sal_Bool bEnlarge ) const 2314 { 2315 // #107947# Extracted from svdograf.cxx 2316 2317 // #104115# Crop the bitmap 2318 if( rAttr.IsCropped() ) 2319 { 2320 rBmpEx.Crop( rCropRect ); 2321 2322 // #104115# Negative crop sizes mean: enlarge bitmap and pad 2323 if( bEnlarge && ( 2324 rCropLeftTop.Width() < 0 || 2325 rCropLeftTop.Height() < 0 || 2326 rCropRightBottom.Width() < 0 || 2327 rCropRightBottom.Height() < 0 ) ) 2328 { 2329 Size aBmpSize( rBmpEx.GetSizePixel() ); 2330 sal_Int32 nPadLeft( rCropLeftTop.Width() < 0 ? -rCropLeftTop.Width() : 0 ); 2331 sal_Int32 nPadTop( rCropLeftTop.Height() < 0 ? -rCropLeftTop.Height() : 0 ); 2332 sal_Int32 nPadTotalWidth( aBmpSize.Width() + nPadLeft + (rCropRightBottom.Width() < 0 ? -rCropRightBottom.Width() : 0) ); 2333 sal_Int32 nPadTotalHeight( aBmpSize.Height() + nPadTop + (rCropRightBottom.Height() < 0 ? -rCropRightBottom.Height() : 0) ); 2334 2335 BitmapEx aBmpEx2; 2336 2337 if( rBmpEx.IsTransparent() ) 2338 { 2339 if( rBmpEx.IsAlpha() ) 2340 aBmpEx2 = BitmapEx( rBmpEx.GetBitmap(), rBmpEx.GetAlpha() ); 2341 else 2342 aBmpEx2 = BitmapEx( rBmpEx.GetBitmap(), rBmpEx.GetMask() ); 2343 } 2344 else 2345 { 2346 // #104115# Generate mask bitmap and init to zero 2347 Bitmap aMask( aBmpSize, 1 ); 2348 aMask.Erase( Color(0,0,0) ); 2349 2350 // #104115# Always generate transparent bitmap, we need the border transparent 2351 aBmpEx2 = BitmapEx( rBmpEx.GetBitmap(), aMask ); 2352 2353 // #104115# Add opaque mask to source bitmap, otherwise the destination remains transparent 2354 rBmpEx = aBmpEx2; 2355 } 2356 2357 aBmpEx2.SetSizePixel( Size(nPadTotalWidth, nPadTotalHeight) ); 2358 aBmpEx2.Erase( Color(0xFF,0,0,0) ); 2359 aBmpEx2.CopyPixel( Rectangle( Point(nPadLeft, nPadTop), aBmpSize ), Rectangle( Point(0, 0), aBmpSize ), &rBmpEx ); 2360 rBmpEx = aBmpEx2; 2361 } 2362 } 2363 2364 const Size aSizePixel( rBmpEx.GetSizePixel() ); 2365 2366 if( rAttr.GetRotation() != 0 && !IsAnimated() ) 2367 { 2368 if( aSizePixel.Width() && aSizePixel.Height() && rDstSize.Width() && rDstSize.Height() ) 2369 { 2370 double fSrcWH = (double) aSizePixel.Width() / aSizePixel.Height(); 2371 double fDstWH = (double) rDstSize.Width() / rDstSize.Height(); 2372 double fScaleX = 1.0, fScaleY = 1.0; 2373 2374 // always choose scaling to shrink bitmap 2375 if( fSrcWH < fDstWH ) 2376 fScaleY = aSizePixel.Width() / ( fDstWH * aSizePixel.Height() ); 2377 else 2378 fScaleX = fDstWH * aSizePixel.Height() / aSizePixel.Width(); 2379 2380 rBmpEx.Scale( fScaleX, fScaleY ); 2381 } 2382 } 2383 } 2384