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