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