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