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