Update ooo320-m1
[ooovba.git] / goodies / source / graphic / grfmgr2.cxx
blob1366afbd58a4f2d01ad32341dc790d72de963436
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: grfmgr2.cxx,v $
10 * $Revision: 1.26 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_goodies.hxx"
34 #include <vos/macros.hxx>
35 #include <vcl/bmpacc.hxx>
36 #include <tools/poly.hxx>
37 #include <vcl/outdev.hxx>
38 #include <vcl/window.hxx>
39 #include <vcl/gdimtf.hxx>
40 #include <vcl/metaact.hxx>
41 #include <vcl/metric.hxx>
42 #include <vcl/animate.hxx>
43 #include <vcl/alpha.hxx>
44 #include <vcl/virdev.hxx>
45 #include "grfcache.hxx"
46 #include "grfmgr.hxx"
48 // -----------
49 // - defines -
50 // -----------
52 #define MAX_PRINTER_EXT 1024
53 #define MAP( cVal0, cVal1, nFrac ) ((BYTE)((((long)(cVal0)<<20L)+nFrac*((long)(cVal1)-(cVal0)))>>20L))
54 #define WATERMARK_LUM_OFFSET 50
55 #define WATERMARK_CON_OFFSET -70
57 // -----------
58 // - helpers -
59 // -----------
61 namespace {
63 void muckWithBitmap( const Point& rDestPoint,
64 const Size& rDestSize,
65 const Size& rRefSize,
66 bool& o_rbNonBitmapActionEncountered )
68 const Point aEmptyPoint;
70 if( aEmptyPoint != rDestPoint ||
71 rDestSize != rRefSize )
73 // non-fullscale, or offsetted bmp -> fallback to mtf
74 // rendering
75 o_rbNonBitmapActionEncountered = true;
79 BitmapEx muckWithBitmap( const BitmapEx& rBmpEx,
80 const Point& rSrcPoint,
81 const Size& rSrcSize,
82 const Point& rDestPoint,
83 const Size& rDestSize,
84 const Size& rRefSize,
85 bool& o_rbNonBitmapActionEncountered )
87 BitmapEx aBmpEx;
89 muckWithBitmap(rDestPoint,
90 rDestSize,
91 rRefSize,
92 o_rbNonBitmapActionEncountered);
94 if( o_rbNonBitmapActionEncountered )
95 return aBmpEx;
97 aBmpEx = rBmpEx;
99 if( (rSrcPoint.X() != 0 && rSrcPoint.Y() != 0) ||
100 rSrcSize != rBmpEx.GetSizePixel() )
102 // crop bitmap to given source rectangle (no
103 // need to copy and convert the whole bitmap)
104 const Rectangle aCropRect( rSrcPoint,
105 rSrcSize );
106 aBmpEx.Crop( aCropRect );
109 return aBmpEx;
112 } // namespace {
115 // ------------------
116 // - GraphicManager -
117 // ------------------
119 GraphicManager::GraphicManager( ULONG nCacheSize, ULONG nMaxObjCacheSize ) :
120 mpCache( new GraphicCache( *this, nCacheSize, nMaxObjCacheSize ) )
124 // -----------------------------------------------------------------------------
126 GraphicManager::~GraphicManager()
128 for( void* pObj = maObjList.First(); pObj; pObj = maObjList.Next() )
129 ( (GraphicObject*) pObj )->GraphicManagerDestroyed();
131 delete mpCache;
134 // -----------------------------------------------------------------------------
136 void GraphicManager::SetMaxCacheSize( ULONG nNewCacheSize )
138 mpCache->SetMaxDisplayCacheSize( nNewCacheSize );
141 // -----------------------------------------------------------------------------
143 ULONG GraphicManager::GetMaxCacheSize() const
145 return mpCache->GetMaxDisplayCacheSize();
148 // -----------------------------------------------------------------------------
150 void GraphicManager::SetMaxObjCacheSize( ULONG nNewMaxObjSize, BOOL bDestroyGreaterCached )
152 mpCache->SetMaxObjDisplayCacheSize( nNewMaxObjSize, bDestroyGreaterCached );
155 // -----------------------------------------------------------------------------
157 ULONG GraphicManager::GetMaxObjCacheSize() const
159 return mpCache->GetMaxObjDisplayCacheSize();
162 // -----------------------------------------------------------------------------
164 ULONG GraphicManager::GetUsedCacheSize() const
166 return mpCache->GetUsedDisplayCacheSize();
169 // -----------------------------------------------------------------------------
171 ULONG GraphicManager::GetFreeCacheSize() const
173 return mpCache->GetFreeDisplayCacheSize();
176 // -----------------------------------------------------------------------------
178 void GraphicManager::SetCacheTimeout( ULONG nTimeoutSeconds )
180 mpCache->SetCacheTimeout( nTimeoutSeconds );
183 // -----------------------------------------------------------------------------
185 ULONG GraphicManager::GetCacheTimeout() const
187 return mpCache->GetCacheTimeout();
190 // -----------------------------------------------------------------------------
192 void GraphicManager::ClearCache()
194 mpCache->ClearDisplayCache();
197 // -----------------------------------------------------------------------------
199 void GraphicManager::ReleaseFromCache( const GraphicObject& /*rObj*/ )
201 // !!!
204 // -----------------------------------------------------------------------------
206 BOOL GraphicManager::IsInCache( OutputDevice* pOut, const Point& rPt,
207 const Size& rSz, const GraphicObject& rObj,
208 const GraphicAttr& rAttr ) const
210 return mpCache->IsInDisplayCache( pOut, rPt, rSz, rObj, rAttr );
213 // -----------------------------------------------------------------------------
215 BOOL GraphicManager::DrawObj( OutputDevice* pOut, const Point& rPt, const Size& rSz,
216 GraphicObject& rObj, const GraphicAttr& rAttr,
217 const ULONG nFlags, BOOL& rCached )
219 Point aPt( rPt );
220 Size aSz( rSz );
221 BOOL bRet = FALSE;
223 rCached = FALSE;
225 if( ( rObj.GetType() == GRAPHIC_BITMAP ) || ( rObj.GetType() == GRAPHIC_GDIMETAFILE ) )
227 // create output and fill cache
228 const Size aOutSize( pOut->GetOutputSizePixel() );
230 if( rObj.IsAnimated() || ( pOut->GetOutDevType() == OUTDEV_PRINTER ) ||
231 ( !( nFlags & GRFMGR_DRAW_NO_SUBSTITUTE ) &&
232 ( ( nFlags & GRFMGR_DRAW_SUBSTITUTE ) ||
233 !( nFlags & GRFMGR_DRAW_CACHED ) ||
234 ( pOut->GetConnectMetaFile() && !pOut->IsOutputEnabled() ) ) ) )
236 // simple output of transformed graphic
237 const Graphic aGraphic( rObj.GetTransformedGraphic( &rAttr ) );
239 if( aGraphic.IsSupportedGraphic() )
241 const USHORT nRot10 = rAttr.GetRotation() % 3600;
243 if( nRot10 )
245 Polygon aPoly( Rectangle( aPt, aSz ) );
247 aPoly.Rotate( aPt, nRot10 );
248 const Rectangle aRotBoundRect( aPoly.GetBoundRect() );
249 aPt = aRotBoundRect.TopLeft();
250 aSz = aRotBoundRect.GetSize();
253 aGraphic.Draw( pOut, aPt, aSz );
256 bRet = TRUE;
259 if( !bRet )
261 // cached/direct drawing
262 if( !mpCache->DrawDisplayCacheObj( pOut, aPt, aSz, rObj, rAttr ) )
263 bRet = ImplDraw( pOut, aPt, aSz, rObj, rAttr, nFlags, rCached );
264 else
265 bRet = rCached = TRUE;
269 return bRet;
272 // -----------------------------------------------------------------------------
274 void GraphicManager::ImplRegisterObj( const GraphicObject& rObj, Graphic& rSubstitute,
275 const ByteString* pID, const GraphicObject* pCopyObj )
277 maObjList.Insert( (void*) &rObj, LIST_APPEND );
278 mpCache->AddGraphicObject( rObj, rSubstitute, pID, pCopyObj );
281 // -----------------------------------------------------------------------------
283 void GraphicManager::ImplUnregisterObj( const GraphicObject& rObj )
285 mpCache->ReleaseGraphicObject( rObj );
286 maObjList.Remove( (void*) &rObj );
289 // -----------------------------------------------------------------------------
291 void GraphicManager::ImplGraphicObjectWasSwappedOut( const GraphicObject& rObj )
293 mpCache->GraphicObjectWasSwappedOut( rObj );
296 // -----------------------------------------------------------------------------
298 ByteString GraphicManager::ImplGetUniqueID( const GraphicObject& rObj ) const
300 return mpCache->GetUniqueID( rObj );
303 // -----------------------------------------------------------------------------
305 BOOL GraphicManager::ImplFillSwappedGraphicObject( const GraphicObject& rObj, Graphic& rSubstitute )
307 return( mpCache->FillSwappedGraphicObject( rObj, rSubstitute ) );
310 // -----------------------------------------------------------------------------
312 void GraphicManager::ImplGraphicObjectWasSwappedIn( const GraphicObject& rObj )
314 mpCache->GraphicObjectWasSwappedIn( rObj );
317 // -----------------------------------------------------------------------------
319 BOOL GraphicManager::ImplDraw( OutputDevice* pOut, const Point& rPt,
320 const Size& rSz, GraphicObject& rObj,
321 const GraphicAttr& rAttr,
322 const ULONG nFlags, BOOL& rCached )
324 const Graphic& rGraphic = rObj.GetGraphic();
325 BOOL bRet = FALSE;
327 if( rGraphic.IsSupportedGraphic() && !rGraphic.IsSwapOut() )
329 if( GRAPHIC_BITMAP == rGraphic.GetType() )
331 const BitmapEx aSrcBmpEx( rGraphic.GetBitmapEx() );
333 // #i46805# No point in caching a bitmap that is rendered
334 // via RectFill on the OutDev
335 if( !(pOut->GetDrawMode() & ( DRAWMODE_BLACKBITMAP | DRAWMODE_WHITEBITMAP )) &&
336 mpCache->IsDisplayCacheable( pOut, rPt, rSz, rObj, rAttr ) )
338 BitmapEx aDstBmpEx;
340 if( ImplCreateOutput( pOut, rPt, rSz, aSrcBmpEx, rAttr, nFlags, &aDstBmpEx ) )
342 rCached = mpCache->CreateDisplayCacheObj( pOut, rPt, rSz, rObj, rAttr, aDstBmpEx );
343 bRet = TRUE;
347 if( !bRet )
348 bRet = ImplCreateOutput( pOut, rPt, rSz, aSrcBmpEx, rAttr, nFlags );
350 else
352 const GDIMetaFile& rSrcMtf = rGraphic.GetGDIMetaFile();
354 if( mpCache->IsDisplayCacheable( pOut, rPt, rSz, rObj, rAttr ) )
356 GDIMetaFile aDstMtf;
357 BitmapEx aContainedBmpEx;
359 if( ImplCreateOutput( pOut, rPt, rSz, rSrcMtf, rAttr, nFlags, aDstMtf, aContainedBmpEx ) )
361 if( !!aContainedBmpEx )
363 // #117889# Use bitmap output method, if
364 // metafile basically contains only a single
365 // bitmap
366 BitmapEx aDstBmpEx;
368 if( ImplCreateOutput( pOut, rPt, rSz, aContainedBmpEx, rAttr, nFlags, &aDstBmpEx ) )
370 rCached = mpCache->CreateDisplayCacheObj( pOut, rPt, rSz, rObj, rAttr, aDstBmpEx );
371 bRet = TRUE;
374 else
376 rCached = mpCache->CreateDisplayCacheObj( pOut, rPt, rSz, rObj, rAttr, aDstMtf );
377 bRet = TRUE;
382 if( !bRet )
384 const Graphic aGraphic( rObj.GetTransformedGraphic( &rAttr ) );
386 if( aGraphic.IsSupportedGraphic() )
388 aGraphic.Draw( pOut, rPt, rSz );
389 bRet = TRUE;
395 return bRet;
398 // -----------------------------------------------------------------------------
400 BOOL GraphicManager::ImplCreateOutput( OutputDevice* pOut,
401 const Point& rPt, const Size& rSz,
402 const BitmapEx& rBmpEx, const GraphicAttr& rAttr,
403 const ULONG nFlags, BitmapEx* pBmpEx )
405 USHORT nRot10 = rAttr.GetRotation() % 3600;
406 Point aOutPtPix;
407 Size aOutSzPix;
408 Size aUnrotatedSzPix( pOut->LogicToPixel( rSz ) );
409 BOOL bRet = FALSE;
411 if( nRot10 )
413 Polygon aPoly( Rectangle( rPt, rSz ) );
415 aPoly.Rotate( rPt, nRot10 );
416 const Rectangle aRotBoundRect( aPoly.GetBoundRect() );
417 aOutPtPix = pOut->LogicToPixel( aRotBoundRect.TopLeft() );
418 aOutSzPix = pOut->LogicToPixel( aRotBoundRect.GetSize() );
420 else
422 aOutPtPix = pOut->LogicToPixel( rPt );
423 aOutSzPix = aUnrotatedSzPix;
426 if( aUnrotatedSzPix.Width() && aUnrotatedSzPix.Height() )
428 BitmapEx aBmpEx( rBmpEx );
429 BitmapEx aOutBmpEx;
430 Point aOutPt;
431 Size aOutSz;
432 const Size& rBmpSzPix = rBmpEx.GetSizePixel();
433 const long nW = rBmpSzPix.Width();
434 const long nH = rBmpSzPix.Height();
435 const long nNewW = aUnrotatedSzPix.Width();
436 const long nNewH = aUnrotatedSzPix.Height();
437 double fTmp;
438 long* pMapIX = new long[ nNewW ];
439 long* pMapFX = new long[ nNewW ];
440 long* pMapIY = new long[ nNewH ];
441 long* pMapFY = new long[ nNewH ];
442 long nStartX = -1, nStartY = -1, nEndX = -1, nEndY = -1;
443 long nX, nY, nTmp, nTmpX, nTmpY;
444 BOOL bHMirr = ( rAttr.GetMirrorFlags() & BMP_MIRROR_HORZ ) != 0;
445 BOOL bVMirr = ( rAttr.GetMirrorFlags() & BMP_MIRROR_VERT ) != 0;
447 if( nFlags & GRFMGR_DRAW_BILINEAR )
449 const double fRevScaleX = ( nNewW > 1L ) ? ( (double) ( nW - 1L ) / ( nNewW - 1L ) ) : 0.0;
450 const double fRevScaleY = ( nNewH > 1L ) ? ( (double) ( nH - 1L ) / ( nNewH - 1L ) ) : 0.0;
452 // create horizontal mapping table
453 for( nX = 0L, nTmpX = nW - 1L, nTmp = nW - 2L; nX < nNewW; nX++ )
455 fTmp = nX * fRevScaleX;
457 if( bHMirr )
458 fTmp = nTmpX - fTmp;
460 pMapFX[ nX ] = (long) ( ( fTmp - ( pMapIX[ nX ] = MinMax( (long) fTmp, 0, nTmp ) ) ) * 1048576. );
463 // create vertical mapping table
464 for( nY = 0L, nTmpY = nH - 1L, nTmp = nH - 2L; nY < nNewH; nY++ )
466 fTmp = nY * fRevScaleY;
468 if( bVMirr )
469 fTmp = nTmpY - fTmp;
471 pMapFY[ nY ] = (long) ( ( fTmp - ( pMapIY[ nY ] = MinMax( (long) fTmp, 0, nTmp ) ) ) * 1048576. );
474 else
476 // #98290# Use a different mapping for non-interpolating mode, to avoid missing rows/columns
477 const double fRevScaleX = ( nNewW > 1L ) ? ( (double) nW / nNewW ) : 0.0;
478 const double fRevScaleY = ( nNewH > 1L ) ? ( (double) nH / nNewH ) : 0.0;
480 // create horizontal mapping table
481 for( nX = 0L, nTmpX = nW - 1L, nTmp = nW - 2L; nX < nNewW; nX++ )
483 fTmp = nX * fRevScaleX;
485 if( bHMirr )
486 fTmp = nTmpX - fTmp;
488 // #98290# Do not use round to zero, otherwise last column will be missing
489 pMapIX[ nX ] = MinMax( (long) fTmp, 0, nTmp );
490 pMapFX[ nX ] = fTmp >= nTmp+1 ? 1048576 : 0;
493 // create vertical mapping table
494 for( nY = 0L, nTmpY = nH - 1L, nTmp = nH - 2L; nY < nNewH; nY++ )
496 fTmp = nY * fRevScaleY;
498 if( bVMirr )
499 fTmp = nTmpY - fTmp;
501 // #98290# Do not use round to zero, otherwise last row will be missing
502 pMapIY[ nY ] = MinMax( (long) fTmp, 0, nTmp );
503 pMapFY[ nY ] = fTmp >= nTmp+1 ? 1048576 : 0;
507 // calculate output sizes
508 if( !pBmpEx )
510 Point aPt;
511 Rectangle aOutRect( aPt, pOut->GetOutputSizePixel() );
512 Rectangle aBmpRect( aOutPtPix, aOutSzPix );
514 if( pOut->GetOutDevType() == OUTDEV_WINDOW )
516 const Region aPaintRgn( ( (Window*) pOut )->GetPaintRegion() );
517 if( !aPaintRgn.IsNull() )
518 aOutRect.Intersection( pOut->LogicToPixel( aPaintRgn.GetBoundRect() ) );
521 aOutRect.Intersection( aBmpRect );
523 if( !aOutRect.IsEmpty() )
525 aOutPt = pOut->PixelToLogic( aOutRect.TopLeft() );
526 aOutSz = pOut->PixelToLogic( aOutRect.GetSize() );
527 nStartX = aOutRect.Left() - aBmpRect.Left();
528 nStartY = aOutRect.Top() - aBmpRect.Top();
529 nEndX = aOutRect.Right() - aBmpRect.Left();
530 nEndY = aOutRect.Bottom() - aBmpRect.Top();
532 else
533 nStartX = -1L; // invalid
535 else
537 aOutPt = pOut->PixelToLogic( aOutPtPix );
538 aOutSz = pOut->PixelToLogic( aOutSzPix );
539 nStartX = nStartY = 0;
540 nEndX = aOutSzPix.Width() - 1L;
541 nEndY = aOutSzPix.Height() - 1L;
544 // do transformation
545 if( nStartX >= 0L )
547 const BOOL bSimple = ( 1 == nW || 1 == nH );
549 if( nRot10 )
551 if( bSimple )
553 bRet = ( aOutBmpEx = aBmpEx ).Scale( aUnrotatedSzPix );
555 if( bRet )
556 aOutBmpEx.Rotate( nRot10, COL_TRANSPARENT );
558 else
560 bRet = ImplCreateRotatedScaled( aBmpEx,
561 nRot10, aOutSzPix, aUnrotatedSzPix,
562 pMapIX, pMapFX, pMapIY, pMapFY, nStartX, nEndX, nStartY, nEndY,
563 aOutBmpEx );
566 else
568 // #105229# Don't scale if output size equals bitmap size
569 // #107226# Copy through only if we're not mirroring
570 if( !bHMirr && !bVMirr && aOutSzPix == rBmpSzPix )
572 // #107226# Use original dimensions when just copying through
573 aOutPt = pOut->PixelToLogic( aOutPtPix );
574 aOutSz = pOut->PixelToLogic( aOutSzPix );
575 aOutBmpEx = aBmpEx;
576 bRet = TRUE;
578 else
580 if( bSimple )
581 bRet = ( aOutBmpEx = aBmpEx ).Scale( Size( nEndX - nStartX + 1, nEndY - nStartY + 1 ) );
582 else
584 bRet = ImplCreateScaled( aBmpEx,
585 pMapIX, pMapFX, pMapIY, pMapFY,
586 nStartX, nEndX, nStartY, nEndY,
587 aOutBmpEx );
592 if( bRet )
594 // attribute adjustment if neccessary
595 if( rAttr.IsSpecialDrawMode() || rAttr.IsAdjusted() || rAttr.IsTransparent() )
596 ImplAdjust( aOutBmpEx, rAttr, ADJUSTMENT_DRAWMODE | ADJUSTMENT_COLORS | ADJUSTMENT_TRANSPARENCY );
598 // OutDev adjustment if neccessary
599 if( pOut->GetOutDevType() != OUTDEV_PRINTER && pOut->GetBitCount() <= 8 && aOutBmpEx.GetBitCount() >= 8 )
600 aOutBmpEx.Dither( BMP_DITHER_MATRIX );
604 // delete lookup tables
605 delete[] pMapIX;
606 delete[] pMapFX;
607 delete[] pMapIY;
608 delete[] pMapFY;
610 // create output
611 if( bRet )
613 if( !pBmpEx )
614 pOut->DrawBitmapEx( aOutPt, aOutSz, aOutBmpEx );
615 else
617 if( !rAttr.IsTransparent() && !aOutBmpEx.IsAlpha() )
618 aOutBmpEx = BitmapEx( aOutBmpEx.GetBitmap().CreateDisplayBitmap( pOut ), aOutBmpEx.GetMask() );
620 pOut->DrawBitmapEx( aOutPt, aOutSz, *pBmpEx = aOutBmpEx );
625 return bRet;
628 // -----------------------------------------------------------------------------
630 BOOL GraphicManager::ImplCreateOutput( OutputDevice* pOut,
631 const Point& rPt, const Size& rSz,
632 const GDIMetaFile& rMtf, const GraphicAttr& rAttr,
633 const ULONG /*nFlags*/, GDIMetaFile& rOutMtf, BitmapEx& rOutBmpEx )
635 const Size aNewSize( rMtf.GetPrefSize() );
637 rOutMtf = rMtf;
639 // #117889# count bitmap actions, and flag actions that paint, but
640 // are no bitmaps.
641 sal_Int32 nNumBitmaps(0);
642 bool bNonBitmapActionEncountered(false);
643 if( aNewSize.Width() && aNewSize.Height() && rSz.Width() && rSz.Height() )
645 const double fGrfWH = (double) aNewSize.Width() / aNewSize.Height();
646 const double fOutWH = (double) rSz.Width() / rSz.Height();
648 const double fScaleX = fOutWH / fGrfWH;
649 const double fScaleY = 1.0;
651 const MapMode& rPrefMapMode( rMtf.GetPrefMapMode() );
652 const Size& rSizePix( pOut->LogicToPixel( aNewSize,
653 rPrefMapMode ) );
655 // taking care of font width default if scaling metafile.
656 // #117889# use existing metafile scan, to determine whether
657 // the metafile basically displays a single bitmap. Note that
658 // the solution, as implemented here, is quite suboptimal (the
659 // cases where a mtf consisting basically of a single bitmap,
660 // that fail to pass the test below, are probably frequent). A
661 // better solution would involve FSAA, but that's currently
662 // expensive, and might trigger bugs on display drivers, if
663 // VDevs get bigger than the actual screen.
664 sal_uInt32 nCurPos;
665 MetaAction* pAct;
666 for( nCurPos = 0, pAct = (MetaAction*)rOutMtf.FirstAction(); pAct;
667 pAct = (MetaAction*)rOutMtf.NextAction(), nCurPos++ )
669 MetaAction* pModAct = NULL;
670 switch( pAct->GetType() )
672 case META_FONT_ACTION:
674 MetaFontAction* pA = (MetaFontAction*)pAct;
675 Font aFont( pA->GetFont() );
676 if ( !aFont.GetWidth() )
678 FontMetric aFontMetric( pOut->GetFontMetric( aFont ) );
679 aFont.SetWidth( aFontMetric.GetWidth() );
680 pModAct = new MetaFontAction( aFont );
683 // FALLTHROUGH intended
684 case META_NULL_ACTION:
685 // FALLTHROUGH intended
687 // OutDev state changes (which don't affect bitmap
688 // output)
689 case META_LINECOLOR_ACTION:
690 // FALLTHROUGH intended
691 case META_FILLCOLOR_ACTION:
692 // FALLTHROUGH intended
693 case META_TEXTCOLOR_ACTION:
694 // FALLTHROUGH intended
695 case META_TEXTFILLCOLOR_ACTION:
696 // FALLTHROUGH intended
697 case META_TEXTALIGN_ACTION:
698 // FALLTHROUGH intended
699 case META_TEXTLINECOLOR_ACTION:
700 // FALLTHROUGH intended
701 case META_TEXTLINE_ACTION:
702 // FALLTHROUGH intended
703 case META_PUSH_ACTION:
704 // FALLTHROUGH intended
705 case META_POP_ACTION:
706 // FALLTHROUGH intended
707 case META_LAYOUTMODE_ACTION:
708 // FALLTHROUGH intended
709 case META_TEXTLANGUAGE_ACTION:
710 // FALLTHROUGH intended
711 case META_COMMENT_ACTION:
712 break;
714 // bitmap output methods
715 case META_BMP_ACTION:
716 if( !nNumBitmaps && !bNonBitmapActionEncountered )
718 MetaBmpAction* pAction = (MetaBmpAction*)pAct;
720 rOutBmpEx = BitmapEx( pAction->GetBitmap() );
721 muckWithBitmap( pOut->LogicToPixel( pAction->GetPoint(),
722 rPrefMapMode ),
723 pAction->GetBitmap().GetSizePixel(),
724 rSizePix,
725 bNonBitmapActionEncountered );
726 ++nNumBitmaps;
728 break;
730 case META_BMPSCALE_ACTION:
731 if( !nNumBitmaps && !bNonBitmapActionEncountered )
733 MetaBmpScaleAction* pAction = (MetaBmpScaleAction*)pAct;
735 rOutBmpEx = BitmapEx( pAction->GetBitmap() );
736 muckWithBitmap( pOut->LogicToPixel( pAction->GetPoint(),
737 rPrefMapMode ),
738 pOut->LogicToPixel( pAction->GetSize(),
739 rPrefMapMode ),
740 rSizePix,
741 bNonBitmapActionEncountered );
742 ++nNumBitmaps;
744 break;
746 case META_BMPSCALEPART_ACTION:
747 if( !nNumBitmaps && !bNonBitmapActionEncountered )
749 MetaBmpScalePartAction* pAction = (MetaBmpScalePartAction*)pAct;
751 rOutBmpEx = muckWithBitmap( BitmapEx( pAction->GetBitmap() ),
752 pAction->GetSrcPoint(),
753 pAction->GetSrcSize(),
754 pOut->LogicToPixel( pAction->GetDestPoint(),
755 rPrefMapMode ),
756 pOut->LogicToPixel( pAction->GetDestSize(),
757 rPrefMapMode ),
758 rSizePix,
759 bNonBitmapActionEncountered );
760 ++nNumBitmaps;
762 break;
764 case META_BMPEX_ACTION:
765 if( !nNumBitmaps && !bNonBitmapActionEncountered )
767 MetaBmpExAction* pAction = (MetaBmpExAction*)pAct;
769 rOutBmpEx = pAction->GetBitmapEx();
770 muckWithBitmap( pOut->LogicToPixel( pAction->GetPoint(),
771 rPrefMapMode ),
772 pAction->GetBitmapEx().GetSizePixel(),
773 rSizePix,
774 bNonBitmapActionEncountered );
775 ++nNumBitmaps;
777 break;
779 case META_BMPEXSCALE_ACTION:
780 if( !nNumBitmaps && !bNonBitmapActionEncountered )
782 MetaBmpExScaleAction* pAction = (MetaBmpExScaleAction*)pAct;
784 rOutBmpEx = pAction->GetBitmapEx();
785 muckWithBitmap( pOut->LogicToPixel( pAction->GetPoint(),
786 rPrefMapMode ),
787 pOut->LogicToPixel( pAction->GetSize(),
788 rPrefMapMode ),
789 rSizePix,
790 bNonBitmapActionEncountered );
791 ++nNumBitmaps;
793 break;
795 case META_BMPEXSCALEPART_ACTION:
796 if( !nNumBitmaps && !bNonBitmapActionEncountered )
798 MetaBmpExScalePartAction* pAction = (MetaBmpExScalePartAction*)pAct;
800 rOutBmpEx = muckWithBitmap( pAction->GetBitmapEx(),
801 pAction->GetSrcPoint(),
802 pAction->GetSrcSize(),
803 pOut->LogicToPixel( pAction->GetDestPoint(),
804 rPrefMapMode ),
805 pOut->LogicToPixel( pAction->GetDestSize(),
806 rPrefMapMode ),
807 rSizePix,
808 bNonBitmapActionEncountered );
809 ++nNumBitmaps;
811 break;
813 // these actions actually output something (that's
814 // different from a bitmap)
815 case META_RASTEROP_ACTION:
816 if( ((MetaRasterOpAction*)pAct)->GetRasterOp() == ROP_OVERPAINT )
817 break;
818 // FALLTHROUGH intended
819 case META_PIXEL_ACTION:
820 // FALLTHROUGH intended
821 case META_POINT_ACTION:
822 // FALLTHROUGH intended
823 case META_LINE_ACTION:
824 // FALLTHROUGH intended
825 case META_RECT_ACTION:
826 // FALLTHROUGH intended
827 case META_ROUNDRECT_ACTION:
828 // FALLTHROUGH intended
829 case META_ELLIPSE_ACTION:
830 // FALLTHROUGH intended
831 case META_ARC_ACTION:
832 // FALLTHROUGH intended
833 case META_PIE_ACTION:
834 // FALLTHROUGH intended
835 case META_CHORD_ACTION:
836 // FALLTHROUGH intended
837 case META_POLYLINE_ACTION:
838 // FALLTHROUGH intended
839 case META_POLYGON_ACTION:
840 // FALLTHROUGH intended
841 case META_POLYPOLYGON_ACTION:
842 // FALLTHROUGH intended
844 case META_TEXT_ACTION:
845 // FALLTHROUGH intended
846 case META_TEXTARRAY_ACTION:
847 // FALLTHROUGH intended
848 case META_STRETCHTEXT_ACTION:
849 // FALLTHROUGH intended
850 case META_TEXTRECT_ACTION:
851 // FALLTHROUGH intended
853 case META_MASK_ACTION:
854 // FALLTHROUGH intended
855 case META_MASKSCALE_ACTION:
856 // FALLTHROUGH intended
857 case META_MASKSCALEPART_ACTION:
858 // FALLTHROUGH intended
860 case META_GRADIENT_ACTION:
861 // FALLTHROUGH intended
862 case META_HATCH_ACTION:
863 // FALLTHROUGH intended
864 case META_WALLPAPER_ACTION:
865 // FALLTHROUGH intended
867 case META_TRANSPARENT_ACTION:
868 // FALLTHROUGH intended
869 case META_EPS_ACTION:
870 // FALLTHROUGH intended
871 case META_FLOATTRANSPARENT_ACTION:
872 // FALLTHROUGH intended
873 case META_GRADIENTEX_ACTION:
874 // FALLTHROUGH intended
876 // OutDev state changes that _do_ affect bitmap
877 // output
878 case META_CLIPREGION_ACTION:
879 // FALLTHROUGH intended
880 case META_ISECTRECTCLIPREGION_ACTION:
881 // FALLTHROUGH intended
882 case META_ISECTREGIONCLIPREGION_ACTION:
883 // FALLTHROUGH intended
884 case META_MOVECLIPREGION_ACTION:
885 // FALLTHROUGH intended
887 case META_MAPMODE_ACTION:
888 // FALLTHROUGH intended
889 case META_REFPOINT_ACTION:
890 // FALLTHROUGH intended
891 default:
892 bNonBitmapActionEncountered = true;
893 break;
895 if ( pModAct )
897 rOutMtf.ReplaceAction( pModAct, nCurPos );
898 pAct->Delete();
900 else
902 if( pAct->GetRefCount() > 1 )
904 rOutMtf.ReplaceAction( pModAct = pAct->Clone(), nCurPos );
905 pAct->Delete();
907 else
908 pModAct = pAct;
910 pModAct->Scale( fScaleX, fScaleY );
912 rOutMtf.SetPrefSize( Size( FRound( aNewSize.Width() * fScaleX ),
913 FRound( aNewSize.Height() * fScaleY ) ) );
916 if( nNumBitmaps != 1 || bNonBitmapActionEncountered )
918 if( rAttr.IsSpecialDrawMode() || rAttr.IsAdjusted() || rAttr.IsMirrored() || rAttr.IsRotated() || rAttr.IsTransparent() )
919 ImplAdjust( rOutMtf, rAttr, ADJUSTMENT_ALL );
921 ImplDraw( pOut, rPt, rSz, rOutMtf, rAttr );
922 rOutBmpEx = BitmapEx();
925 return TRUE;
928 // -----------------------------------------------------------------------------
930 BOOL GraphicManager::ImplCreateScaled( const BitmapEx& rBmpEx,
931 long* pMapIX, long* pMapFX, long* pMapIY, long* pMapFY,
932 long nStartX, long nEndX, long nStartY, long nEndY,
933 BitmapEx& rOutBmpEx )
935 Bitmap aBmp( rBmpEx.GetBitmap() );
936 Bitmap aOutBmp;
937 BitmapReadAccess* pAcc = aBmp.AcquireReadAccess();
938 BitmapWriteAccess* pWAcc;
939 BitmapColor aCol0, aCol1, aColRes;
940 const long nDstW = nEndX - nStartX + 1L;
941 const long nDstH = nEndY - nStartY + 1L;
942 long nX, nY, nTmpX, nTmpY, nTmpFX, nTmpFY;
943 long nXDst, nYDst;
944 BYTE cR0, cG0, cB0, cR1, cG1, cB1;
945 BOOL bRet = FALSE;
947 DBG_ASSERT( aBmp.GetSizePixel() == rBmpEx.GetSizePixel(),
948 "GraphicManager::ImplCreateScaled(): bmp size inconsistent" );
950 if( pAcc )
952 aOutBmp = Bitmap( Size( nDstW, nDstH ), 24 );
953 pWAcc = aOutBmp.AcquireWriteAccess();
955 if( pWAcc )
957 if( pAcc->HasPalette() )
959 if( pAcc->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL )
961 Scanline pLine0, pLine1;
963 for( nY = nStartY, nYDst = 0L; nY <= nEndY; nY++, nYDst++ )
965 nTmpY = pMapIY[ nY ]; nTmpFY = pMapFY[ nY ];
966 pLine0 = pAcc->GetScanline( nTmpY );
967 pLine1 = pAcc->GetScanline( ++nTmpY );
969 for( nX = nStartX, nXDst = 0L; nX <= nEndX; nX++ )
971 nTmpX = pMapIX[ nX ]; nTmpFX = pMapFX[ nX ];
973 const BitmapColor& rCol0 = pAcc->GetPaletteColor( pLine0[ nTmpX ] );
974 const BitmapColor& rCol2 = pAcc->GetPaletteColor( pLine1[ nTmpX ] );
975 const BitmapColor& rCol1 = pAcc->GetPaletteColor( pLine0[ ++nTmpX ] );
976 const BitmapColor& rCol3 = pAcc->GetPaletteColor( pLine1[ nTmpX ] );
978 cR0 = MAP( rCol0.GetRed(), rCol1.GetRed(), nTmpFX );
979 cG0 = MAP( rCol0.GetGreen(), rCol1.GetGreen(), nTmpFX );
980 cB0 = MAP( rCol0.GetBlue(), rCol1.GetBlue(), nTmpFX );
982 cR1 = MAP( rCol2.GetRed(), rCol3.GetRed(), nTmpFX );
983 cG1 = MAP( rCol2.GetGreen(), rCol3.GetGreen(), nTmpFX );
984 cB1 = MAP( rCol2.GetBlue(), rCol3.GetBlue(), nTmpFX );
986 aColRes.SetRed( MAP( cR0, cR1, nTmpFY ) );
987 aColRes.SetGreen( MAP( cG0, cG1, nTmpFY ) );
988 aColRes.SetBlue( MAP( cB0, cB1, nTmpFY ) );
989 pWAcc->SetPixel( nYDst, nXDst++, aColRes );
993 else
995 for( nY = nStartY, nYDst = 0L; nY <= nEndY; nY++, nYDst++ )
997 nTmpY = pMapIY[ nY ], nTmpFY = pMapFY[ nY ];
999 for( nX = nStartX, nXDst = 0L; nX <= nEndX; nX++ )
1001 nTmpX = pMapIX[ nX ]; nTmpFX = pMapFX[ nX ];
1003 aCol0 = pAcc->GetPaletteColor( pAcc->GetPixel( nTmpY, nTmpX ) );
1004 aCol1 = pAcc->GetPaletteColor( pAcc->GetPixel( nTmpY, ++nTmpX ) );
1005 cR0 = MAP( aCol0.GetRed(), aCol1.GetRed(), nTmpFX );
1006 cG0 = MAP( aCol0.GetGreen(), aCol1.GetGreen(), nTmpFX );
1007 cB0 = MAP( aCol0.GetBlue(), aCol1.GetBlue(), nTmpFX );
1009 aCol1 = pAcc->GetPaletteColor( pAcc->GetPixel( ++nTmpY, nTmpX ) );
1010 aCol0 = pAcc->GetPaletteColor( pAcc->GetPixel( nTmpY--, --nTmpX ) );
1011 cR1 = MAP( aCol0.GetRed(), aCol1.GetRed(), nTmpFX );
1012 cG1 = MAP( aCol0.GetGreen(), aCol1.GetGreen(), nTmpFX );
1013 cB1 = MAP( aCol0.GetBlue(), aCol1.GetBlue(), nTmpFX );
1015 aColRes.SetRed( MAP( cR0, cR1, nTmpFY ) );
1016 aColRes.SetGreen( MAP( cG0, cG1, nTmpFY ) );
1017 aColRes.SetBlue( MAP( cB0, cB1, nTmpFY ) );
1018 pWAcc->SetPixel( nYDst, nXDst++, aColRes );
1023 else
1025 if( pAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_BGR )
1027 Scanline pLine0, pLine1, pTmp0, pTmp1;
1028 long nOff;
1030 for( nY = nStartY, nYDst = 0L; nY <= nEndY; nY++, nYDst++ )
1032 nTmpY = pMapIY[ nY ]; nTmpFY = pMapFY[ nY ];
1033 pLine0 = pAcc->GetScanline( nTmpY );
1034 pLine1 = pAcc->GetScanline( ++nTmpY );
1036 for( nX = nStartX, nXDst = 0L; nX <= nEndX; nX++ )
1038 nOff = 3L * ( nTmpX = pMapIX[ nX ] );
1039 nTmpFX = pMapFX[ nX ];
1041 pTmp1 = ( pTmp0 = pLine0 + nOff ) + 3L;
1042 cB0 = MAP( *pTmp0, *pTmp1, nTmpFX ); pTmp0++; pTmp1++;
1043 cG0 = MAP( *pTmp0, *pTmp1, nTmpFX ); pTmp0++; pTmp1++;
1044 cR0 = MAP( *pTmp0, *pTmp1, nTmpFX );
1046 pTmp1 = ( pTmp0 = pLine1 + nOff ) + 3L;
1047 cB1 = MAP( *pTmp0, *pTmp1, nTmpFX ); pTmp0++; pTmp1++;
1048 cG1 = MAP( *pTmp0, *pTmp1, nTmpFX ); pTmp0++; pTmp1++;
1049 cR1 = MAP( *pTmp0, *pTmp1, nTmpFX );
1051 aColRes.SetRed( MAP( cR0, cR1, nTmpFY ) );
1052 aColRes.SetGreen( MAP( cG0, cG1, nTmpFY ) );
1053 aColRes.SetBlue( MAP( cB0, cB1, nTmpFY ) );
1054 pWAcc->SetPixel( nYDst, nXDst++, aColRes );
1058 else if( pAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_RGB )
1060 Scanline pLine0, pLine1, pTmp0, pTmp1;
1061 long nOff;
1063 for( nY = nStartY, nYDst = 0L; nY <= nEndY; nY++, nYDst++ )
1065 nTmpY = pMapIY[ nY ]; nTmpFY = pMapFY[ nY ];
1066 pLine0 = pAcc->GetScanline( nTmpY );
1067 pLine1 = pAcc->GetScanline( ++nTmpY );
1069 for( nX = nStartX, nXDst = 0L; nX <= nEndX; nX++ )
1071 nOff = 3L * ( nTmpX = pMapIX[ nX ] );
1072 nTmpFX = pMapFX[ nX ];
1074 pTmp1 = ( pTmp0 = pLine0 + nOff ) + 3L;
1075 cR0 = MAP( *pTmp0, *pTmp1, nTmpFX ); pTmp0++; pTmp1++;
1076 cG0 = MAP( *pTmp0, *pTmp1, nTmpFX ); pTmp0++; pTmp1++;
1077 cB0 = MAP( *pTmp0, *pTmp1, nTmpFX );
1079 pTmp1 = ( pTmp0 = pLine1 + nOff ) + 3L;
1080 cR1 = MAP( *pTmp0, *pTmp1, nTmpFX ); pTmp0++; pTmp1++;
1081 cG1 = MAP( *pTmp0, *pTmp1, nTmpFX ); pTmp0++; pTmp1++;
1082 cB1 = MAP( *pTmp0, *pTmp1, nTmpFX );
1084 aColRes.SetRed( MAP( cR0, cR1, nTmpFY ) );
1085 aColRes.SetGreen( MAP( cG0, cG1, nTmpFY ) );
1086 aColRes.SetBlue( MAP( cB0, cB1, nTmpFY ) );
1087 pWAcc->SetPixel( nYDst, nXDst++, aColRes );
1091 else
1093 for( nY = nStartY, nYDst = 0L; nY <= nEndY; nY++, nYDst++ )
1095 nTmpY = pMapIY[ nY ]; nTmpFY = pMapFY[ nY ];
1097 for( nX = nStartX, nXDst = 0L; nX <= nEndX; nX++ )
1099 nTmpX = pMapIX[ nX ]; nTmpFX = pMapFX[ nX ];
1101 aCol0 = pAcc->GetPixel( nTmpY, nTmpX );
1102 aCol1 = pAcc->GetPixel( nTmpY, ++nTmpX );
1103 cR0 = MAP( aCol0.GetRed(), aCol1.GetRed(), nTmpFX );
1104 cG0 = MAP( aCol0.GetGreen(), aCol1.GetGreen(), nTmpFX );
1105 cB0 = MAP( aCol0.GetBlue(), aCol1.GetBlue(), nTmpFX );
1107 aCol1 = pAcc->GetPixel( ++nTmpY, nTmpX );
1108 aCol0 = pAcc->GetPixel( nTmpY--, --nTmpX );
1109 cR1 = MAP( aCol0.GetRed(), aCol1.GetRed(), nTmpFX );
1110 cG1 = MAP( aCol0.GetGreen(), aCol1.GetGreen(), nTmpFX );
1111 cB1 = MAP( aCol0.GetBlue(), aCol1.GetBlue(), nTmpFX );
1113 aColRes.SetRed( MAP( cR0, cR1, nTmpFY ) );
1114 aColRes.SetGreen( MAP( cG0, cG1, nTmpFY ) );
1115 aColRes.SetBlue( MAP( cB0, cB1, nTmpFY ) );
1116 pWAcc->SetPixel( nYDst, nXDst++, aColRes );
1122 aOutBmp.ReleaseAccess( pWAcc );
1123 bRet = TRUE;
1126 aBmp.ReleaseAccess( pAcc );
1129 if( bRet && rBmpEx.IsTransparent() )
1131 bRet = FALSE;
1133 if( rBmpEx.IsAlpha() )
1135 DBG_ASSERT( rBmpEx.GetAlpha().GetSizePixel() == rBmpEx.GetSizePixel(),
1136 "GraphicManager::ImplCreateScaled(): alpha mask size inconsistent" );
1138 AlphaMask aAlpha( rBmpEx.GetAlpha() );
1139 AlphaMask aOutAlpha;
1141 pAcc = aAlpha.AcquireReadAccess();
1143 if( pAcc )
1145 aOutAlpha = AlphaMask( Size( nDstW, nDstH ) );
1146 pWAcc = aOutAlpha.AcquireWriteAccess();
1148 if( pWAcc )
1150 if( pAcc->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL &&
1151 pWAcc->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL )
1153 Scanline pLine0, pLine1, pLineW;
1155 for( nY = nStartY, nYDst = 0L; nY <= nEndY; nY++, nYDst++ )
1157 nTmpY = pMapIY[ nY ]; nTmpFY = pMapFY[ nY ];
1158 pLine0 = pAcc->GetScanline( nTmpY );
1159 pLine1 = pAcc->GetScanline( ++nTmpY );
1160 pLineW = pWAcc->GetScanline( nYDst );
1162 for( nX = nStartX, nXDst = 0L; nX <= nEndX; nX++, nXDst++ )
1164 nTmpX = pMapIX[ nX ]; nTmpFX = pMapFX[ nX ];
1166 const long nAlpha0 = pLine0[ nTmpX ];
1167 const long nAlpha2 = pLine1[ nTmpX ];
1168 const long nAlpha1 = pLine0[ ++nTmpX ];
1169 const long nAlpha3 = pLine1[ nTmpX ];
1170 const long n0 = MAP( nAlpha0, nAlpha1, nTmpFX );
1171 const long n1 = MAP( nAlpha2, nAlpha3, nTmpFX );
1173 *pLineW++ = MAP( n0, n1, nTmpFY );
1177 else
1179 BitmapColor aAlphaValue( 0 );
1181 for( nY = nStartY, nYDst = 0L; nY <= nEndY; nY++, nYDst++ )
1183 nTmpY = pMapIY[ nY ], nTmpFY = pMapFY[ nY ];
1185 for( nX = nStartX, nXDst = 0L; nX <= nEndX; nX++ )
1187 nTmpX = pMapIX[ nX ]; nTmpFX = pMapFX[ nX ];
1189 long nAlpha0 = pAcc->GetPixel( nTmpY, nTmpX ).GetIndex();
1190 long nAlpha1 = pAcc->GetPixel( nTmpY, ++nTmpX ).GetIndex();
1191 const long n0 = MAP( nAlpha0, nAlpha1, nTmpFX );
1193 nAlpha1 = pAcc->GetPixel( ++nTmpY, nTmpX ).GetIndex();
1194 nAlpha0 = pAcc->GetPixel( nTmpY--, --nTmpX ).GetIndex();
1195 const long n1 = MAP( nAlpha0, nAlpha1, nTmpFX );
1197 aAlphaValue.SetIndex( MAP( n0, n1, nTmpFY ) );
1198 pWAcc->SetPixel( nYDst, nXDst++, aAlphaValue );
1203 aOutAlpha.ReleaseAccess( pWAcc );
1204 bRet = TRUE;
1207 aAlpha.ReleaseAccess( pAcc );
1209 if( bRet )
1210 rOutBmpEx = BitmapEx( aOutBmp, aOutAlpha );
1213 else
1215 DBG_ASSERT( rBmpEx.GetMask().GetSizePixel() == rBmpEx.GetSizePixel(),
1216 "GraphicManager::ImplCreateScaled(): mask size inconsistent" );
1218 Bitmap aMsk( rBmpEx.GetMask() );
1219 Bitmap aOutMsk;
1221 pAcc = aMsk.AcquireReadAccess();
1223 if( pAcc )
1225 // #i40115# Use the same palette for destination
1226 // bitmap. Otherwise, we'd have to color-map even the
1227 // case below, when both masks are one bit deep.
1228 if( pAcc->HasPalette() )
1229 aOutMsk = Bitmap( Size( nDstW, nDstH ),
1231 &pAcc->GetPalette() );
1232 else
1233 aOutMsk = Bitmap( Size( nDstW, nDstH ), 1 );
1235 pWAcc = aOutMsk.AcquireWriteAccess();
1237 if( pWAcc )
1239 long* pMapLX = new long[ nDstW ];
1240 long* pMapLY = new long[ nDstH ];
1242 // create new horizontal mapping table
1243 for( nX = 0UL, nTmpX = nStartX; nX < nDstW; nTmpX++ )
1244 pMapLX[ nX++ ] = FRound( (double) pMapIX[ nTmpX ] + pMapFX[ nTmpX ] / 1048576. );
1246 // create new vertical mapping table
1247 for( nY = 0UL, nTmpY = nStartY; nY < nDstH; nTmpY++ )
1248 pMapLY[ nY++ ] = FRound( (double) pMapIY[ nTmpY ] + pMapFY[ nTmpY ] / 1048576. );
1250 // do normal scaling
1251 if( pAcc->GetScanlineFormat() == BMP_FORMAT_1BIT_MSB_PAL &&
1252 pWAcc->GetScanlineFormat() == BMP_FORMAT_1BIT_MSB_PAL )
1254 // optimized
1255 for( nY = 0; nY < nDstH; nY++ )
1257 Scanline pSrc = pAcc->GetScanline( pMapLY[ nY ] );
1258 Scanline pDst = pWAcc->GetScanline( nY );
1260 for( nX = 0L; nX < nDstW; nX++ )
1262 const long nSrcX = pMapLX[ nX ];
1264 if( pSrc[ nSrcX >> 3 ] & ( 1 << ( 7 - ( nSrcX & 7 ) ) ) )
1265 pDst[ nX >> 3 ] |= 1 << ( 7 - ( nX & 7 ) );
1266 else
1267 pDst[ nX >> 3 ] &= ~( 1 << ( 7 - ( nX & 7 ) ) );
1271 else
1273 const BitmapColor aB( pAcc->GetBestMatchingColor( Color( COL_BLACK ) ) );
1274 const BitmapColor aWB( pWAcc->GetBestMatchingColor( Color( COL_BLACK ) ) );
1275 const BitmapColor aWW( pWAcc->GetBestMatchingColor( Color( COL_WHITE ) ) );
1277 if( pAcc->HasPalette() )
1279 for( nY = 0L; nY < nDstH; nY++ )
1281 for( nX = 0L; nX < nDstW; nX++ )
1283 if( pAcc->GetPaletteColor( (BYTE) pAcc->GetPixel( pMapLY[ nY ], pMapLX[ nX ] ) ) == aB )
1284 pWAcc->SetPixel( nY, nX, aWB );
1285 else
1286 pWAcc->SetPixel( nY, nX, aWW );
1290 else
1292 for( nY = 0L; nY < nDstH; nY++ )
1294 for( nX = 0L; nX < nDstW; nX++ )
1296 if( pAcc->GetPixel( pMapLY[ nY ], pMapLX[ nX ] ) == aB )
1297 pWAcc->SetPixel( nY, nX, aWB );
1298 else
1299 pWAcc->SetPixel( nY, nX, aWW );
1305 delete[] pMapLX;
1306 delete[] pMapLY;
1307 aOutMsk.ReleaseAccess( pWAcc );
1308 bRet = TRUE;
1311 aMsk.ReleaseAccess( pAcc );
1313 if( bRet )
1314 rOutBmpEx = BitmapEx( aOutBmp, aOutMsk );
1318 if( !bRet )
1319 rOutBmpEx = aOutBmp;
1321 else
1322 rOutBmpEx = aOutBmp;
1324 return bRet;
1327 // -----------------------------------------------------------------------------
1329 BOOL GraphicManager::ImplCreateRotatedScaled( const BitmapEx& rBmpEx,
1330 USHORT nRot10, const Size& /*rOutSzPix*/, const Size& rUnrotatedSzPix,
1331 long* pMapIX, long* pMapFX, long* pMapIY, long* pMapFY,
1332 long nStartX, long nEndX, long nStartY, long nEndY,
1333 BitmapEx& rOutBmpEx )
1335 Point aPt;
1336 Bitmap aBmp( rBmpEx.GetBitmap() );
1337 Bitmap aOutBmp;
1338 BitmapReadAccess* pAcc = aBmp.AcquireReadAccess();
1339 BitmapWriteAccess* pWAcc;
1340 Polygon aPoly( Rectangle( aPt, rUnrotatedSzPix ) ); aPoly.Rotate( Point(), nRot10 );
1341 Rectangle aNewBound( aPoly.GetBoundRect() );
1342 const double fCosAngle = cos( nRot10 * F_PI1800 ), fSinAngle = sin( nRot10 * F_PI1800 );
1343 double fTmp;
1344 const long nDstW = nEndX - nStartX + 1L;
1345 const long nDstH = nEndY - nStartY + 1L;
1346 const long nUnRotW = rUnrotatedSzPix.Width();
1347 const long nUnRotH = rUnrotatedSzPix.Height();
1348 long* pCosX = new long[ nDstW ];
1349 long* pSinX = new long[ nDstW ];
1350 long* pCosY = new long[ nDstH ];
1351 long* pSinY = new long[ nDstH ];
1352 long nX, nY, nTmpX, nTmpY, nTmpFX, nTmpFY, nUnRotX, nUnRotY, nSinY, nCosY;
1353 BYTE cR0, cG0, cB0, cR1, cG1, cB1;
1354 BOOL bRet = FALSE;
1356 // create horizontal mapping table
1357 for( nX = 0L, nTmpX = aNewBound.Left() + nStartX; nX < nDstW; nX++ )
1359 pCosX[ nX ] = FRound( fCosAngle * ( fTmp = nTmpX++ << 8 ) );
1360 pSinX[ nX ] = FRound( fSinAngle * fTmp );
1363 // create vertical mapping table
1364 for( nY = 0L, nTmpY = aNewBound.Top() + nStartY; nY < nDstH; nY++ )
1366 pCosY[ nY ] = FRound( fCosAngle * ( fTmp = nTmpY++ << 8 ) );
1367 pSinY[ nY ] = FRound( fSinAngle * fTmp );
1370 if( pAcc )
1372 aOutBmp = Bitmap( Size( nDstW, nDstH ), 24 );
1373 pWAcc = aOutBmp.AcquireWriteAccess();
1375 if( pWAcc )
1377 BitmapColor aColRes;
1379 if( pAcc->HasPalette() )
1381 for( nY = 0; nY < nDstH; nY++ )
1383 nSinY = pSinY[ nY ];
1384 nCosY = pCosY[ nY ];
1386 for( nX = 0; nX < nDstW; nX++ )
1388 nUnRotX = ( pCosX[ nX ] - nSinY ) >> 8;
1389 nUnRotY = ( pSinX[ nX ] + nCosY ) >> 8;
1391 if( ( nUnRotX >= 0L ) && ( nUnRotX < nUnRotW ) &&
1392 ( nUnRotY >= 0L ) && ( nUnRotY < nUnRotH ) )
1394 nTmpX = pMapIX[ nUnRotX ]; nTmpFX = pMapFX[ nUnRotX ];
1395 nTmpY = pMapIY[ nUnRotY ], nTmpFY = pMapFY[ nUnRotY ];
1397 const BitmapColor& rCol0 = pAcc->GetPaletteColor( pAcc->GetPixel( nTmpY, nTmpX ) );
1398 const BitmapColor& rCol1 = pAcc->GetPaletteColor( pAcc->GetPixel( nTmpY, ++nTmpX ) );
1399 cR0 = MAP( rCol0.GetRed(), rCol1.GetRed(), nTmpFX );
1400 cG0 = MAP( rCol0.GetGreen(), rCol1.GetGreen(), nTmpFX );
1401 cB0 = MAP( rCol0.GetBlue(), rCol1.GetBlue(), nTmpFX );
1403 const BitmapColor& rCol3 = pAcc->GetPaletteColor( pAcc->GetPixel( ++nTmpY, nTmpX ) );
1404 const BitmapColor& rCol2 = pAcc->GetPaletteColor( pAcc->GetPixel( nTmpY, --nTmpX ) );
1405 cR1 = MAP( rCol2.GetRed(), rCol3.GetRed(), nTmpFX );
1406 cG1 = MAP( rCol2.GetGreen(), rCol3.GetGreen(), nTmpFX );
1407 cB1 = MAP( rCol2.GetBlue(), rCol3.GetBlue(), nTmpFX );
1409 aColRes.SetRed( MAP( cR0, cR1, nTmpFY ) );
1410 aColRes.SetGreen( MAP( cG0, cG1, nTmpFY ) );
1411 aColRes.SetBlue( MAP( cB0, cB1, nTmpFY ) );
1412 pWAcc->SetPixel( nY, nX, aColRes );
1417 else
1419 BitmapColor aCol0, aCol1;
1421 for( nY = 0; nY < nDstH; nY++ )
1423 nSinY = pSinY[ nY ];
1424 nCosY = pCosY[ nY ];
1426 for( nX = 0; nX < nDstW; nX++ )
1428 nUnRotX = ( pCosX[ nX ] - nSinY ) >> 8;
1429 nUnRotY = ( pSinX[ nX ] + nCosY ) >> 8;
1431 if( ( nUnRotX >= 0L ) && ( nUnRotX < nUnRotW ) &&
1432 ( nUnRotY >= 0L ) && ( nUnRotY < nUnRotH ) )
1434 nTmpX = pMapIX[ nUnRotX ]; nTmpFX = pMapFX[ nUnRotX ];
1435 nTmpY = pMapIY[ nUnRotY ], nTmpFY = pMapFY[ nUnRotY ];
1437 aCol0 = pAcc->GetPixel( nTmpY, nTmpX );
1438 aCol1 = pAcc->GetPixel( nTmpY, ++nTmpX );
1439 cR0 = MAP( aCol0.GetRed(), aCol1.GetRed(), nTmpFX );
1440 cG0 = MAP( aCol0.GetGreen(), aCol1.GetGreen(), nTmpFX );
1441 cB0 = MAP( aCol0.GetBlue(), aCol1.GetBlue(), nTmpFX );
1443 aCol1 = pAcc->GetPixel( ++nTmpY, nTmpX );
1444 aCol0 = pAcc->GetPixel( nTmpY, --nTmpX );
1445 cR1 = MAP( aCol0.GetRed(), aCol1.GetRed(), nTmpFX );
1446 cG1 = MAP( aCol0.GetGreen(), aCol1.GetGreen(), nTmpFX );
1447 cB1 = MAP( aCol0.GetBlue(), aCol1.GetBlue(), nTmpFX );
1449 aColRes.SetRed( MAP( cR0, cR1, nTmpFY ) );
1450 aColRes.SetGreen( MAP( cG0, cG1, nTmpFY ) );
1451 aColRes.SetBlue( MAP( cB0, cB1, nTmpFY ) );
1452 pWAcc->SetPixel( nY, nX, aColRes );
1458 aOutBmp.ReleaseAccess( pWAcc );
1459 bRet = TRUE;
1462 aBmp.ReleaseAccess( pAcc );
1465 // mask processing
1466 if( bRet && ( rBmpEx.IsTransparent() || ( nRot10 != 900 && nRot10 != 1800 && nRot10 != 2700 ) ) )
1468 bRet = FALSE;
1470 if( rBmpEx.IsAlpha() )
1472 AlphaMask aAlpha( rBmpEx.GetAlpha() );
1473 AlphaMask aOutAlpha;
1475 pAcc = aAlpha.AcquireReadAccess();
1477 if( pAcc )
1479 aOutAlpha = AlphaMask( Size( nDstW, nDstH ) );
1480 pWAcc = aOutAlpha.AcquireWriteAccess();
1482 if( pWAcc )
1484 if( pAcc->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL &&
1485 pWAcc->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL )
1487 Scanline pLine0, pLine1, pLineW;
1489 for( nY = 0; nY < nDstH; nY++ )
1491 nSinY = pSinY[ nY ], nCosY = pCosY[ nY ];
1492 pLineW = pWAcc->GetScanline( nY );
1494 for( nX = 0; nX < nDstW; nX++ )
1496 nUnRotX = ( pCosX[ nX ] - nSinY ) >> 8;
1497 nUnRotY = ( pSinX[ nX ] + nCosY ) >> 8;
1499 if( ( nUnRotX >= 0L ) && ( nUnRotX < nUnRotW ) &&
1500 ( nUnRotY >= 0L ) && ( nUnRotY < nUnRotH ) )
1502 nTmpX = pMapIX[ nUnRotX ], nTmpFX = pMapFX[ nUnRotX ];
1503 nTmpY = pMapIY[ nUnRotY ], nTmpFY = pMapFY[ nUnRotY ];
1505 pLine0 = pAcc->GetScanline( nTmpY++ );
1506 pLine1 = pAcc->GetScanline( nTmpY );
1508 const long nAlpha0 = pLine0[ nTmpX ];
1509 const long nAlpha2 = pLine1[ nTmpX++ ];
1510 const long nAlpha1 = pLine0[ nTmpX ];
1511 const long nAlpha3 = pLine1[ nTmpX ];
1512 const long n0 = MAP( nAlpha0, nAlpha1, nTmpFX );
1513 const long n1 = MAP( nAlpha2, nAlpha3, nTmpFX );
1515 *pLineW++ = MAP( n0, n1, nTmpFY );
1517 else
1518 *pLineW++ = 255;
1522 else
1524 const BitmapColor aTrans( pWAcc->GetBestMatchingColor( Color( COL_WHITE ) ) );
1525 BitmapColor aAlphaVal( 0 );
1527 for( nY = 0; nY < nDstH; nY++ )
1529 nSinY = pSinY[ nY ], nCosY = pCosY[ nY ];
1531 for( nX = 0; nX < nDstW; nX++ )
1533 nUnRotX = ( pCosX[ nX ] - nSinY ) >> 8;
1534 nUnRotY = ( pSinX[ nX ] + nCosY ) >> 8;
1536 if( ( nUnRotX >= 0L ) && ( nUnRotX < nUnRotW ) &&
1537 ( nUnRotY >= 0L ) && ( nUnRotY < nUnRotH ) )
1539 nTmpX = pMapIX[ nUnRotX ]; nTmpFX = pMapFX[ nUnRotX ];
1540 nTmpY = pMapIY[ nUnRotY ], nTmpFY = pMapFY[ nUnRotY ];
1542 const long nAlpha0 = pAcc->GetPixel( nTmpY, nTmpX ).GetIndex();
1543 const long nAlpha1 = pAcc->GetPixel( nTmpY, ++nTmpX ).GetIndex();
1544 const long nAlpha3 = pAcc->GetPixel( ++nTmpY, nTmpX ).GetIndex();
1545 const long nAlpha2 = pAcc->GetPixel( nTmpY, --nTmpX ).GetIndex();
1546 const long n0 = MAP( nAlpha0, nAlpha1, nTmpFX );
1547 const long n1 = MAP( nAlpha2, nAlpha3, nTmpFX );
1549 aAlphaVal.SetIndex( MAP( n0, n1, nTmpFY ) );
1550 pWAcc->SetPixel( nY, nX, aAlphaVal );
1552 else
1553 pWAcc->SetPixel( nY, nX, aTrans );
1558 aOutAlpha.ReleaseAccess( pWAcc );
1559 bRet = TRUE;
1562 aAlpha.ReleaseAccess( pAcc );
1565 if( bRet )
1566 rOutBmpEx = BitmapEx( aOutBmp, aOutAlpha );
1568 else
1570 Bitmap aOutMsk( Size( nDstW, nDstH ), 1 );
1571 pWAcc = aOutMsk.AcquireWriteAccess();
1573 if( pWAcc )
1575 Bitmap aMsk( rBmpEx.GetMask() );
1576 const BitmapColor aB( pWAcc->GetBestMatchingColor( Color( COL_BLACK ) ) );
1577 const BitmapColor aW( pWAcc->GetBestMatchingColor( Color( COL_WHITE ) ) );
1578 BitmapReadAccess* pMAcc = NULL;
1580 if( !aMsk || ( ( pMAcc = aMsk.AcquireReadAccess() ) != NULL ) )
1582 long* pMapLX = new long[ nUnRotW ];
1583 long* pMapLY = new long[ nUnRotH ];
1584 BitmapColor aTestB;
1586 if( pMAcc )
1587 aTestB = pMAcc->GetBestMatchingColor( Color( COL_BLACK ) );
1589 // create new horizontal mapping table
1590 for( nX = 0UL; nX < nUnRotW; nX++ )
1591 pMapLX[ nX ] = FRound( (double) pMapIX[ nX ] + pMapFX[ nX ] / 1048576. );
1593 // create new vertical mapping table
1594 for( nY = 0UL; nY < nUnRotH; nY++ )
1595 pMapLY[ nY ] = FRound( (double) pMapIY[ nY ] + pMapFY[ nY ] / 1048576. );
1597 // do mask rotation
1598 for( nY = 0; nY < nDstH; nY++ )
1600 nSinY = pSinY[ nY ];
1601 nCosY = pCosY[ nY ];
1603 for( nX = 0; nX < nDstW; nX++ )
1605 nUnRotX = ( pCosX[ nX ] - nSinY ) >> 8;
1606 nUnRotY = ( pSinX[ nX ] + nCosY ) >> 8;
1608 if( ( nUnRotX >= 0L ) && ( nUnRotX < nUnRotW ) &&
1609 ( nUnRotY >= 0L ) && ( nUnRotY < nUnRotH ) )
1611 if( pMAcc )
1613 if( pMAcc->GetPixel( pMapLY[ nUnRotY ], pMapLX[ nUnRotX ] ) == aTestB )
1614 pWAcc->SetPixel( nY, nX, aB );
1615 else
1616 pWAcc->SetPixel( nY, nX, aW );
1618 else
1619 pWAcc->SetPixel( nY, nX, aB );
1621 else
1622 pWAcc->SetPixel( nY, nX, aW );
1626 delete[] pMapLX;
1627 delete[] pMapLY;
1629 if( pMAcc )
1630 aMsk.ReleaseAccess( pMAcc );
1632 bRet = TRUE;
1635 aOutMsk.ReleaseAccess( pWAcc );
1638 if( bRet )
1639 rOutBmpEx = BitmapEx( aOutBmp, aOutMsk );
1642 if( !bRet )
1643 rOutBmpEx = aOutBmp;
1645 else
1646 rOutBmpEx = aOutBmp;
1648 delete[] pSinX;
1649 delete[] pCosX;
1650 delete[] pSinY;
1651 delete[] pCosY;
1653 return bRet;
1656 // -----------------------------------------------------------------------------
1658 void GraphicManager::ImplAdjust( BitmapEx& rBmpEx, const GraphicAttr& rAttr, ULONG nAdjustmentFlags )
1660 GraphicAttr aAttr( rAttr );
1662 if( ( nAdjustmentFlags & ADJUSTMENT_DRAWMODE ) && aAttr.IsSpecialDrawMode() )
1664 switch( aAttr.GetDrawMode() )
1666 case( GRAPHICDRAWMODE_MONO ):
1667 rBmpEx.Convert( BMP_CONVERSION_1BIT_THRESHOLD );
1668 break;
1670 case( GRAPHICDRAWMODE_GREYS ):
1671 rBmpEx.Convert( BMP_CONVERSION_8BIT_GREYS );
1672 break;
1674 case( GRAPHICDRAWMODE_WATERMARK ):
1676 aAttr.SetLuminance( aAttr.GetLuminance() + WATERMARK_LUM_OFFSET );
1677 aAttr.SetContrast( aAttr.GetContrast() + WATERMARK_CON_OFFSET );
1679 break;
1681 default:
1682 break;
1686 if( ( nAdjustmentFlags & ADJUSTMENT_COLORS ) && aAttr.IsAdjusted() )
1688 rBmpEx.Adjust( aAttr.GetLuminance(), aAttr.GetContrast(),
1689 aAttr.GetChannelR(), aAttr.GetChannelG(), aAttr.GetChannelB(),
1690 aAttr.GetGamma(), aAttr.IsInvert() );
1693 if( ( nAdjustmentFlags & ADJUSTMENT_MIRROR ) && aAttr.IsMirrored() )
1695 rBmpEx.Mirror( aAttr.GetMirrorFlags() );
1698 if( ( nAdjustmentFlags & ADJUSTMENT_ROTATE ) && aAttr.IsRotated() )
1700 rBmpEx.Rotate( aAttr.GetRotation(), Color( COL_TRANSPARENT ) );
1703 if( ( nAdjustmentFlags & ADJUSTMENT_TRANSPARENCY ) && aAttr.IsTransparent() )
1705 AlphaMask aAlpha;
1706 BYTE cTrans = aAttr.GetTransparency();
1708 if( !rBmpEx.IsTransparent() )
1709 aAlpha = AlphaMask( rBmpEx.GetSizePixel(), &cTrans );
1710 else if( !rBmpEx.IsAlpha() )
1712 aAlpha = rBmpEx.GetMask();
1713 aAlpha.Replace( 0, cTrans );
1715 else
1717 aAlpha = rBmpEx.GetAlpha();
1718 BitmapWriteAccess* pA = aAlpha.AcquireWriteAccess();
1720 if( pA )
1722 ULONG nTrans = cTrans, nNewTrans;
1723 const long nWidth = pA->Width(), nHeight = pA->Height();
1725 if( pA->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL )
1727 for( long nY = 0; nY < nHeight; nY++ )
1729 Scanline pAScan = pA->GetScanline( nY );
1731 for( long nX = 0; nX < nWidth; nX++ )
1733 nNewTrans = nTrans + *pAScan;
1734 *pAScan++ = (BYTE) ( ( nNewTrans & 0xffffff00 ) ? 255 : nNewTrans );
1738 else
1740 BitmapColor aAlphaValue( 0 );
1742 for( long nY = 0; nY < nHeight; nY++ )
1744 for( long nX = 0; nX < nWidth; nX++ )
1746 nNewTrans = nTrans + pA->GetPixel( nY, nX ).GetIndex();
1747 aAlphaValue.SetIndex( (BYTE) ( ( nNewTrans & 0xffffff00 ) ? 255 : nNewTrans ) );
1748 pA->SetPixel( nY, nX, aAlphaValue );
1753 aAlpha.ReleaseAccess( pA );
1757 rBmpEx = BitmapEx( rBmpEx.GetBitmap(), aAlpha );
1761 // -----------------------------------------------------------------------------
1763 void GraphicManager::ImplAdjust( GDIMetaFile& rMtf, const GraphicAttr& rAttr, ULONG nAdjustmentFlags )
1765 GraphicAttr aAttr( rAttr );
1767 if( ( nAdjustmentFlags & ADJUSTMENT_DRAWMODE ) && aAttr.IsSpecialDrawMode() )
1769 switch( aAttr.GetDrawMode() )
1771 case( GRAPHICDRAWMODE_MONO ):
1772 rMtf.Convert( MTF_CONVERSION_1BIT_THRESHOLD );
1773 break;
1775 case( GRAPHICDRAWMODE_GREYS ):
1776 rMtf.Convert( MTF_CONVERSION_8BIT_GREYS );
1777 break;
1779 case( GRAPHICDRAWMODE_WATERMARK ):
1781 aAttr.SetLuminance( aAttr.GetLuminance() + WATERMARK_LUM_OFFSET );
1782 aAttr.SetContrast( aAttr.GetContrast() + WATERMARK_CON_OFFSET );
1784 break;
1786 default:
1787 break;
1791 if( ( nAdjustmentFlags & ADJUSTMENT_COLORS ) && aAttr.IsAdjusted() )
1793 rMtf.Adjust( aAttr.GetLuminance(), aAttr.GetContrast(),
1794 aAttr.GetChannelR(), aAttr.GetChannelG(), aAttr.GetChannelB(),
1795 aAttr.GetGamma(), aAttr.IsInvert() );
1798 if( ( nAdjustmentFlags & ADJUSTMENT_MIRROR ) && aAttr.IsMirrored() )
1800 rMtf.Mirror( aAttr.GetMirrorFlags() );
1803 if( ( nAdjustmentFlags & ADJUSTMENT_ROTATE ) && aAttr.IsRotated() )
1805 rMtf.Rotate( aAttr.GetRotation() );
1808 if( ( nAdjustmentFlags & ADJUSTMENT_TRANSPARENCY ) && aAttr.IsTransparent() )
1810 DBG_ERROR( "Missing implementation: Mtf-Transparency" );
1814 // -----------------------------------------------------------------------------
1816 void GraphicManager::ImplAdjust( Animation& rAnimation, const GraphicAttr& rAttr, ULONG nAdjustmentFlags )
1818 GraphicAttr aAttr( rAttr );
1820 if( ( nAdjustmentFlags & ADJUSTMENT_DRAWMODE ) && aAttr.IsSpecialDrawMode() )
1822 switch( aAttr.GetDrawMode() )
1824 case( GRAPHICDRAWMODE_MONO ):
1825 rAnimation.Convert( BMP_CONVERSION_1BIT_THRESHOLD );
1826 break;
1828 case( GRAPHICDRAWMODE_GREYS ):
1829 rAnimation.Convert( BMP_CONVERSION_8BIT_GREYS );
1830 break;
1832 case( GRAPHICDRAWMODE_WATERMARK ):
1834 aAttr.SetLuminance( aAttr.GetLuminance() + WATERMARK_LUM_OFFSET );
1835 aAttr.SetContrast( aAttr.GetContrast() + WATERMARK_CON_OFFSET );
1837 break;
1839 default:
1840 break;
1844 if( ( nAdjustmentFlags & ADJUSTMENT_COLORS ) && aAttr.IsAdjusted() )
1846 rAnimation.Adjust( aAttr.GetLuminance(), aAttr.GetContrast(),
1847 aAttr.GetChannelR(), aAttr.GetChannelG(), aAttr.GetChannelB(),
1848 aAttr.GetGamma(), aAttr.IsInvert() );
1851 if( ( nAdjustmentFlags & ADJUSTMENT_MIRROR ) && aAttr.IsMirrored() )
1853 rAnimation.Mirror( aAttr.GetMirrorFlags() );
1856 if( ( nAdjustmentFlags & ADJUSTMENT_ROTATE ) && aAttr.IsRotated() )
1858 DBG_ERROR( "Missing implementation: Animation-Rotation" );
1861 if( ( nAdjustmentFlags & ADJUSTMENT_TRANSPARENCY ) && aAttr.IsTransparent() )
1863 DBG_ERROR( "Missing implementation: Animation-Transparency" );
1867 // -----------------------------------------------------------------------------
1869 void GraphicManager::ImplDraw( OutputDevice* pOut, const Point& rPt, const Size& rSz,
1870 const GDIMetaFile& rMtf, const GraphicAttr& rAttr )
1872 USHORT nRot10 = rAttr.GetRotation() % 3600;
1873 Point aOutPt( rPt );
1874 Size aOutSz( rSz );
1876 if( nRot10 )
1878 Polygon aPoly( Rectangle( aOutPt, aOutSz ) );
1880 aPoly.Rotate( aOutPt, nRot10 );
1881 const Rectangle aRotBoundRect( aPoly.GetBoundRect() );
1882 aOutPt = aRotBoundRect.TopLeft();
1883 aOutSz = aRotBoundRect.GetSize();
1886 pOut->Push( PUSH_CLIPREGION );
1887 pOut->IntersectClipRegion( Rectangle( aOutPt, aOutSz ) );
1889 ( (GDIMetaFile&) rMtf ).WindStart();
1890 ( (GDIMetaFile&) rMtf ).Play( pOut, aOutPt, aOutSz );
1891 ( (GDIMetaFile&) rMtf ).WindStart();
1893 pOut->Pop();
1896 // -----------------------------------------------------------------------------
1898 struct ImplTileInfo
1900 ImplTileInfo() : aTileTopLeft(), aNextTileTopLeft(), aTileSizePixel(), nTilesEmptyX(0), nTilesEmptyY(0) {}
1902 Point aTileTopLeft; // top, left position of the rendered tile
1903 Point aNextTileTopLeft; // top, left position for next recursion
1904 // level's tile
1905 Size aTileSizePixel; // size of the generated tile (might
1906 // differ from
1907 // aNextTileTopLeft-aTileTopLeft, because
1908 // this is nExponent*prevTileSize. The
1909 // generated tile is always nExponent
1910 // times the previous tile, such that it
1911 // can be used in the next stage. The
1912 // required area coverage is often
1913 // less. The extraneous area covered is
1914 // later overwritten by the next stage)
1915 int nTilesEmptyX; // number of original tiles empty right of
1916 // this tile. This counts from
1917 // aNextTileTopLeft, i.e. the additional
1918 // area covered by aTileSizePixel is not
1919 // considered here. This is for
1920 // unification purposes, as the iterative
1921 // calculation of the next level's empty
1922 // tiles has to be based on this value.
1923 int nTilesEmptyY; // as above, for Y
1927 bool GraphicObject::ImplRenderTempTile( VirtualDevice& rVDev, int nExponent,
1928 int nNumTilesX, int nNumTilesY,
1929 const Size& rTileSizePixel,
1930 const GraphicAttr* pAttr, ULONG nFlags )
1932 if( nExponent <= 1 )
1933 return false;
1935 // determine MSB factor
1936 int nMSBFactor( 1 );
1937 while( nNumTilesX / nMSBFactor != 0 ||
1938 nNumTilesY / nMSBFactor != 0 )
1940 nMSBFactor *= nExponent;
1943 // one less
1944 nMSBFactor /= nExponent;
1946 ImplTileInfo aTileInfo;
1948 // #105229# Switch off mapping (converting to logic and back to
1949 // pixel might cause roundoff errors)
1950 BOOL bOldMap( rVDev.IsMapModeEnabled() );
1951 rVDev.EnableMapMode( FALSE );
1953 bool bRet( ImplRenderTileRecursive( rVDev, nExponent, nMSBFactor, nNumTilesX, nNumTilesY,
1954 nNumTilesX, nNumTilesY, rTileSizePixel, pAttr, nFlags, aTileInfo ) );
1956 rVDev.EnableMapMode( bOldMap );
1958 return bRet;
1961 // -----------------------------------------------------------------------------
1963 // define for debug drawings
1964 //#define DBG_TEST
1966 // see header comment. this works similar to base conversion of a
1967 // number, i.e. if the exponent is 10, then the number for every tile
1968 // size is given by the decimal place of the corresponding decimal
1969 // representation.
1970 bool GraphicObject::ImplRenderTileRecursive( VirtualDevice& rVDev, int nExponent, int nMSBFactor,
1971 int nNumOrigTilesX, int nNumOrigTilesY,
1972 int nRemainderTilesX, int nRemainderTilesY,
1973 const Size& rTileSizePixel, const GraphicAttr* pAttr,
1974 ULONG nFlags, ImplTileInfo& rTileInfo )
1976 // gets loaded with our tile bitmap
1977 GraphicObject aTmpGraphic;
1979 // stores a flag that renders the zero'th tile position
1980 // (i.e. (0,0)+rCurrPos) only if we're at the bottom of the
1981 // recursion stack. All other position already have that tile
1982 // rendered, because the lower levels painted their generated tile
1983 // there.
1984 bool bNoFirstTileDraw( false );
1986 // what's left when we're done with our tile size
1987 const int nNewRemainderX( nRemainderTilesX % nMSBFactor );
1988 const int nNewRemainderY( nRemainderTilesY % nMSBFactor );
1990 // gets filled out from the recursive call with info of what's
1991 // been generated
1992 ImplTileInfo aTileInfo;
1994 // current output position while drawing
1995 Point aCurrPos;
1996 int nX, nY;
1998 // check for recursion's end condition: LSB place reached?
1999 if( nMSBFactor == 1 )
2001 aTmpGraphic = *this;
2003 // set initial tile size -> orig size
2004 aTileInfo.aTileSizePixel = rTileSizePixel;
2005 aTileInfo.nTilesEmptyX = nNumOrigTilesX;
2006 aTileInfo.nTilesEmptyY = nNumOrigTilesY;
2008 else if( ImplRenderTileRecursive( rVDev, nExponent, nMSBFactor/nExponent,
2009 nNumOrigTilesX, nNumOrigTilesY,
2010 nNewRemainderX, nNewRemainderY,
2011 rTileSizePixel, pAttr, nFlags, aTileInfo ) )
2013 // extract generated tile -> see comment on the first loop below
2014 BitmapEx aTileBitmap( rVDev.GetBitmap( aTileInfo.aTileTopLeft, aTileInfo.aTileSizePixel ) );
2016 aTmpGraphic = GraphicObject( aTileBitmap );
2018 // fill stripes left over from upstream levels:
2020 // x0000
2021 // 0
2022 // 0
2023 // 0
2024 // 0
2026 // where x denotes the place filled by our recursive predecessors
2028 // check whether we have to fill stripes here. Although not
2029 // obvious, there is one case where we can skip this step: if
2030 // the previous recursion level (the one who filled our
2031 // aTileInfo) had zero area to fill, then there are no white
2032 // stripes left, naturally. This happens if the digit
2033 // associated to that level has a zero, and can be checked via
2034 // aTileTopLeft==aNextTileTopLeft.
2035 if( aTileInfo.aTileTopLeft != aTileInfo.aNextTileTopLeft )
2037 // now fill one row from aTileInfo.aNextTileTopLeft.X() all
2038 // the way to the right
2039 aCurrPos.X() = aTileInfo.aNextTileTopLeft.X();
2040 aCurrPos.Y() = aTileInfo.aTileTopLeft.Y();
2041 for( nX=0; nX < aTileInfo.nTilesEmptyX; nX += nMSBFactor )
2043 if( !aTmpGraphic.Draw( &rVDev, aCurrPos, aTileInfo.aTileSizePixel, pAttr, nFlags ) )
2044 return false;
2046 aCurrPos.X() += aTileInfo.aTileSizePixel.Width();
2049 #ifdef DBG_TEST
2050 // rVDev.SetFillColor( COL_WHITE );
2051 rVDev.SetFillColor();
2052 rVDev.SetLineColor( Color( 255 * nExponent / nMSBFactor, 255 - 255 * nExponent / nMSBFactor, 128 - 255 * nExponent / nMSBFactor ) );
2053 rVDev.DrawEllipse( Rectangle(aTileInfo.aNextTileTopLeft.X(), aTileInfo.aTileTopLeft.Y(),
2054 aTileInfo.aNextTileTopLeft.X() - 1 + (aTileInfo.nTilesEmptyX/nMSBFactor)*aTileInfo.aTileSizePixel.Width(),
2055 aTileInfo.aTileTopLeft.Y() + aTileInfo.aTileSizePixel.Height() - 1) );
2056 #endif
2058 // now fill one column from aTileInfo.aNextTileTopLeft.Y() all
2059 // the way to the bottom
2060 aCurrPos.X() = aTileInfo.aTileTopLeft.X();
2061 aCurrPos.Y() = aTileInfo.aNextTileTopLeft.Y();
2062 for( nY=0; nY < aTileInfo.nTilesEmptyY; nY += nMSBFactor )
2064 if( !aTmpGraphic.Draw( &rVDev, aCurrPos, aTileInfo.aTileSizePixel, pAttr, nFlags ) )
2065 return false;
2067 aCurrPos.Y() += aTileInfo.aTileSizePixel.Height();
2070 #ifdef DBG_TEST
2071 rVDev.DrawEllipse( Rectangle(aTileInfo.aTileTopLeft.X(), aTileInfo.aNextTileTopLeft.Y(),
2072 aTileInfo.aTileTopLeft.X() + aTileInfo.aTileSizePixel.Width() - 1,
2073 aTileInfo.aNextTileTopLeft.Y() - 1 + (aTileInfo.nTilesEmptyY/nMSBFactor)*aTileInfo.aTileSizePixel.Height()) );
2074 #endif
2076 else
2078 // Thought that aTileInfo.aNextTileTopLeft tile has always
2079 // been drawn already, but that's wrong: typically,
2080 // _parts_ of that tile have been drawn, since the
2081 // previous level generated the tile there. But when
2082 // aTileInfo.aNextTileTopLeft!=aTileInfo.aTileTopLeft, the
2083 // difference between these two values is missing in the
2084 // lower right corner of this first tile. So, can do that
2085 // only here.
2086 bNoFirstTileDraw = true;
2089 else
2091 return false;
2094 // calc number of original tiles in our drawing area without
2095 // remainder
2096 nRemainderTilesX -= nNewRemainderX;
2097 nRemainderTilesY -= nNewRemainderY;
2099 // fill tile info for calling method
2100 rTileInfo.aTileTopLeft = aTileInfo.aNextTileTopLeft;
2101 rTileInfo.aNextTileTopLeft = Point( rTileInfo.aTileTopLeft.X() + rTileSizePixel.Width()*nRemainderTilesX,
2102 rTileInfo.aTileTopLeft.Y() + rTileSizePixel.Height()*nRemainderTilesY );
2103 rTileInfo.aTileSizePixel = Size( rTileSizePixel.Width()*nMSBFactor*nExponent,
2104 rTileSizePixel.Height()*nMSBFactor*nExponent );
2105 rTileInfo.nTilesEmptyX = aTileInfo.nTilesEmptyX - nRemainderTilesX;
2106 rTileInfo.nTilesEmptyY = aTileInfo.nTilesEmptyY - nRemainderTilesY;
2108 // init output position
2109 aCurrPos = aTileInfo.aNextTileTopLeft;
2111 // fill our drawing area. Fill possibly more, to create the next
2112 // bigger tile size -> see bitmap extraction above. This does no
2113 // harm, since everything right or below our actual area is
2114 // overdrawn by our caller. Just in case we're in the last level,
2115 // we don't draw beyond the right or bottom border.
2116 for( nY=0; nY < aTileInfo.nTilesEmptyY && nY < nExponent*nMSBFactor; nY += nMSBFactor )
2118 aCurrPos.X() = aTileInfo.aNextTileTopLeft.X();
2120 for( nX=0; nX < aTileInfo.nTilesEmptyX && nX < nExponent*nMSBFactor; nX += nMSBFactor )
2122 if( bNoFirstTileDraw )
2123 bNoFirstTileDraw = false; // don't draw first tile position
2124 else if( !aTmpGraphic.Draw( &rVDev, aCurrPos, aTileInfo.aTileSizePixel, pAttr, nFlags ) )
2125 return false;
2127 aCurrPos.X() += aTileInfo.aTileSizePixel.Width();
2130 aCurrPos.Y() += aTileInfo.aTileSizePixel.Height();
2133 #ifdef DBG_TEST
2134 // rVDev.SetFillColor( COL_WHITE );
2135 rVDev.SetFillColor();
2136 rVDev.SetLineColor( Color( 255 * nExponent / nMSBFactor, 255 - 255 * nExponent / nMSBFactor, 128 - 255 * nExponent / nMSBFactor ) );
2137 rVDev.DrawRect( Rectangle((rTileInfo.aTileTopLeft.X())*rTileSizePixel.Width(),
2138 (rTileInfo.aTileTopLeft.Y())*rTileSizePixel.Height(),
2139 (rTileInfo.aNextTileTopLeft.X())*rTileSizePixel.Width()-1,
2140 (rTileInfo.aNextTileTopLeft.Y())*rTileSizePixel.Height()-1) );
2141 #endif
2143 return true;
2146 // -----------------------------------------------------------------------------
2148 bool GraphicObject::ImplDrawTiled( OutputDevice* pOut, const Rectangle& rArea, const Size& rSizePixel,
2149 const Size& rOffset, const GraphicAttr* pAttr, ULONG nFlags, int nTileCacheSize1D )
2151 // how many tiles to generate per recursion step
2152 enum{ SubdivisionExponent=2 };
2154 const MapMode aOutMapMode( pOut->GetMapMode() );
2155 const MapMode aMapMode( aOutMapMode.GetMapUnit(), Point(), aOutMapMode.GetScaleX(), aOutMapMode.GetScaleY() );
2156 bool bRet( false );
2158 // #i42643# Casting to Int64, to avoid integer overflow for
2159 // huge-DPI output devices
2160 if( GetGraphic().GetType() == GRAPHIC_BITMAP &&
2161 static_cast<sal_Int64>(rSizePixel.Width()) * rSizePixel.Height() <
2162 static_cast<sal_Int64>(nTileCacheSize1D)*nTileCacheSize1D )
2164 // First combine very small bitmaps into a larger tile
2165 // ===================================================
2167 VirtualDevice aVDev;
2168 const int nNumTilesInCacheX( (nTileCacheSize1D + rSizePixel.Width()-1) / rSizePixel.Width() );
2169 const int nNumTilesInCacheY( (nTileCacheSize1D + rSizePixel.Height()-1) / rSizePixel.Height() );
2171 aVDev.SetOutputSizePixel( Size( nNumTilesInCacheX*rSizePixel.Width(),
2172 nNumTilesInCacheY*rSizePixel.Height() ) );
2173 aVDev.SetMapMode( aMapMode );
2175 // draw bitmap content
2176 if( ImplRenderTempTile( aVDev, SubdivisionExponent, nNumTilesInCacheX,
2177 nNumTilesInCacheY, rSizePixel, pAttr, nFlags ) )
2179 BitmapEx aTileBitmap( aVDev.GetBitmap( Point(0,0), aVDev.GetOutputSize() ) );
2181 // draw alpha content, if any
2182 if( IsTransparent() )
2184 GraphicObject aAlphaGraphic;
2186 if( GetGraphic().IsAlpha() )
2187 aAlphaGraphic.SetGraphic( GetGraphic().GetBitmapEx().GetAlpha().GetBitmap() );
2188 else
2189 aAlphaGraphic.SetGraphic( GetGraphic().GetBitmapEx().GetMask() );
2191 if( aAlphaGraphic.ImplRenderTempTile( aVDev, SubdivisionExponent, nNumTilesInCacheX,
2192 nNumTilesInCacheY, rSizePixel, pAttr, nFlags ) )
2194 // Combine bitmap and alpha/mask
2195 if( GetGraphic().IsAlpha() )
2196 aTileBitmap = BitmapEx( aTileBitmap.GetBitmap(),
2197 AlphaMask( aVDev.GetBitmap( Point(0,0), aVDev.GetOutputSize() ) ) );
2198 else
2199 aTileBitmap = BitmapEx( aTileBitmap.GetBitmap(),
2200 aVDev.GetBitmap( Point(0,0), aVDev.GetOutputSize() ).CreateMask( Color(COL_WHITE) ) );
2204 // paint generated tile
2205 GraphicObject aTmpGraphic( aTileBitmap );
2206 bRet = aTmpGraphic.ImplDrawTiled( pOut, rArea,
2207 aTileBitmap.GetSizePixel(),
2208 rOffset, pAttr, nFlags, nTileCacheSize1D );
2211 else
2213 const Size aOutOffset( pOut->LogicToPixel( rOffset, aOutMapMode ) );
2214 const Rectangle aOutArea( pOut->LogicToPixel( rArea, aOutMapMode ) );
2216 // number of invisible (because out-of-area) tiles
2217 int nInvisibleTilesX;
2218 int nInvisibleTilesY;
2220 // round towards -infty for negative offset
2221 if( aOutOffset.Width() < 0 )
2222 nInvisibleTilesX = (aOutOffset.Width() - rSizePixel.Width() + 1) / rSizePixel.Width();
2223 else
2224 nInvisibleTilesX = aOutOffset.Width() / rSizePixel.Width();
2226 // round towards -infty for negative offset
2227 if( aOutOffset.Height() < 0 )
2228 nInvisibleTilesY = (aOutOffset.Height() - rSizePixel.Height() + 1) / rSizePixel.Height();
2229 else
2230 nInvisibleTilesY = aOutOffset.Height() / rSizePixel.Height();
2232 // origin from where to 'virtually' start drawing in pixel
2233 const Point aOutOrigin( pOut->LogicToPixel( Point( rArea.Left() - rOffset.Width(),
2234 rArea.Top() - rOffset.Height() ) ) );
2235 // position in pixel from where to really start output
2236 const Point aOutStart( aOutOrigin.X() + nInvisibleTilesX*rSizePixel.Width(),
2237 aOutOrigin.Y() + nInvisibleTilesY*rSizePixel.Height() );
2239 pOut->Push( PUSH_CLIPREGION );
2240 pOut->IntersectClipRegion( rArea );
2242 // Paint all tiles
2243 // ===============
2245 bRet = ImplDrawTiled( *pOut, aOutStart,
2246 (aOutArea.GetWidth() + aOutArea.Left() - aOutStart.X() + rSizePixel.Width() - 1) / rSizePixel.Width(),
2247 (aOutArea.GetHeight() + aOutArea.Top() - aOutStart.Y() + rSizePixel.Height() - 1) / rSizePixel.Height(),
2248 rSizePixel, pAttr, nFlags );
2250 pOut->Pop();
2253 return bRet;
2256 // -----------------------------------------------------------------------------
2258 bool GraphicObject::ImplDrawTiled( OutputDevice& rOut, const Point& rPosPixel,
2259 int nNumTilesX, int nNumTilesY,
2260 const Size& rTileSizePixel, const GraphicAttr* pAttr, ULONG nFlags )
2262 Point aCurrPos( rPosPixel );
2263 Size aTileSizeLogic( rOut.PixelToLogic( rTileSizePixel ) );
2264 int nX, nY;
2266 // #107607# Use logical coordinates for metafile playing, too
2267 bool bDrawInPixel( rOut.GetConnectMetaFile() == NULL && GRAPHIC_BITMAP == GetType() );
2268 BOOL bRet( FALSE );
2270 // #105229# Switch off mapping (converting to logic and back to
2271 // pixel might cause roundoff errors)
2272 BOOL bOldMap( rOut.IsMapModeEnabled() );
2274 if( bDrawInPixel )
2275 rOut.EnableMapMode( FALSE );
2277 for( nY=0; nY < nNumTilesY; ++nY )
2279 aCurrPos.X() = rPosPixel.X();
2281 for( nX=0; nX < nNumTilesX; ++nX )
2283 // #105229# work with pixel coordinates here, mapping is disabled!
2284 // #104004# don't disable mapping for metafile recordings
2285 // #108412# don't quit the loop if one draw fails
2287 // update return value. This method should return true, if
2288 // at least one of the looped Draws succeeded.
2289 bRet |= Draw( &rOut,
2290 bDrawInPixel ? aCurrPos : rOut.PixelToLogic( aCurrPos ),
2291 bDrawInPixel ? rTileSizePixel : aTileSizeLogic,
2292 pAttr, nFlags );
2294 aCurrPos.X() += rTileSizePixel.Width();
2297 aCurrPos.Y() += rTileSizePixel.Height();
2300 if( bDrawInPixel )
2301 rOut.EnableMapMode( bOldMap );
2303 return bRet;
2306 // -----------------------------------------------------------------------------
2308 void GraphicObject::ImplTransformBitmap( BitmapEx& rBmpEx,
2309 const GraphicAttr& rAttr,
2310 const Size& rCropLeftTop,
2311 const Size& rCropRightBottom,
2312 const Rectangle& rCropRect,
2313 const Size& rDstSize,
2314 BOOL bEnlarge ) const
2316 // #107947# Extracted from svdograf.cxx
2318 // #104115# Crop the bitmap
2319 if( rAttr.IsCropped() )
2321 rBmpEx.Crop( rCropRect );
2323 // #104115# Negative crop sizes mean: enlarge bitmap and pad
2324 if( bEnlarge && (
2325 rCropLeftTop.Width() < 0 ||
2326 rCropLeftTop.Height() < 0 ||
2327 rCropRightBottom.Width() < 0 ||
2328 rCropRightBottom.Height() < 0 ) )
2330 Size aBmpSize( rBmpEx.GetSizePixel() );
2331 sal_Int32 nPadLeft( rCropLeftTop.Width() < 0 ? -rCropLeftTop.Width() : 0 );
2332 sal_Int32 nPadTop( rCropLeftTop.Height() < 0 ? -rCropLeftTop.Height() : 0 );
2333 sal_Int32 nPadTotalWidth( aBmpSize.Width() + nPadLeft + (rCropRightBottom.Width() < 0 ? -rCropRightBottom.Width() : 0) );
2334 sal_Int32 nPadTotalHeight( aBmpSize.Height() + nPadTop + (rCropRightBottom.Height() < 0 ? -rCropRightBottom.Height() : 0) );
2336 BitmapEx aBmpEx2;
2338 if( rBmpEx.IsTransparent() )
2340 if( rBmpEx.IsAlpha() )
2341 aBmpEx2 = BitmapEx( rBmpEx.GetBitmap(), rBmpEx.GetAlpha() );
2342 else
2343 aBmpEx2 = BitmapEx( rBmpEx.GetBitmap(), rBmpEx.GetMask() );
2345 else
2347 // #104115# Generate mask bitmap and init to zero
2348 Bitmap aMask( aBmpSize, 1 );
2349 aMask.Erase( Color(0,0,0) );
2351 // #104115# Always generate transparent bitmap, we need the border transparent
2352 aBmpEx2 = BitmapEx( rBmpEx.GetBitmap(), aMask );
2354 // #104115# Add opaque mask to source bitmap, otherwise the destination remains transparent
2355 rBmpEx = aBmpEx2;
2358 aBmpEx2.SetSizePixel( Size(nPadTotalWidth, nPadTotalHeight) );
2359 aBmpEx2.Erase( Color(0xFF,0,0,0) );
2360 aBmpEx2.CopyPixel( Rectangle( Point(nPadLeft, nPadTop), aBmpSize ), Rectangle( Point(0, 0), aBmpSize ), &rBmpEx );
2361 rBmpEx = aBmpEx2;
2365 const Size aSizePixel( rBmpEx.GetSizePixel() );
2367 if( rAttr.GetRotation() != 0 && !IsAnimated() )
2369 if( aSizePixel.Width() && aSizePixel.Height() && rDstSize.Width() && rDstSize.Height() )
2371 double fSrcWH = (double) aSizePixel.Width() / aSizePixel.Height();
2372 double fDstWH = (double) rDstSize.Width() / rDstSize.Height();
2373 double fScaleX = 1.0, fScaleY = 1.0;
2375 // always choose scaling to shrink bitmap
2376 if( fSrcWH < fDstWH )
2377 fScaleY = aSizePixel.Width() / ( fDstWH * aSizePixel.Height() );
2378 else
2379 fScaleX = fDstWH * aSizePixel.Height() / aSizePixel.Width();
2381 rBmpEx.Scale( fScaleX, fScaleY );