summaryrefslogtreecommitdiff
path: root/svtools/source/graphic/grfmgr2.cxx
diff options
context:
space:
mode:
authorMathias Bauer <mba@openoffice.org>2009-12-15 21:55:40 +0100
committerMathias Bauer <mba@openoffice.org>2009-12-15 21:55:40 +0100
commit4770f50e0c8e6706f0f514bd73a8bcfd7dd88cb3 (patch)
treeb21b3409ecc71d4802ab2f5eafd6e01c3bfd5254 /svtools/source/graphic/grfmgr2.cxx
parent003fc5390522ecad9e1f3a2c99b2a0a324ae5473 (diff)
#i107706#: liquidate goodies module
Diffstat (limited to 'svtools/source/graphic/grfmgr2.cxx')
-rw-r--r--svtools/source/graphic/grfmgr2.cxx2385
1 files changed, 2385 insertions, 0 deletions
diff --git a/svtools/source/graphic/grfmgr2.cxx b/svtools/source/graphic/grfmgr2.cxx
new file mode 100644
index 000000000000..03e88a7be6c4
--- /dev/null
+++ b/svtools/source/graphic/grfmgr2.cxx
@@ -0,0 +1,2385 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: grfmgr2.cxx,v $
+ * $Revision: 1.26 $
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_svtools.hxx"
+
+#include <vos/macros.hxx>
+#include <vcl/bmpacc.hxx>
+#include <tools/poly.hxx>
+#include <vcl/outdev.hxx>
+#include <vcl/window.hxx>
+#include <vcl/gdimtf.hxx>
+#include <vcl/metaact.hxx>
+#include <vcl/metric.hxx>
+#include <vcl/animate.hxx>
+#include <vcl/alpha.hxx>
+#include <vcl/virdev.hxx>
+#include "grfcache.hxx"
+#include <svtools/grfmgr.hxx>
+
+// -----------
+// - defines -
+// -----------
+
+#define MAX_PRINTER_EXT 1024
+#define MAP( cVal0, cVal1, nFrac ) ((BYTE)((((long)(cVal0)<<20L)+nFrac*((long)(cVal1)-(cVal0)))>>20L))
+#define WATERMARK_LUM_OFFSET 50
+#define WATERMARK_CON_OFFSET -70
+
+// -----------
+// - helpers -
+// -----------
+
+namespace {
+
+void muckWithBitmap( const Point& rDestPoint,
+ const Size& rDestSize,
+ const Size& rRefSize,
+ bool& o_rbNonBitmapActionEncountered )
+{
+ const Point aEmptyPoint;
+
+ if( aEmptyPoint != rDestPoint ||
+ rDestSize != rRefSize )
+ {
+ // non-fullscale, or offsetted bmp -> fallback to mtf
+ // rendering
+ o_rbNonBitmapActionEncountered = true;
+ }
+}
+
+BitmapEx muckWithBitmap( const BitmapEx& rBmpEx,
+ const Point& rSrcPoint,
+ const Size& rSrcSize,
+ const Point& rDestPoint,
+ const Size& rDestSize,
+ const Size& rRefSize,
+ bool& o_rbNonBitmapActionEncountered )
+{
+ BitmapEx aBmpEx;
+
+ muckWithBitmap(rDestPoint,
+ rDestSize,
+ rRefSize,
+ o_rbNonBitmapActionEncountered);
+
+ if( o_rbNonBitmapActionEncountered )
+ return aBmpEx;
+
+ aBmpEx = rBmpEx;
+
+ if( (rSrcPoint.X() != 0 && rSrcPoint.Y() != 0) ||
+ rSrcSize != rBmpEx.GetSizePixel() )
+ {
+ // crop bitmap to given source rectangle (no
+ // need to copy and convert the whole bitmap)
+ const Rectangle aCropRect( rSrcPoint,
+ rSrcSize );
+ aBmpEx.Crop( aCropRect );
+ }
+
+ return aBmpEx;
+}
+
+} // namespace {
+
+
+// ------------------
+// - GraphicManager -
+// ------------------
+
+GraphicManager::GraphicManager( ULONG nCacheSize, ULONG nMaxObjCacheSize ) :
+ mpCache( new GraphicCache( *this, nCacheSize, nMaxObjCacheSize ) )
+{
+}
+
+// -----------------------------------------------------------------------------
+
+GraphicManager::~GraphicManager()
+{
+ for( void* pObj = maObjList.First(); pObj; pObj = maObjList.Next() )
+ ( (GraphicObject*) pObj )->GraphicManagerDestroyed();
+
+ delete mpCache;
+}
+
+// -----------------------------------------------------------------------------
+
+void GraphicManager::SetMaxCacheSize( ULONG nNewCacheSize )
+{
+ mpCache->SetMaxDisplayCacheSize( nNewCacheSize );
+}
+
+// -----------------------------------------------------------------------------
+
+ULONG GraphicManager::GetMaxCacheSize() const
+{
+ return mpCache->GetMaxDisplayCacheSize();
+}
+
+// -----------------------------------------------------------------------------
+
+void GraphicManager::SetMaxObjCacheSize( ULONG nNewMaxObjSize, BOOL bDestroyGreaterCached )
+{
+ mpCache->SetMaxObjDisplayCacheSize( nNewMaxObjSize, bDestroyGreaterCached );
+}
+
+// -----------------------------------------------------------------------------
+
+ULONG GraphicManager::GetMaxObjCacheSize() const
+{
+ return mpCache->GetMaxObjDisplayCacheSize();
+}
+
+// -----------------------------------------------------------------------------
+
+ULONG GraphicManager::GetUsedCacheSize() const
+{
+ return mpCache->GetUsedDisplayCacheSize();
+}
+
+// -----------------------------------------------------------------------------
+
+ULONG GraphicManager::GetFreeCacheSize() const
+{
+ return mpCache->GetFreeDisplayCacheSize();
+}
+
+// -----------------------------------------------------------------------------
+
+void GraphicManager::SetCacheTimeout( ULONG nTimeoutSeconds )
+{
+ mpCache->SetCacheTimeout( nTimeoutSeconds );
+}
+
+// -----------------------------------------------------------------------------
+
+ULONG GraphicManager::GetCacheTimeout() const
+{
+ return mpCache->GetCacheTimeout();
+}
+
+// -----------------------------------------------------------------------------
+
+void GraphicManager::ClearCache()
+{
+ mpCache->ClearDisplayCache();
+}
+
+// -----------------------------------------------------------------------------
+
+void GraphicManager::ReleaseFromCache( const GraphicObject& /*rObj*/ )
+{
+ // !!!
+}
+
+// -----------------------------------------------------------------------------
+
+BOOL GraphicManager::IsInCache( OutputDevice* pOut, const Point& rPt,
+ const Size& rSz, const GraphicObject& rObj,
+ const GraphicAttr& rAttr ) const
+{
+ return mpCache->IsInDisplayCache( pOut, rPt, rSz, rObj, rAttr );
+}
+
+// -----------------------------------------------------------------------------
+
+BOOL GraphicManager::DrawObj( OutputDevice* pOut, const Point& rPt, const Size& rSz,
+ GraphicObject& rObj, const GraphicAttr& rAttr,
+ const ULONG nFlags, BOOL& rCached )
+{
+ Point aPt( rPt );
+ Size aSz( rSz );
+ BOOL bRet = FALSE;
+
+ rCached = FALSE;
+
+ if( ( rObj.GetType() == GRAPHIC_BITMAP ) || ( rObj.GetType() == GRAPHIC_GDIMETAFILE ) )
+ {
+ // create output and fill cache
+ const Size aOutSize( pOut->GetOutputSizePixel() );
+
+ if( rObj.IsAnimated() || ( pOut->GetOutDevType() == OUTDEV_PRINTER ) ||
+ ( !( nFlags & GRFMGR_DRAW_NO_SUBSTITUTE ) &&
+ ( ( nFlags & GRFMGR_DRAW_SUBSTITUTE ) ||
+ !( nFlags & GRFMGR_DRAW_CACHED ) ||
+ ( pOut->GetConnectMetaFile() && !pOut->IsOutputEnabled() ) ) ) )
+ {
+ // simple output of transformed graphic
+ const Graphic aGraphic( rObj.GetTransformedGraphic( &rAttr ) );
+
+ if( aGraphic.IsSupportedGraphic() )
+ {
+ const USHORT nRot10 = rAttr.GetRotation() % 3600;
+
+ if( nRot10 )
+ {
+ Polygon aPoly( Rectangle( aPt, aSz ) );
+
+ aPoly.Rotate( aPt, nRot10 );
+ const Rectangle aRotBoundRect( aPoly.GetBoundRect() );
+ aPt = aRotBoundRect.TopLeft();
+ aSz = aRotBoundRect.GetSize();
+ }
+
+ aGraphic.Draw( pOut, aPt, aSz );
+ }
+
+ bRet = TRUE;
+ }
+
+ if( !bRet )
+ {
+ // cached/direct drawing
+ if( !mpCache->DrawDisplayCacheObj( pOut, aPt, aSz, rObj, rAttr ) )
+ bRet = ImplDraw( pOut, aPt, aSz, rObj, rAttr, nFlags, rCached );
+ else
+ bRet = rCached = TRUE;
+ }
+ }
+
+ return bRet;
+}
+
+// -----------------------------------------------------------------------------
+
+void GraphicManager::ImplRegisterObj( const GraphicObject& rObj, Graphic& rSubstitute,
+ const ByteString* pID, const GraphicObject* pCopyObj )
+{
+ maObjList.Insert( (void*) &rObj, LIST_APPEND );
+ mpCache->AddGraphicObject( rObj, rSubstitute, pID, pCopyObj );
+}
+
+// -----------------------------------------------------------------------------
+
+void GraphicManager::ImplUnregisterObj( const GraphicObject& rObj )
+{
+ mpCache->ReleaseGraphicObject( rObj );
+ maObjList.Remove( (void*) &rObj );
+}
+
+// -----------------------------------------------------------------------------
+
+void GraphicManager::ImplGraphicObjectWasSwappedOut( const GraphicObject& rObj )
+{
+ mpCache->GraphicObjectWasSwappedOut( rObj );
+}
+
+// -----------------------------------------------------------------------------
+
+ByteString GraphicManager::ImplGetUniqueID( const GraphicObject& rObj ) const
+{
+ return mpCache->GetUniqueID( rObj );
+}
+
+// -----------------------------------------------------------------------------
+
+BOOL GraphicManager::ImplFillSwappedGraphicObject( const GraphicObject& rObj, Graphic& rSubstitute )
+{
+ return( mpCache->FillSwappedGraphicObject( rObj, rSubstitute ) );
+}
+
+// -----------------------------------------------------------------------------
+
+void GraphicManager::ImplGraphicObjectWasSwappedIn( const GraphicObject& rObj )
+{
+ mpCache->GraphicObjectWasSwappedIn( rObj );
+}
+
+// -----------------------------------------------------------------------------
+
+BOOL GraphicManager::ImplDraw( OutputDevice* pOut, const Point& rPt,
+ const Size& rSz, GraphicObject& rObj,
+ const GraphicAttr& rAttr,
+ const ULONG nFlags, BOOL& rCached )
+{
+ const Graphic& rGraphic = rObj.GetGraphic();
+ BOOL bRet = FALSE;
+
+ if( rGraphic.IsSupportedGraphic() && !rGraphic.IsSwapOut() )
+ {
+ if( GRAPHIC_BITMAP == rGraphic.GetType() )
+ {
+ const BitmapEx aSrcBmpEx( rGraphic.GetBitmapEx() );
+
+ // #i46805# No point in caching a bitmap that is rendered
+ // via RectFill on the OutDev
+ if( !(pOut->GetDrawMode() & ( DRAWMODE_BLACKBITMAP | DRAWMODE_WHITEBITMAP )) &&
+ mpCache->IsDisplayCacheable( pOut, rPt, rSz, rObj, rAttr ) )
+ {
+ BitmapEx aDstBmpEx;
+
+ if( ImplCreateOutput( pOut, rPt, rSz, aSrcBmpEx, rAttr, nFlags, &aDstBmpEx ) )
+ {
+ rCached = mpCache->CreateDisplayCacheObj( pOut, rPt, rSz, rObj, rAttr, aDstBmpEx );
+ bRet = TRUE;
+ }
+ }
+
+ if( !bRet )
+ bRet = ImplCreateOutput( pOut, rPt, rSz, aSrcBmpEx, rAttr, nFlags );
+ }
+ else
+ {
+ const GDIMetaFile& rSrcMtf = rGraphic.GetGDIMetaFile();
+
+ if( mpCache->IsDisplayCacheable( pOut, rPt, rSz, rObj, rAttr ) )
+ {
+ GDIMetaFile aDstMtf;
+ BitmapEx aContainedBmpEx;
+
+ if( ImplCreateOutput( pOut, rPt, rSz, rSrcMtf, rAttr, nFlags, aDstMtf, aContainedBmpEx ) )
+ {
+ if( !!aContainedBmpEx )
+ {
+ // #117889# Use bitmap output method, if
+ // metafile basically contains only a single
+ // bitmap
+ BitmapEx aDstBmpEx;
+
+ if( ImplCreateOutput( pOut, rPt, rSz, aContainedBmpEx, rAttr, nFlags, &aDstBmpEx ) )
+ {
+ rCached = mpCache->CreateDisplayCacheObj( pOut, rPt, rSz, rObj, rAttr, aDstBmpEx );
+ bRet = TRUE;
+ }
+ }
+ else
+ {
+ rCached = mpCache->CreateDisplayCacheObj( pOut, rPt, rSz, rObj, rAttr, aDstMtf );
+ bRet = TRUE;
+ }
+ }
+ }
+
+ if( !bRet )
+ {
+ const Graphic aGraphic( rObj.GetTransformedGraphic( &rAttr ) );
+
+ if( aGraphic.IsSupportedGraphic() )
+ {
+ aGraphic.Draw( pOut, rPt, rSz );
+ bRet = TRUE;
+ }
+ }
+ }
+ }
+
+ return bRet;
+}
+
+// -----------------------------------------------------------------------------
+
+BOOL GraphicManager::ImplCreateOutput( OutputDevice* pOut,
+ const Point& rPt, const Size& rSz,
+ const BitmapEx& rBmpEx, const GraphicAttr& rAttr,
+ const ULONG nFlags, BitmapEx* pBmpEx )
+{
+ USHORT nRot10 = rAttr.GetRotation() % 3600;
+ Point aOutPtPix;
+ Size aOutSzPix;
+ Size aUnrotatedSzPix( pOut->LogicToPixel( rSz ) );
+ BOOL bRet = FALSE;
+
+ if( nRot10 )
+ {
+ Polygon aPoly( Rectangle( rPt, rSz ) );
+
+ aPoly.Rotate( rPt, nRot10 );
+ const Rectangle aRotBoundRect( aPoly.GetBoundRect() );
+ aOutPtPix = pOut->LogicToPixel( aRotBoundRect.TopLeft() );
+ aOutSzPix = pOut->LogicToPixel( aRotBoundRect.GetSize() );
+ }
+ else
+ {
+ aOutPtPix = pOut->LogicToPixel( rPt );
+ aOutSzPix = aUnrotatedSzPix;
+ }
+
+ if( aUnrotatedSzPix.Width() && aUnrotatedSzPix.Height() )
+ {
+ BitmapEx aBmpEx( rBmpEx );
+ BitmapEx aOutBmpEx;
+ Point aOutPt;
+ Size aOutSz;
+ const Size& rBmpSzPix = rBmpEx.GetSizePixel();
+ const long nW = rBmpSzPix.Width();
+ const long nH = rBmpSzPix.Height();
+ const long nNewW = aUnrotatedSzPix.Width();
+ const long nNewH = aUnrotatedSzPix.Height();
+ double fTmp;
+ long* pMapIX = new long[ nNewW ];
+ long* pMapFX = new long[ nNewW ];
+ long* pMapIY = new long[ nNewH ];
+ long* pMapFY = new long[ nNewH ];
+ long nStartX = -1, nStartY = -1, nEndX = -1, nEndY = -1;
+ long nX, nY, nTmp, nTmpX, nTmpY;
+ BOOL bHMirr = ( rAttr.GetMirrorFlags() & BMP_MIRROR_HORZ ) != 0;
+ BOOL bVMirr = ( rAttr.GetMirrorFlags() & BMP_MIRROR_VERT ) != 0;
+
+ if( nFlags & GRFMGR_DRAW_BILINEAR )
+ {
+ const double fRevScaleX = ( nNewW > 1L ) ? ( (double) ( nW - 1L ) / ( nNewW - 1L ) ) : 0.0;
+ const double fRevScaleY = ( nNewH > 1L ) ? ( (double) ( nH - 1L ) / ( nNewH - 1L ) ) : 0.0;
+
+ // create horizontal mapping table
+ for( nX = 0L, nTmpX = nW - 1L, nTmp = nW - 2L; nX < nNewW; nX++ )
+ {
+ fTmp = nX * fRevScaleX;
+
+ if( bHMirr )
+ fTmp = nTmpX - fTmp;
+
+ pMapFX[ nX ] = (long) ( ( fTmp - ( pMapIX[ nX ] = MinMax( (long) fTmp, 0, nTmp ) ) ) * 1048576. );
+ }
+
+ // create vertical mapping table
+ for( nY = 0L, nTmpY = nH - 1L, nTmp = nH - 2L; nY < nNewH; nY++ )
+ {
+ fTmp = nY * fRevScaleY;
+
+ if( bVMirr )
+ fTmp = nTmpY - fTmp;
+
+ pMapFY[ nY ] = (long) ( ( fTmp - ( pMapIY[ nY ] = MinMax( (long) fTmp, 0, nTmp ) ) ) * 1048576. );
+ }
+ }
+ else
+ {
+ // #98290# Use a different mapping for non-interpolating mode, to avoid missing rows/columns
+ const double fRevScaleX = ( nNewW > 1L ) ? ( (double) nW / nNewW ) : 0.0;
+ const double fRevScaleY = ( nNewH > 1L ) ? ( (double) nH / nNewH ) : 0.0;
+
+ // create horizontal mapping table
+ for( nX = 0L, nTmpX = nW - 1L, nTmp = nW - 2L; nX < nNewW; nX++ )
+ {
+ fTmp = nX * fRevScaleX;
+
+ if( bHMirr )
+ fTmp = nTmpX - fTmp;
+
+ // #98290# Do not use round to zero, otherwise last column will be missing
+ pMapIX[ nX ] = MinMax( (long) fTmp, 0, nTmp );
+ pMapFX[ nX ] = fTmp >= nTmp+1 ? 1048576 : 0;
+ }
+
+ // create vertical mapping table
+ for( nY = 0L, nTmpY = nH - 1L, nTmp = nH - 2L; nY < nNewH; nY++ )
+ {
+ fTmp = nY * fRevScaleY;
+
+ if( bVMirr )
+ fTmp = nTmpY - fTmp;
+
+ // #98290# Do not use round to zero, otherwise last row will be missing
+ pMapIY[ nY ] = MinMax( (long) fTmp, 0, nTmp );
+ pMapFY[ nY ] = fTmp >= nTmp+1 ? 1048576 : 0;
+ }
+ }
+
+ // calculate output sizes
+ if( !pBmpEx )
+ {
+ Point aPt;
+ Rectangle aOutRect( aPt, pOut->GetOutputSizePixel() );
+ Rectangle aBmpRect( aOutPtPix, aOutSzPix );
+
+ if( pOut->GetOutDevType() == OUTDEV_WINDOW )
+ {
+ const Region aPaintRgn( ( (Window*) pOut )->GetPaintRegion() );
+ if( !aPaintRgn.IsNull() )
+ aOutRect.Intersection( pOut->LogicToPixel( aPaintRgn.GetBoundRect() ) );
+ }
+
+ aOutRect.Intersection( aBmpRect );
+
+ if( !aOutRect.IsEmpty() )
+ {
+ aOutPt = pOut->PixelToLogic( aOutRect.TopLeft() );
+ aOutSz = pOut->PixelToLogic( aOutRect.GetSize() );
+ nStartX = aOutRect.Left() - aBmpRect.Left();
+ nStartY = aOutRect.Top() - aBmpRect.Top();
+ nEndX = aOutRect.Right() - aBmpRect.Left();
+ nEndY = aOutRect.Bottom() - aBmpRect.Top();
+ }
+ else
+ nStartX = -1L; // invalid
+ }
+ else
+ {
+ aOutPt = pOut->PixelToLogic( aOutPtPix );
+ aOutSz = pOut->PixelToLogic( aOutSzPix );
+ nStartX = nStartY = 0;
+ nEndX = aOutSzPix.Width() - 1L;
+ nEndY = aOutSzPix.Height() - 1L;
+ }
+
+ // do transformation
+ if( nStartX >= 0L )
+ {
+ const BOOL bSimple = ( 1 == nW || 1 == nH );
+
+ if( nRot10 )
+ {
+ if( bSimple )
+ {
+ bRet = ( aOutBmpEx = aBmpEx ).Scale( aUnrotatedSzPix );
+
+ if( bRet )
+ aOutBmpEx.Rotate( nRot10, COL_TRANSPARENT );
+ }
+ else
+ {
+ bRet = ImplCreateRotatedScaled( aBmpEx,
+ nRot10, aOutSzPix, aUnrotatedSzPix,
+ pMapIX, pMapFX, pMapIY, pMapFY, nStartX, nEndX, nStartY, nEndY,
+ aOutBmpEx );
+ }
+ }
+ else
+ {
+ // #105229# Don't scale if output size equals bitmap size
+ // #107226# Copy through only if we're not mirroring
+ if( !bHMirr && !bVMirr && aOutSzPix == rBmpSzPix )
+ {
+ // #107226# Use original dimensions when just copying through
+ aOutPt = pOut->PixelToLogic( aOutPtPix );
+ aOutSz = pOut->PixelToLogic( aOutSzPix );
+ aOutBmpEx = aBmpEx;
+ bRet = TRUE;
+ }
+ else
+ {
+ if( bSimple )
+ bRet = ( aOutBmpEx = aBmpEx ).Scale( Size( nEndX - nStartX + 1, nEndY - nStartY + 1 ) );
+ else
+ {
+ bRet = ImplCreateScaled( aBmpEx,
+ pMapIX, pMapFX, pMapIY, pMapFY,
+ nStartX, nEndX, nStartY, nEndY,
+ aOutBmpEx );
+ }
+ }
+ }
+
+ if( bRet )
+ {
+ // attribute adjustment if neccessary
+ if( rAttr.IsSpecialDrawMode() || rAttr.IsAdjusted() || rAttr.IsTransparent() )
+ ImplAdjust( aOutBmpEx, rAttr, ADJUSTMENT_DRAWMODE | ADJUSTMENT_COLORS | ADJUSTMENT_TRANSPARENCY );
+
+ // OutDev adjustment if neccessary
+ if( pOut->GetOutDevType() != OUTDEV_PRINTER && pOut->GetBitCount() <= 8 && aOutBmpEx.GetBitCount() >= 8 )
+ aOutBmpEx.Dither( BMP_DITHER_MATRIX );
+ }
+ }
+
+ // delete lookup tables
+ delete[] pMapIX;
+ delete[] pMapFX;
+ delete[] pMapIY;
+ delete[] pMapFY;
+
+ // create output
+ if( bRet )
+ {
+ if( !pBmpEx )
+ pOut->DrawBitmapEx( aOutPt, aOutSz, aOutBmpEx );
+ else
+ {
+ if( !rAttr.IsTransparent() && !aOutBmpEx.IsAlpha() )
+ aOutBmpEx = BitmapEx( aOutBmpEx.GetBitmap().CreateDisplayBitmap( pOut ), aOutBmpEx.GetMask() );
+
+ pOut->DrawBitmapEx( aOutPt, aOutSz, *pBmpEx = aOutBmpEx );
+ }
+ }
+ }
+
+ return bRet;
+}
+
+// -----------------------------------------------------------------------------
+
+BOOL GraphicManager::ImplCreateOutput( OutputDevice* pOut,
+ const Point& rPt, const Size& rSz,
+ const GDIMetaFile& rMtf, const GraphicAttr& rAttr,
+ const ULONG /*nFlags*/, GDIMetaFile& rOutMtf, BitmapEx& rOutBmpEx )
+{
+ const Size aNewSize( rMtf.GetPrefSize() );
+
+ rOutMtf = rMtf;
+
+ // #117889# count bitmap actions, and flag actions that paint, but
+ // are no bitmaps.
+ sal_Int32 nNumBitmaps(0);
+ bool bNonBitmapActionEncountered(false);
+ if( aNewSize.Width() && aNewSize.Height() && rSz.Width() && rSz.Height() )
+ {
+ const double fGrfWH = (double) aNewSize.Width() / aNewSize.Height();
+ const double fOutWH = (double) rSz.Width() / rSz.Height();
+
+ const double fScaleX = fOutWH / fGrfWH;
+ const double fScaleY = 1.0;
+
+ const MapMode& rPrefMapMode( rMtf.GetPrefMapMode() );
+ const Size& rSizePix( pOut->LogicToPixel( aNewSize,
+ rPrefMapMode ) );
+
+ // taking care of font width default if scaling metafile.
+ // #117889# use existing metafile scan, to determine whether
+ // the metafile basically displays a single bitmap. Note that
+ // the solution, as implemented here, is quite suboptimal (the
+ // cases where a mtf consisting basically of a single bitmap,
+ // that fail to pass the test below, are probably frequent). A
+ // better solution would involve FSAA, but that's currently
+ // expensive, and might trigger bugs on display drivers, if
+ // VDevs get bigger than the actual screen.
+ sal_uInt32 nCurPos;
+ MetaAction* pAct;
+ for( nCurPos = 0, pAct = (MetaAction*)rOutMtf.FirstAction(); pAct;
+ pAct = (MetaAction*)rOutMtf.NextAction(), nCurPos++ )
+ {
+ MetaAction* pModAct = NULL;
+ switch( pAct->GetType() )
+ {
+ case META_FONT_ACTION:
+ {
+ MetaFontAction* pA = (MetaFontAction*)pAct;
+ Font aFont( pA->GetFont() );
+ if ( !aFont.GetWidth() )
+ {
+ FontMetric aFontMetric( pOut->GetFontMetric( aFont ) );
+ aFont.SetWidth( aFontMetric.GetWidth() );
+ pModAct = new MetaFontAction( aFont );
+ }
+ }
+ // FALLTHROUGH intended
+ case META_NULL_ACTION:
+ // FALLTHROUGH intended
+
+ // OutDev state changes (which don't affect bitmap
+ // output)
+ case META_LINECOLOR_ACTION:
+ // FALLTHROUGH intended
+ case META_FILLCOLOR_ACTION:
+ // FALLTHROUGH intended
+ case META_TEXTCOLOR_ACTION:
+ // FALLTHROUGH intended
+ case META_TEXTFILLCOLOR_ACTION:
+ // FALLTHROUGH intended
+ case META_TEXTALIGN_ACTION:
+ // FALLTHROUGH intended
+ case META_TEXTLINECOLOR_ACTION:
+ // FALLTHROUGH intended
+ case META_TEXTLINE_ACTION:
+ // FALLTHROUGH intended
+ case META_PUSH_ACTION:
+ // FALLTHROUGH intended
+ case META_POP_ACTION:
+ // FALLTHROUGH intended
+ case META_LAYOUTMODE_ACTION:
+ // FALLTHROUGH intended
+ case META_TEXTLANGUAGE_ACTION:
+ // FALLTHROUGH intended
+ case META_COMMENT_ACTION:
+ break;
+
+ // bitmap output methods
+ case META_BMP_ACTION:
+ if( !nNumBitmaps && !bNonBitmapActionEncountered )
+ {
+ MetaBmpAction* pAction = (MetaBmpAction*)pAct;
+
+ rOutBmpEx = BitmapEx( pAction->GetBitmap() );
+ muckWithBitmap( pOut->LogicToPixel( pAction->GetPoint(),
+ rPrefMapMode ),
+ pAction->GetBitmap().GetSizePixel(),
+ rSizePix,
+ bNonBitmapActionEncountered );
+ ++nNumBitmaps;
+ }
+ break;
+
+ case META_BMPSCALE_ACTION:
+ if( !nNumBitmaps && !bNonBitmapActionEncountered )
+ {
+ MetaBmpScaleAction* pAction = (MetaBmpScaleAction*)pAct;
+
+ rOutBmpEx = BitmapEx( pAction->GetBitmap() );
+ muckWithBitmap( pOut->LogicToPixel( pAction->GetPoint(),
+ rPrefMapMode ),
+ pOut->LogicToPixel( pAction->GetSize(),
+ rPrefMapMode ),
+ rSizePix,
+ bNonBitmapActionEncountered );
+ ++nNumBitmaps;
+ }
+ break;
+
+ case META_BMPSCALEPART_ACTION:
+ if( !nNumBitmaps && !bNonBitmapActionEncountered )
+ {
+ MetaBmpScalePartAction* pAction = (MetaBmpScalePartAction*)pAct;
+
+ rOutBmpEx = muckWithBitmap( BitmapEx( pAction->GetBitmap() ),
+ pAction->GetSrcPoint(),
+ pAction->GetSrcSize(),
+ pOut->LogicToPixel( pAction->GetDestPoint(),
+ rPrefMapMode ),
+ pOut->LogicToPixel( pAction->GetDestSize(),
+ rPrefMapMode ),
+ rSizePix,
+ bNonBitmapActionEncountered );
+ ++nNumBitmaps;
+ }
+ break;
+
+ case META_BMPEX_ACTION:
+ if( !nNumBitmaps && !bNonBitmapActionEncountered )
+ {
+ MetaBmpExAction* pAction = (MetaBmpExAction*)pAct;
+
+ rOutBmpEx = pAction->GetBitmapEx();
+ muckWithBitmap( pOut->LogicToPixel( pAction->GetPoint(),
+ rPrefMapMode ),
+ pAction->GetBitmapEx().GetSizePixel(),
+ rSizePix,
+ bNonBitmapActionEncountered );
+ ++nNumBitmaps;
+ }
+ break;
+
+ case META_BMPEXSCALE_ACTION:
+ if( !nNumBitmaps && !bNonBitmapActionEncountered )
+ {
+ MetaBmpExScaleAction* pAction = (MetaBmpExScaleAction*)pAct;
+
+ rOutBmpEx = pAction->GetBitmapEx();
+ muckWithBitmap( pOut->LogicToPixel( pAction->GetPoint(),
+ rPrefMapMode ),
+ pOut->LogicToPixel( pAction->GetSize(),
+ rPrefMapMode ),
+ rSizePix,
+ bNonBitmapActionEncountered );
+ ++nNumBitmaps;
+ }
+ break;
+
+ case META_BMPEXSCALEPART_ACTION:
+ if( !nNumBitmaps && !bNonBitmapActionEncountered )
+ {
+ MetaBmpExScalePartAction* pAction = (MetaBmpExScalePartAction*)pAct;
+
+ rOutBmpEx = muckWithBitmap( pAction->GetBitmapEx(),
+ pAction->GetSrcPoint(),
+ pAction->GetSrcSize(),
+ pOut->LogicToPixel( pAction->GetDestPoint(),
+ rPrefMapMode ),
+ pOut->LogicToPixel( pAction->GetDestSize(),
+ rPrefMapMode ),
+ rSizePix,
+ bNonBitmapActionEncountered );
+ ++nNumBitmaps;
+ }
+ break;
+
+ // these actions actually output something (that's
+ // different from a bitmap)
+ case META_RASTEROP_ACTION:
+ if( ((MetaRasterOpAction*)pAct)->GetRasterOp() == ROP_OVERPAINT )
+ break;
+ // FALLTHROUGH intended
+ case META_PIXEL_ACTION:
+ // FALLTHROUGH intended
+ case META_POINT_ACTION:
+ // FALLTHROUGH intended
+ case META_LINE_ACTION:
+ // FALLTHROUGH intended
+ case META_RECT_ACTION:
+ // FALLTHROUGH intended
+ case META_ROUNDRECT_ACTION:
+ // FALLTHROUGH intended
+ case META_ELLIPSE_ACTION:
+ // FALLTHROUGH intended
+ case META_ARC_ACTION:
+ // FALLTHROUGH intended
+ case META_PIE_ACTION:
+ // FALLTHROUGH intended
+ case META_CHORD_ACTION:
+ // FALLTHROUGH intended
+ case META_POLYLINE_ACTION:
+ // FALLTHROUGH intended
+ case META_POLYGON_ACTION:
+ // FALLTHROUGH intended
+ case META_POLYPOLYGON_ACTION:
+ // FALLTHROUGH intended
+
+ case META_TEXT_ACTION:
+ // FALLTHROUGH intended
+ case META_TEXTARRAY_ACTION:
+ // FALLTHROUGH intended
+ case META_STRETCHTEXT_ACTION:
+ // FALLTHROUGH intended
+ case META_TEXTRECT_ACTION:
+ // FALLTHROUGH intended
+
+ case META_MASK_ACTION:
+ // FALLTHROUGH intended
+ case META_MASKSCALE_ACTION:
+ // FALLTHROUGH intended
+ case META_MASKSCALEPART_ACTION:
+ // FALLTHROUGH intended
+
+ case META_GRADIENT_ACTION:
+ // FALLTHROUGH intended
+ case META_HATCH_ACTION:
+ // FALLTHROUGH intended
+ case META_WALLPAPER_ACTION:
+ // FALLTHROUGH intended
+
+ case META_TRANSPARENT_ACTION:
+ // FALLTHROUGH intended
+ case META_EPS_ACTION:
+ // FALLTHROUGH intended
+ case META_FLOATTRANSPARENT_ACTION:
+ // FALLTHROUGH intended
+ case META_GRADIENTEX_ACTION:
+ // FALLTHROUGH intended
+
+ // OutDev state changes that _do_ affect bitmap
+ // output
+ case META_CLIPREGION_ACTION:
+ // FALLTHROUGH intended
+ case META_ISECTRECTCLIPREGION_ACTION:
+ // FALLTHROUGH intended
+ case META_ISECTREGIONCLIPREGION_ACTION:
+ // FALLTHROUGH intended
+ case META_MOVECLIPREGION_ACTION:
+ // FALLTHROUGH intended
+
+ case META_MAPMODE_ACTION:
+ // FALLTHROUGH intended
+ case META_REFPOINT_ACTION:
+ // FALLTHROUGH intended
+ default:
+ bNonBitmapActionEncountered = true;
+ break;
+ }
+ if ( pModAct )
+ {
+ rOutMtf.ReplaceAction( pModAct, nCurPos );
+ pAct->Delete();
+ }
+ else
+ {
+ if( pAct->GetRefCount() > 1 )
+ {
+ rOutMtf.ReplaceAction( pModAct = pAct->Clone(), nCurPos );
+ pAct->Delete();
+ }
+ else
+ pModAct = pAct;
+ }
+ pModAct->Scale( fScaleX, fScaleY );
+ }
+ rOutMtf.SetPrefSize( Size( FRound( aNewSize.Width() * fScaleX ),
+ FRound( aNewSize.Height() * fScaleY ) ) );
+ }
+
+ if( nNumBitmaps != 1 || bNonBitmapActionEncountered )
+ {
+ if( rAttr.IsSpecialDrawMode() || rAttr.IsAdjusted() || rAttr.IsMirrored() || rAttr.IsRotated() || rAttr.IsTransparent() )
+ ImplAdjust( rOutMtf, rAttr, ADJUSTMENT_ALL );
+
+ ImplDraw( pOut, rPt, rSz, rOutMtf, rAttr );
+ rOutBmpEx = BitmapEx();
+ }
+
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------------
+
+BOOL GraphicManager::ImplCreateScaled( const BitmapEx& rBmpEx,
+ long* pMapIX, long* pMapFX, long* pMapIY, long* pMapFY,
+ long nStartX, long nEndX, long nStartY, long nEndY,
+ BitmapEx& rOutBmpEx )
+{
+ Bitmap aBmp( rBmpEx.GetBitmap() );
+ Bitmap aOutBmp;
+ BitmapReadAccess* pAcc = aBmp.AcquireReadAccess();
+ BitmapWriteAccess* pWAcc;
+ BitmapColor aCol0, aCol1, aColRes;
+ const long nDstW = nEndX - nStartX + 1L;
+ const long nDstH = nEndY - nStartY + 1L;
+ long nX, nY, nTmpX, nTmpY, nTmpFX, nTmpFY;
+ long nXDst, nYDst;
+ BYTE cR0, cG0, cB0, cR1, cG1, cB1;
+ BOOL bRet = FALSE;
+
+ DBG_ASSERT( aBmp.GetSizePixel() == rBmpEx.GetSizePixel(),
+ "GraphicManager::ImplCreateScaled(): bmp size inconsistent" );
+
+ if( pAcc )
+ {
+ aOutBmp = Bitmap( Size( nDstW, nDstH ), 24 );
+ pWAcc = aOutBmp.AcquireWriteAccess();
+
+ if( pWAcc )
+ {
+ if( pAcc->HasPalette() )
+ {
+ if( pAcc->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL )
+ {
+ Scanline pLine0, pLine1;
+
+ for( nY = nStartY, nYDst = 0L; nY <= nEndY; nY++, nYDst++ )
+ {
+ nTmpY = pMapIY[ nY ]; nTmpFY = pMapFY[ nY ];
+ pLine0 = pAcc->GetScanline( nTmpY );
+ pLine1 = pAcc->GetScanline( ++nTmpY );
+
+ for( nX = nStartX, nXDst = 0L; nX <= nEndX; nX++ )
+ {
+ nTmpX = pMapIX[ nX ]; nTmpFX = pMapFX[ nX ];
+
+ const BitmapColor& rCol0 = pAcc->GetPaletteColor( pLine0[ nTmpX ] );
+ const BitmapColor& rCol2 = pAcc->GetPaletteColor( pLine1[ nTmpX ] );
+ const BitmapColor& rCol1 = pAcc->GetPaletteColor( pLine0[ ++nTmpX ] );
+ const BitmapColor& rCol3 = pAcc->GetPaletteColor( pLine1[ nTmpX ] );
+
+ cR0 = MAP( rCol0.GetRed(), rCol1.GetRed(), nTmpFX );
+ cG0 = MAP( rCol0.GetGreen(), rCol1.GetGreen(), nTmpFX );
+ cB0 = MAP( rCol0.GetBlue(), rCol1.GetBlue(), nTmpFX );
+
+ cR1 = MAP( rCol2.GetRed(), rCol3.GetRed(), nTmpFX );
+ cG1 = MAP( rCol2.GetGreen(), rCol3.GetGreen(), nTmpFX );
+ cB1 = MAP( rCol2.GetBlue(), rCol3.GetBlue(), nTmpFX );
+
+ aColRes.SetRed( MAP( cR0, cR1, nTmpFY ) );
+ aColRes.SetGreen( MAP( cG0, cG1, nTmpFY ) );
+ aColRes.SetBlue( MAP( cB0, cB1, nTmpFY ) );
+ pWAcc->SetPixel( nYDst, nXDst++, aColRes );
+ }
+ }
+ }
+ else
+ {
+ for( nY = nStartY, nYDst = 0L; nY <= nEndY; nY++, nYDst++ )
+ {
+ nTmpY = pMapIY[ nY ], nTmpFY = pMapFY[ nY ];
+
+ for( nX = nStartX, nXDst = 0L; nX <= nEndX; nX++ )
+ {
+ nTmpX = pMapIX[ nX ]; nTmpFX = pMapFX[ nX ];
+
+ aCol0 = pAcc->GetPaletteColor( pAcc->GetPixel( nTmpY, nTmpX ) );
+ aCol1 = pAcc->GetPaletteColor( pAcc->GetPixel( nTmpY, ++nTmpX ) );
+ cR0 = MAP( aCol0.GetRed(), aCol1.GetRed(), nTmpFX );
+ cG0 = MAP( aCol0.GetGreen(), aCol1.GetGreen(), nTmpFX );
+ cB0 = MAP( aCol0.GetBlue(), aCol1.GetBlue(), nTmpFX );
+
+ aCol1 = pAcc->GetPaletteColor( pAcc->GetPixel( ++nTmpY, nTmpX ) );
+ aCol0 = pAcc->GetPaletteColor( pAcc->GetPixel( nTmpY--, --nTmpX ) );
+ cR1 = MAP( aCol0.GetRed(), aCol1.GetRed(), nTmpFX );
+ cG1 = MAP( aCol0.GetGreen(), aCol1.GetGreen(), nTmpFX );
+ cB1 = MAP( aCol0.GetBlue(), aCol1.GetBlue(), nTmpFX );
+
+ aColRes.SetRed( MAP( cR0, cR1, nTmpFY ) );
+ aColRes.SetGreen( MAP( cG0, cG1, nTmpFY ) );
+ aColRes.SetBlue( MAP( cB0, cB1, nTmpFY ) );
+ pWAcc->SetPixel( nYDst, nXDst++, aColRes );
+ }
+ }
+ }
+ }
+ else
+ {
+ if( pAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_BGR )
+ {
+ Scanline pLine0, pLine1, pTmp0, pTmp1;
+ long nOff;
+
+ for( nY = nStartY, nYDst = 0L; nY <= nEndY; nY++, nYDst++ )
+ {
+ nTmpY = pMapIY[ nY ]; nTmpFY = pMapFY[ nY ];
+ pLine0 = pAcc->GetScanline( nTmpY );
+ pLine1 = pAcc->GetScanline( ++nTmpY );
+
+ for( nX = nStartX, nXDst = 0L; nX <= nEndX; nX++ )
+ {
+ nOff = 3L * ( nTmpX = pMapIX[ nX ] );
+ nTmpFX = pMapFX[ nX ];
+
+ pTmp1 = ( pTmp0 = pLine0 + nOff ) + 3L;
+ cB0 = MAP( *pTmp0, *pTmp1, nTmpFX ); pTmp0++; pTmp1++;
+ cG0 = MAP( *pTmp0, *pTmp1, nTmpFX ); pTmp0++; pTmp1++;
+ cR0 = MAP( *pTmp0, *pTmp1, nTmpFX );
+
+ pTmp1 = ( pTmp0 = pLine1 + nOff ) + 3L;
+ cB1 = MAP( *pTmp0, *pTmp1, nTmpFX ); pTmp0++; pTmp1++;
+ cG1 = MAP( *pTmp0, *pTmp1, nTmpFX ); pTmp0++; pTmp1++;
+ cR1 = MAP( *pTmp0, *pTmp1, nTmpFX );
+
+ aColRes.SetRed( MAP( cR0, cR1, nTmpFY ) );
+ aColRes.SetGreen( MAP( cG0, cG1, nTmpFY ) );
+ aColRes.SetBlue( MAP( cB0, cB1, nTmpFY ) );
+ pWAcc->SetPixel( nYDst, nXDst++, aColRes );
+ }
+ }
+ }
+ else if( pAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_RGB )
+ {
+ Scanline pLine0, pLine1, pTmp0, pTmp1;
+ long nOff;
+
+ for( nY = nStartY, nYDst = 0L; nY <= nEndY; nY++, nYDst++ )
+ {
+ nTmpY = pMapIY[ nY ]; nTmpFY = pMapFY[ nY ];
+ pLine0 = pAcc->GetScanline( nTmpY );
+ pLine1 = pAcc->GetScanline( ++nTmpY );
+
+ for( nX = nStartX, nXDst = 0L; nX <= nEndX; nX++ )
+ {
+ nOff = 3L * ( nTmpX = pMapIX[ nX ] );
+ nTmpFX = pMapFX[ nX ];
+
+ pTmp1 = ( pTmp0 = pLine0 + nOff ) + 3L;
+ cR0 = MAP( *pTmp0, *pTmp1, nTmpFX ); pTmp0++; pTmp1++;
+ cG0 = MAP( *pTmp0, *pTmp1, nTmpFX ); pTmp0++; pTmp1++;
+ cB0 = MAP( *pTmp0, *pTmp1, nTmpFX );
+
+ pTmp1 = ( pTmp0 = pLine1 + nOff ) + 3L;
+ cR1 = MAP( *pTmp0, *pTmp1, nTmpFX ); pTmp0++; pTmp1++;
+ cG1 = MAP( *pTmp0, *pTmp1, nTmpFX ); pTmp0++; pTmp1++;
+ cB1 = MAP( *pTmp0, *pTmp1, nTmpFX );
+
+ aColRes.SetRed( MAP( cR0, cR1, nTmpFY ) );
+ aColRes.SetGreen( MAP( cG0, cG1, nTmpFY ) );
+ aColRes.SetBlue( MAP( cB0, cB1, nTmpFY ) );
+ pWAcc->SetPixel( nYDst, nXDst++, aColRes );
+ }
+ }
+ }
+ else
+ {
+ for( nY = nStartY, nYDst = 0L; nY <= nEndY; nY++, nYDst++ )
+ {
+ nTmpY = pMapIY[ nY ]; nTmpFY = pMapFY[ nY ];
+
+ for( nX = nStartX, nXDst = 0L; nX <= nEndX; nX++ )
+ {
+ nTmpX = pMapIX[ nX ]; nTmpFX = pMapFX[ nX ];
+
+ aCol0 = pAcc->GetPixel( nTmpY, nTmpX );
+ aCol1 = pAcc->GetPixel( nTmpY, ++nTmpX );
+ cR0 = MAP( aCol0.GetRed(), aCol1.GetRed(), nTmpFX );
+ cG0 = MAP( aCol0.GetGreen(), aCol1.GetGreen(), nTmpFX );
+ cB0 = MAP( aCol0.GetBlue(), aCol1.GetBlue(), nTmpFX );
+
+ aCol1 = pAcc->GetPixel( ++nTmpY, nTmpX );
+ aCol0 = pAcc->GetPixel( nTmpY--, --nTmpX );
+ cR1 = MAP( aCol0.GetRed(), aCol1.GetRed(), nTmpFX );
+ cG1 = MAP( aCol0.GetGreen(), aCol1.GetGreen(), nTmpFX );
+ cB1 = MAP( aCol0.GetBlue(), aCol1.GetBlue(), nTmpFX );
+
+ aColRes.SetRed( MAP( cR0, cR1, nTmpFY ) );
+ aColRes.SetGreen( MAP( cG0, cG1, nTmpFY ) );
+ aColRes.SetBlue( MAP( cB0, cB1, nTmpFY ) );
+ pWAcc->SetPixel( nYDst, nXDst++, aColRes );
+ }
+ }
+ }
+ }
+
+ aOutBmp.ReleaseAccess( pWAcc );
+ bRet = TRUE;
+ }
+
+ aBmp.ReleaseAccess( pAcc );
+ }
+
+ if( bRet && rBmpEx.IsTransparent() )
+ {
+ bRet = FALSE;
+
+ if( rBmpEx.IsAlpha() )
+ {
+ DBG_ASSERT( rBmpEx.GetAlpha().GetSizePixel() == rBmpEx.GetSizePixel(),
+ "GraphicManager::ImplCreateScaled(): alpha mask size inconsistent" );
+
+ AlphaMask aAlpha( rBmpEx.GetAlpha() );
+ AlphaMask aOutAlpha;
+
+ pAcc = aAlpha.AcquireReadAccess();
+
+ if( pAcc )
+ {
+ aOutAlpha = AlphaMask( Size( nDstW, nDstH ) );
+ pWAcc = aOutAlpha.AcquireWriteAccess();
+
+ if( pWAcc )
+ {
+ if( pAcc->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL &&
+ pWAcc->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL )
+ {
+ Scanline pLine0, pLine1, pLineW;
+
+ for( nY = nStartY, nYDst = 0L; nY <= nEndY; nY++, nYDst++ )
+ {
+ nTmpY = pMapIY[ nY ]; nTmpFY = pMapFY[ nY ];
+ pLine0 = pAcc->GetScanline( nTmpY );
+ pLine1 = pAcc->GetScanline( ++nTmpY );
+ pLineW = pWAcc->GetScanline( nYDst );
+
+ for( nX = nStartX, nXDst = 0L; nX <= nEndX; nX++, nXDst++ )
+ {
+ nTmpX = pMapIX[ nX ]; nTmpFX = pMapFX[ nX ];
+
+ const long nAlpha0 = pLine0[ nTmpX ];
+ const long nAlpha2 = pLine1[ nTmpX ];
+ const long nAlpha1 = pLine0[ ++nTmpX ];
+ const long nAlpha3 = pLine1[ nTmpX ];
+ const long n0 = MAP( nAlpha0, nAlpha1, nTmpFX );
+ const long n1 = MAP( nAlpha2, nAlpha3, nTmpFX );
+
+ *pLineW++ = MAP( n0, n1, nTmpFY );
+ }
+ }
+ }
+ else
+ {
+ BitmapColor aAlphaValue( 0 );
+
+ for( nY = nStartY, nYDst = 0L; nY <= nEndY; nY++, nYDst++ )
+ {
+ nTmpY = pMapIY[ nY ], nTmpFY = pMapFY[ nY ];
+
+ for( nX = nStartX, nXDst = 0L; nX <= nEndX; nX++ )
+ {
+ nTmpX = pMapIX[ nX ]; nTmpFX = pMapFX[ nX ];
+
+ long nAlpha0 = pAcc->GetPixel( nTmpY, nTmpX ).GetIndex();
+ long nAlpha1 = pAcc->GetPixel( nTmpY, ++nTmpX ).GetIndex();
+ const long n0 = MAP( nAlpha0, nAlpha1, nTmpFX );
+
+ nAlpha1 = pAcc->GetPixel( ++nTmpY, nTmpX ).GetIndex();
+ nAlpha0 = pAcc->GetPixel( nTmpY--, --nTmpX ).GetIndex();
+ const long n1 = MAP( nAlpha0, nAlpha1, nTmpFX );
+
+ aAlphaValue.SetIndex( MAP( n0, n1, nTmpFY ) );
+ pWAcc->SetPixel( nYDst, nXDst++, aAlphaValue );
+ }
+ }
+ }
+
+ aOutAlpha.ReleaseAccess( pWAcc );
+ bRet = TRUE;
+ }
+
+ aAlpha.ReleaseAccess( pAcc );
+
+ if( bRet )
+ rOutBmpEx = BitmapEx( aOutBmp, aOutAlpha );
+ }
+ }
+ else
+ {
+ DBG_ASSERT( rBmpEx.GetMask().GetSizePixel() == rBmpEx.GetSizePixel(),
+ "GraphicManager::ImplCreateScaled(): mask size inconsistent" );
+
+ Bitmap aMsk( rBmpEx.GetMask() );
+ Bitmap aOutMsk;
+
+ pAcc = aMsk.AcquireReadAccess();
+
+ if( pAcc )
+ {
+ // #i40115# Use the same palette for destination
+ // bitmap. Otherwise, we'd have to color-map even the
+ // case below, when both masks are one bit deep.
+ if( pAcc->HasPalette() )
+ aOutMsk = Bitmap( Size( nDstW, nDstH ),
+ 1,
+ &pAcc->GetPalette() );
+ else
+ aOutMsk = Bitmap( Size( nDstW, nDstH ), 1 );
+
+ pWAcc = aOutMsk.AcquireWriteAccess();
+
+ if( pWAcc )
+ {
+ long* pMapLX = new long[ nDstW ];
+ long* pMapLY = new long[ nDstH ];
+
+ // create new horizontal mapping table
+ for( nX = 0UL, nTmpX = nStartX; nX < nDstW; nTmpX++ )
+ pMapLX[ nX++ ] = FRound( (double) pMapIX[ nTmpX ] + pMapFX[ nTmpX ] / 1048576. );
+
+ // create new vertical mapping table
+ for( nY = 0UL, nTmpY = nStartY; nY < nDstH; nTmpY++ )
+ pMapLY[ nY++ ] = FRound( (double) pMapIY[ nTmpY ] + pMapFY[ nTmpY ] / 1048576. );
+
+ // do normal scaling
+ if( pAcc->GetScanlineFormat() == BMP_FORMAT_1BIT_MSB_PAL &&
+ pWAcc->GetScanlineFormat() == BMP_FORMAT_1BIT_MSB_PAL )
+ {
+ // optimized
+ for( nY = 0; nY < nDstH; nY++ )
+ {
+ Scanline pSrc = pAcc->GetScanline( pMapLY[ nY ] );
+ Scanline pDst = pWAcc->GetScanline( nY );
+
+ for( nX = 0L; nX < nDstW; nX++ )
+ {
+ const long nSrcX = pMapLX[ nX ];
+
+ if( pSrc[ nSrcX >> 3 ] & ( 1 << ( 7 - ( nSrcX & 7 ) ) ) )
+ pDst[ nX >> 3 ] |= 1 << ( 7 - ( nX & 7 ) );
+ else
+ pDst[ nX >> 3 ] &= ~( 1 << ( 7 - ( nX & 7 ) ) );
+ }
+ }
+ }
+ else
+ {
+ const BitmapColor aB( pAcc->GetBestMatchingColor( Color( COL_BLACK ) ) );
+ const BitmapColor aWB( pWAcc->GetBestMatchingColor( Color( COL_BLACK ) ) );
+ const BitmapColor aWW( pWAcc->GetBestMatchingColor( Color( COL_WHITE ) ) );
+
+ if( pAcc->HasPalette() )
+ {
+ for( nY = 0L; nY < nDstH; nY++ )
+ {
+ for( nX = 0L; nX < nDstW; nX++ )
+ {
+ if( pAcc->GetPaletteColor( (BYTE) pAcc->GetPixel( pMapLY[ nY ], pMapLX[ nX ] ) ) == aB )
+ pWAcc->SetPixel( nY, nX, aWB );
+ else
+ pWAcc->SetPixel( nY, nX, aWW );
+ }
+ }
+ }
+ else
+ {
+ for( nY = 0L; nY < nDstH; nY++ )
+ {
+ for( nX = 0L; nX < nDstW; nX++ )
+ {
+ if( pAcc->GetPixel( pMapLY[ nY ], pMapLX[ nX ] ) == aB )
+ pWAcc->SetPixel( nY, nX, aWB );
+ else
+ pWAcc->SetPixel( nY, nX, aWW );
+ }
+ }
+ }
+ }
+
+ delete[] pMapLX;
+ delete[] pMapLY;
+ aOutMsk.ReleaseAccess( pWAcc );
+ bRet = TRUE;
+ }
+
+ aMsk.ReleaseAccess( pAcc );
+
+ if( bRet )
+ rOutBmpEx = BitmapEx( aOutBmp, aOutMsk );
+ }
+ }
+
+ if( !bRet )
+ rOutBmpEx = aOutBmp;
+ }
+ else
+ rOutBmpEx = aOutBmp;
+
+ return bRet;
+}
+
+// -----------------------------------------------------------------------------
+
+BOOL GraphicManager::ImplCreateRotatedScaled( const BitmapEx& rBmpEx,
+ USHORT nRot10, const Size& /*rOutSzPix*/, const Size& rUnrotatedSzPix,
+ long* pMapIX, long* pMapFX, long* pMapIY, long* pMapFY,
+ long nStartX, long nEndX, long nStartY, long nEndY,
+ BitmapEx& rOutBmpEx )
+{
+ Point aPt;
+ Bitmap aBmp( rBmpEx.GetBitmap() );
+ Bitmap aOutBmp;
+ BitmapReadAccess* pAcc = aBmp.AcquireReadAccess();
+ BitmapWriteAccess* pWAcc;
+ Polygon aPoly( Rectangle( aPt, rUnrotatedSzPix ) ); aPoly.Rotate( Point(), nRot10 );
+ Rectangle aNewBound( aPoly.GetBoundRect() );
+ const double fCosAngle = cos( nRot10 * F_PI1800 ), fSinAngle = sin( nRot10 * F_PI1800 );
+ double fTmp;
+ const long nDstW = nEndX - nStartX + 1L;
+ const long nDstH = nEndY - nStartY + 1L;
+ const long nUnRotW = rUnrotatedSzPix.Width();
+ const long nUnRotH = rUnrotatedSzPix.Height();
+ long* pCosX = new long[ nDstW ];
+ long* pSinX = new long[ nDstW ];
+ long* pCosY = new long[ nDstH ];
+ long* pSinY = new long[ nDstH ];
+ long nX, nY, nTmpX, nTmpY, nTmpFX, nTmpFY, nUnRotX, nUnRotY, nSinY, nCosY;
+ BYTE cR0, cG0, cB0, cR1, cG1, cB1;
+ BOOL bRet = FALSE;
+
+ // create horizontal mapping table
+ for( nX = 0L, nTmpX = aNewBound.Left() + nStartX; nX < nDstW; nX++ )
+ {
+ pCosX[ nX ] = FRound( fCosAngle * ( fTmp = nTmpX++ << 8 ) );
+ pSinX[ nX ] = FRound( fSinAngle * fTmp );
+ }
+
+ // create vertical mapping table
+ for( nY = 0L, nTmpY = aNewBound.Top() + nStartY; nY < nDstH; nY++ )
+ {
+ pCosY[ nY ] = FRound( fCosAngle * ( fTmp = nTmpY++ << 8 ) );
+ pSinY[ nY ] = FRound( fSinAngle * fTmp );
+ }
+
+ if( pAcc )
+ {
+ aOutBmp = Bitmap( Size( nDstW, nDstH ), 24 );
+ pWAcc = aOutBmp.AcquireWriteAccess();
+
+ if( pWAcc )
+ {
+ BitmapColor aColRes;
+
+ if( pAcc->HasPalette() )
+ {
+ for( nY = 0; nY < nDstH; nY++ )
+ {
+ nSinY = pSinY[ nY ];
+ nCosY = pCosY[ nY ];
+
+ for( nX = 0; nX < nDstW; nX++ )
+ {
+ nUnRotX = ( pCosX[ nX ] - nSinY ) >> 8;
+ nUnRotY = ( pSinX[ nX ] + nCosY ) >> 8;
+
+ if( ( nUnRotX >= 0L ) && ( nUnRotX < nUnRotW ) &&
+ ( nUnRotY >= 0L ) && ( nUnRotY < nUnRotH ) )
+ {
+ nTmpX = pMapIX[ nUnRotX ]; nTmpFX = pMapFX[ nUnRotX ];
+ nTmpY = pMapIY[ nUnRotY ], nTmpFY = pMapFY[ nUnRotY ];
+
+ const BitmapColor& rCol0 = pAcc->GetPaletteColor( pAcc->GetPixel( nTmpY, nTmpX ) );
+ const BitmapColor& rCol1 = pAcc->GetPaletteColor( pAcc->GetPixel( nTmpY, ++nTmpX ) );
+ cR0 = MAP( rCol0.GetRed(), rCol1.GetRed(), nTmpFX );
+ cG0 = MAP( rCol0.GetGreen(), rCol1.GetGreen(), nTmpFX );
+ cB0 = MAP( rCol0.GetBlue(), rCol1.GetBlue(), nTmpFX );
+
+ const BitmapColor& rCol3 = pAcc->GetPaletteColor( pAcc->GetPixel( ++nTmpY, nTmpX ) );
+ const BitmapColor& rCol2 = pAcc->GetPaletteColor( pAcc->GetPixel( nTmpY, --nTmpX ) );
+ cR1 = MAP( rCol2.GetRed(), rCol3.GetRed(), nTmpFX );
+ cG1 = MAP( rCol2.GetGreen(), rCol3.GetGreen(), nTmpFX );
+ cB1 = MAP( rCol2.GetBlue(), rCol3.GetBlue(), nTmpFX );
+
+ aColRes.SetRed( MAP( cR0, cR1, nTmpFY ) );
+ aColRes.SetGreen( MAP( cG0, cG1, nTmpFY ) );
+ aColRes.SetBlue( MAP( cB0, cB1, nTmpFY ) );
+ pWAcc->SetPixel( nY, nX, aColRes );
+ }
+ }
+ }
+ }
+ else
+ {
+ BitmapColor aCol0, aCol1;
+
+ for( nY = 0; nY < nDstH; nY++ )
+ {
+ nSinY = pSinY[ nY ];
+ nCosY = pCosY[ nY ];
+
+ for( nX = 0; nX < nDstW; nX++ )
+ {
+ nUnRotX = ( pCosX[ nX ] - nSinY ) >> 8;
+ nUnRotY = ( pSinX[ nX ] + nCosY ) >> 8;
+
+ if( ( nUnRotX >= 0L ) && ( nUnRotX < nUnRotW ) &&
+ ( nUnRotY >= 0L ) && ( nUnRotY < nUnRotH ) )
+ {
+ nTmpX = pMapIX[ nUnRotX ]; nTmpFX = pMapFX[ nUnRotX ];
+ nTmpY = pMapIY[ nUnRotY ], nTmpFY = pMapFY[ nUnRotY ];
+
+ aCol0 = pAcc->GetPixel( nTmpY, nTmpX );
+ aCol1 = pAcc->GetPixel( nTmpY, ++nTmpX );
+ cR0 = MAP( aCol0.GetRed(), aCol1.GetRed(), nTmpFX );
+ cG0 = MAP( aCol0.GetGreen(), aCol1.GetGreen(), nTmpFX );
+ cB0 = MAP( aCol0.GetBlue(), aCol1.GetBlue(), nTmpFX );
+
+ aCol1 = pAcc->GetPixel( ++nTmpY, nTmpX );
+ aCol0 = pAcc->GetPixel( nTmpY, --nTmpX );
+ cR1 = MAP( aCol0.GetRed(), aCol1.GetRed(), nTmpFX );
+ cG1 = MAP( aCol0.GetGreen(), aCol1.GetGreen(), nTmpFX );
+ cB1 = MAP( aCol0.GetBlue(), aCol1.GetBlue(), nTmpFX );
+
+ aColRes.SetRed( MAP( cR0, cR1, nTmpFY ) );
+ aColRes.SetGreen( MAP( cG0, cG1, nTmpFY ) );
+ aColRes.SetBlue( MAP( cB0, cB1, nTmpFY ) );
+ pWAcc->SetPixel( nY, nX, aColRes );
+ }
+ }
+ }
+ }
+
+ aOutBmp.ReleaseAccess( pWAcc );
+ bRet = TRUE;
+ }
+
+ aBmp.ReleaseAccess( pAcc );
+ }
+
+ // mask processing
+ if( bRet && ( rBmpEx.IsTransparent() || ( nRot10 != 900 && nRot10 != 1800 && nRot10 != 2700 ) ) )
+ {
+ bRet = FALSE;
+
+ if( rBmpEx.IsAlpha() )
+ {
+ AlphaMask aAlpha( rBmpEx.GetAlpha() );
+ AlphaMask aOutAlpha;
+
+ pAcc = aAlpha.AcquireReadAccess();
+
+ if( pAcc )
+ {
+ aOutAlpha = AlphaMask( Size( nDstW, nDstH ) );
+ pWAcc = aOutAlpha.AcquireWriteAccess();
+
+ if( pWAcc )
+ {
+ if( pAcc->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL &&
+ pWAcc->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL )
+ {
+ Scanline pLine0, pLine1, pLineW;
+
+ for( nY = 0; nY < nDstH; nY++ )
+ {
+ nSinY = pSinY[ nY ], nCosY = pCosY[ nY ];
+ pLineW = pWAcc->GetScanline( nY );
+
+ for( nX = 0; nX < nDstW; nX++ )
+ {
+ nUnRotX = ( pCosX[ nX ] - nSinY ) >> 8;
+ nUnRotY = ( pSinX[ nX ] + nCosY ) >> 8;
+
+ if( ( nUnRotX >= 0L ) && ( nUnRotX < nUnRotW ) &&
+ ( nUnRotY >= 0L ) && ( nUnRotY < nUnRotH ) )
+ {
+ nTmpX = pMapIX[ nUnRotX ], nTmpFX = pMapFX[ nUnRotX ];
+ nTmpY = pMapIY[ nUnRotY ], nTmpFY = pMapFY[ nUnRotY ];
+
+ pLine0 = pAcc->GetScanline( nTmpY++ );
+ pLine1 = pAcc->GetScanline( nTmpY );
+
+ const long nAlpha0 = pLine0[ nTmpX ];
+ const long nAlpha2 = pLine1[ nTmpX++ ];
+ const long nAlpha1 = pLine0[ nTmpX ];
+ const long nAlpha3 = pLine1[ nTmpX ];
+ const long n0 = MAP( nAlpha0, nAlpha1, nTmpFX );
+ const long n1 = MAP( nAlpha2, nAlpha3, nTmpFX );
+
+ *pLineW++ = MAP( n0, n1, nTmpFY );
+ }
+ else
+ *pLineW++ = 255;
+ }
+ }
+ }
+ else
+ {
+ const BitmapColor aTrans( pWAcc->GetBestMatchingColor( Color( COL_WHITE ) ) );
+ BitmapColor aAlphaVal( 0 );
+
+ for( nY = 0; nY < nDstH; nY++ )
+ {
+ nSinY = pSinY[ nY ], nCosY = pCosY[ nY ];
+
+ for( nX = 0; nX < nDstW; nX++ )
+ {
+ nUnRotX = ( pCosX[ nX ] - nSinY ) >> 8;
+ nUnRotY = ( pSinX[ nX ] + nCosY ) >> 8;
+
+ if( ( nUnRotX >= 0L ) && ( nUnRotX < nUnRotW ) &&
+ ( nUnRotY >= 0L ) && ( nUnRotY < nUnRotH ) )
+ {
+ nTmpX = pMapIX[ nUnRotX ]; nTmpFX = pMapFX[ nUnRotX ];
+ nTmpY = pMapIY[ nUnRotY ], nTmpFY = pMapFY[ nUnRotY ];
+
+ const long nAlpha0 = pAcc->GetPixel( nTmpY, nTmpX ).GetIndex();
+ const long nAlpha1 = pAcc->GetPixel( nTmpY, ++nTmpX ).GetIndex();
+ const long nAlpha3 = pAcc->GetPixel( ++nTmpY, nTmpX ).GetIndex();
+ const long nAlpha2 = pAcc->GetPixel( nTmpY, --nTmpX ).GetIndex();
+ const long n0 = MAP( nAlpha0, nAlpha1, nTmpFX );
+ const long n1 = MAP( nAlpha2, nAlpha3, nTmpFX );
+
+ aAlphaVal.SetIndex( MAP( n0, n1, nTmpFY ) );
+ pWAcc->SetPixel( nY, nX, aAlphaVal );
+ }
+ else
+ pWAcc->SetPixel( nY, nX, aTrans );
+ }
+ }
+ }
+
+ aOutAlpha.ReleaseAccess( pWAcc );
+ bRet = TRUE;
+ }
+
+ aAlpha.ReleaseAccess( pAcc );
+ }
+
+ if( bRet )
+ rOutBmpEx = BitmapEx( aOutBmp, aOutAlpha );
+ }
+ else
+ {
+ Bitmap aOutMsk( Size( nDstW, nDstH ), 1 );
+ pWAcc = aOutMsk.AcquireWriteAccess();
+
+ if( pWAcc )
+ {
+ Bitmap aMsk( rBmpEx.GetMask() );
+ const BitmapColor aB( pWAcc->GetBestMatchingColor( Color( COL_BLACK ) ) );
+ const BitmapColor aW( pWAcc->GetBestMatchingColor( Color( COL_WHITE ) ) );
+ BitmapReadAccess* pMAcc = NULL;
+
+ if( !aMsk || ( ( pMAcc = aMsk.AcquireReadAccess() ) != NULL ) )
+ {
+ long* pMapLX = new long[ nUnRotW ];
+ long* pMapLY = new long[ nUnRotH ];
+ BitmapColor aTestB;
+
+ if( pMAcc )
+ aTestB = pMAcc->GetBestMatchingColor( Color( COL_BLACK ) );
+
+ // create new horizontal mapping table
+ for( nX = 0UL; nX < nUnRotW; nX++ )
+ pMapLX[ nX ] = FRound( (double) pMapIX[ nX ] + pMapFX[ nX ] / 1048576. );
+
+ // create new vertical mapping table
+ for( nY = 0UL; nY < nUnRotH; nY++ )
+ pMapLY[ nY ] = FRound( (double) pMapIY[ nY ] + pMapFY[ nY ] / 1048576. );
+
+ // do mask rotation
+ for( nY = 0; nY < nDstH; nY++ )
+ {
+ nSinY = pSinY[ nY ];
+ nCosY = pCosY[ nY ];
+
+ for( nX = 0; nX < nDstW; nX++ )
+ {
+ nUnRotX = ( pCosX[ nX ] - nSinY ) >> 8;
+ nUnRotY = ( pSinX[ nX ] + nCosY ) >> 8;
+
+ if( ( nUnRotX >= 0L ) && ( nUnRotX < nUnRotW ) &&
+ ( nUnRotY >= 0L ) && ( nUnRotY < nUnRotH ) )
+ {
+ if( pMAcc )
+ {
+ if( pMAcc->GetPixel( pMapLY[ nUnRotY ], pMapLX[ nUnRotX ] ) == aTestB )
+ pWAcc->SetPixel( nY, nX, aB );
+ else
+ pWAcc->SetPixel( nY, nX, aW );
+ }
+ else
+ pWAcc->SetPixel( nY, nX, aB );
+ }
+ else
+ pWAcc->SetPixel( nY, nX, aW );
+ }
+ }
+
+ delete[] pMapLX;
+ delete[] pMapLY;
+
+ if( pMAcc )
+ aMsk.ReleaseAccess( pMAcc );
+
+ bRet = TRUE;
+ }
+
+ aOutMsk.ReleaseAccess( pWAcc );
+ }
+
+ if( bRet )
+ rOutBmpEx = BitmapEx( aOutBmp, aOutMsk );
+ }
+
+ if( !bRet )
+ rOutBmpEx = aOutBmp;
+ }
+ else
+ rOutBmpEx = aOutBmp;
+
+ delete[] pSinX;
+ delete[] pCosX;
+ delete[] pSinY;
+ delete[] pCosY;
+
+ return bRet;
+}
+
+// -----------------------------------------------------------------------------
+
+void GraphicManager::ImplAdjust( BitmapEx& rBmpEx, const GraphicAttr& rAttr, ULONG nAdjustmentFlags )
+{
+ GraphicAttr aAttr( rAttr );
+
+ if( ( nAdjustmentFlags & ADJUSTMENT_DRAWMODE ) && aAttr.IsSpecialDrawMode() )
+ {
+ switch( aAttr.GetDrawMode() )
+ {
+ case( GRAPHICDRAWMODE_MONO ):
+ rBmpEx.Convert( BMP_CONVERSION_1BIT_THRESHOLD );
+ break;
+
+ case( GRAPHICDRAWMODE_GREYS ):
+ rBmpEx.Convert( BMP_CONVERSION_8BIT_GREYS );
+ break;
+
+ case( GRAPHICDRAWMODE_WATERMARK ):
+ {
+ aAttr.SetLuminance( aAttr.GetLuminance() + WATERMARK_LUM_OFFSET );
+ aAttr.SetContrast( aAttr.GetContrast() + WATERMARK_CON_OFFSET );
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if( ( nAdjustmentFlags & ADJUSTMENT_COLORS ) && aAttr.IsAdjusted() )
+ {
+ rBmpEx.Adjust( aAttr.GetLuminance(), aAttr.GetContrast(),
+ aAttr.GetChannelR(), aAttr.GetChannelG(), aAttr.GetChannelB(),
+ aAttr.GetGamma(), aAttr.IsInvert() );
+ }
+
+ if( ( nAdjustmentFlags & ADJUSTMENT_MIRROR ) && aAttr.IsMirrored() )
+ {
+ rBmpEx.Mirror( aAttr.GetMirrorFlags() );
+ }
+
+ if( ( nAdjustmentFlags & ADJUSTMENT_ROTATE ) && aAttr.IsRotated() )
+ {
+ rBmpEx.Rotate( aAttr.GetRotation(), Color( COL_TRANSPARENT ) );
+ }
+
+ if( ( nAdjustmentFlags & ADJUSTMENT_TRANSPARENCY ) && aAttr.IsTransparent() )
+ {
+ AlphaMask aAlpha;
+ BYTE cTrans = aAttr.GetTransparency();
+
+ if( !rBmpEx.IsTransparent() )
+ aAlpha = AlphaMask( rBmpEx.GetSizePixel(), &cTrans );
+ else if( !rBmpEx.IsAlpha() )
+ {
+ aAlpha = rBmpEx.GetMask();
+ aAlpha.Replace( 0, cTrans );
+ }
+ else
+ {
+ aAlpha = rBmpEx.GetAlpha();
+ BitmapWriteAccess* pA = aAlpha.AcquireWriteAccess();
+
+ if( pA )
+ {
+ ULONG nTrans = cTrans, nNewTrans;
+ const long nWidth = pA->Width(), nHeight = pA->Height();
+
+ if( pA->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL )
+ {
+ for( long nY = 0; nY < nHeight; nY++ )
+ {
+ Scanline pAScan = pA->GetScanline( nY );
+
+ for( long nX = 0; nX < nWidth; nX++ )
+ {
+ nNewTrans = nTrans + *pAScan;
+ *pAScan++ = (BYTE) ( ( nNewTrans & 0xffffff00 ) ? 255 : nNewTrans );
+ }
+ }
+ }
+ else
+ {
+ BitmapColor aAlphaValue( 0 );
+
+ for( long nY = 0; nY < nHeight; nY++ )
+ {
+ for( long nX = 0; nX < nWidth; nX++ )
+ {
+ nNewTrans = nTrans + pA->GetPixel( nY, nX ).GetIndex();
+ aAlphaValue.SetIndex( (BYTE) ( ( nNewTrans & 0xffffff00 ) ? 255 : nNewTrans ) );
+ pA->SetPixel( nY, nX, aAlphaValue );
+ }
+ }
+ }
+
+ aAlpha.ReleaseAccess( pA );
+ }
+ }
+
+ rBmpEx = BitmapEx( rBmpEx.GetBitmap(), aAlpha );
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+void GraphicManager::ImplAdjust( GDIMetaFile& rMtf, const GraphicAttr& rAttr, ULONG nAdjustmentFlags )
+{
+ GraphicAttr aAttr( rAttr );
+
+ if( ( nAdjustmentFlags & ADJUSTMENT_DRAWMODE ) && aAttr.IsSpecialDrawMode() )
+ {
+ switch( aAttr.GetDrawMode() )
+ {
+ case( GRAPHICDRAWMODE_MONO ):
+ rMtf.Convert( MTF_CONVERSION_1BIT_THRESHOLD );
+ break;
+
+ case( GRAPHICDRAWMODE_GREYS ):
+ rMtf.Convert( MTF_CONVERSION_8BIT_GREYS );
+ break;
+
+ case( GRAPHICDRAWMODE_WATERMARK ):
+ {
+ aAttr.SetLuminance( aAttr.GetLuminance() + WATERMARK_LUM_OFFSET );
+ aAttr.SetContrast( aAttr.GetContrast() + WATERMARK_CON_OFFSET );
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if( ( nAdjustmentFlags & ADJUSTMENT_COLORS ) && aAttr.IsAdjusted() )
+ {
+ rMtf.Adjust( aAttr.GetLuminance(), aAttr.GetContrast(),
+ aAttr.GetChannelR(), aAttr.GetChannelG(), aAttr.GetChannelB(),
+ aAttr.GetGamma(), aAttr.IsInvert() );
+ }
+
+ if( ( nAdjustmentFlags & ADJUSTMENT_MIRROR ) && aAttr.IsMirrored() )
+ {
+ rMtf.Mirror( aAttr.GetMirrorFlags() );
+ }
+
+ if( ( nAdjustmentFlags & ADJUSTMENT_ROTATE ) && aAttr.IsRotated() )
+ {
+ rMtf.Rotate( aAttr.GetRotation() );
+ }
+
+ if( ( nAdjustmentFlags & ADJUSTMENT_TRANSPARENCY ) && aAttr.IsTransparent() )
+ {
+ DBG_ERROR( "Missing implementation: Mtf-Transparency" );
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+void GraphicManager::ImplAdjust( Animation& rAnimation, const GraphicAttr& rAttr, ULONG nAdjustmentFlags )
+{
+ GraphicAttr aAttr( rAttr );
+
+ if( ( nAdjustmentFlags & ADJUSTMENT_DRAWMODE ) && aAttr.IsSpecialDrawMode() )
+ {
+ switch( aAttr.GetDrawMode() )
+ {
+ case( GRAPHICDRAWMODE_MONO ):
+ rAnimation.Convert( BMP_CONVERSION_1BIT_THRESHOLD );
+ break;
+
+ case( GRAPHICDRAWMODE_GREYS ):
+ rAnimation.Convert( BMP_CONVERSION_8BIT_GREYS );
+ break;
+
+ case( GRAPHICDRAWMODE_WATERMARK ):
+ {
+ aAttr.SetLuminance( aAttr.GetLuminance() + WATERMARK_LUM_OFFSET );
+ aAttr.SetContrast( aAttr.GetContrast() + WATERMARK_CON_OFFSET );
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if( ( nAdjustmentFlags & ADJUSTMENT_COLORS ) && aAttr.IsAdjusted() )
+ {
+ rAnimation.Adjust( aAttr.GetLuminance(), aAttr.GetContrast(),
+ aAttr.GetChannelR(), aAttr.GetChannelG(), aAttr.GetChannelB(),
+ aAttr.GetGamma(), aAttr.IsInvert() );
+ }
+
+ if( ( nAdjustmentFlags & ADJUSTMENT_MIRROR ) && aAttr.IsMirrored() )
+ {
+ rAnimation.Mirror( aAttr.GetMirrorFlags() );
+ }
+
+ if( ( nAdjustmentFlags & ADJUSTMENT_ROTATE ) && aAttr.IsRotated() )
+ {
+ DBG_ERROR( "Missing implementation: Animation-Rotation" );
+ }
+
+ if( ( nAdjustmentFlags & ADJUSTMENT_TRANSPARENCY ) && aAttr.IsTransparent() )
+ {
+ DBG_ERROR( "Missing implementation: Animation-Transparency" );
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+void GraphicManager::ImplDraw( OutputDevice* pOut, const Point& rPt, const Size& rSz,
+ const GDIMetaFile& rMtf, const GraphicAttr& rAttr )
+{
+ USHORT nRot10 = rAttr.GetRotation() % 3600;
+ Point aOutPt( rPt );
+ Size aOutSz( rSz );
+
+ if( nRot10 )
+ {
+ Polygon aPoly( Rectangle( aOutPt, aOutSz ) );
+
+ aPoly.Rotate( aOutPt, nRot10 );
+ const Rectangle aRotBoundRect( aPoly.GetBoundRect() );
+ aOutPt = aRotBoundRect.TopLeft();
+ aOutSz = aRotBoundRect.GetSize();
+ }
+
+ pOut->Push( PUSH_CLIPREGION );
+ pOut->IntersectClipRegion( Rectangle( aOutPt, aOutSz ) );
+
+ ( (GDIMetaFile&) rMtf ).WindStart();
+ ( (GDIMetaFile&) rMtf ).Play( pOut, aOutPt, aOutSz );
+ ( (GDIMetaFile&) rMtf ).WindStart();
+
+ pOut->Pop();
+}
+
+// -----------------------------------------------------------------------------
+
+struct ImplTileInfo
+{
+ ImplTileInfo() : aTileTopLeft(), aNextTileTopLeft(), aTileSizePixel(), nTilesEmptyX(0), nTilesEmptyY(0) {}
+
+ Point aTileTopLeft; // top, left position of the rendered tile
+ Point aNextTileTopLeft; // top, left position for next recursion
+ // level's tile
+ Size aTileSizePixel; // size of the generated tile (might
+ // differ from
+ // aNextTileTopLeft-aTileTopLeft, because
+ // this is nExponent*prevTileSize. The
+ // generated tile is always nExponent
+ // times the previous tile, such that it
+ // can be used in the next stage. The
+ // required area coverage is often
+ // less. The extraneous area covered is
+ // later overwritten by the next stage)
+ int nTilesEmptyX; // number of original tiles empty right of
+ // this tile. This counts from
+ // aNextTileTopLeft, i.e. the additional
+ // area covered by aTileSizePixel is not
+ // considered here. This is for
+ // unification purposes, as the iterative
+ // calculation of the next level's empty
+ // tiles has to be based on this value.
+ int nTilesEmptyY; // as above, for Y
+};
+
+
+bool GraphicObject::ImplRenderTempTile( VirtualDevice& rVDev, int nExponent,
+ int nNumTilesX, int nNumTilesY,
+ const Size& rTileSizePixel,
+ const GraphicAttr* pAttr, ULONG nFlags )
+{
+ if( nExponent <= 1 )
+ return false;
+
+ // determine MSB factor
+ int nMSBFactor( 1 );
+ while( nNumTilesX / nMSBFactor != 0 ||
+ nNumTilesY / nMSBFactor != 0 )
+ {
+ nMSBFactor *= nExponent;
+ }
+
+ // one less
+ nMSBFactor /= nExponent;
+
+ ImplTileInfo aTileInfo;
+
+ // #105229# Switch off mapping (converting to logic and back to
+ // pixel might cause roundoff errors)
+ BOOL bOldMap( rVDev.IsMapModeEnabled() );
+ rVDev.EnableMapMode( FALSE );
+
+ bool bRet( ImplRenderTileRecursive( rVDev, nExponent, nMSBFactor, nNumTilesX, nNumTilesY,
+ nNumTilesX, nNumTilesY, rTileSizePixel, pAttr, nFlags, aTileInfo ) );
+
+ rVDev.EnableMapMode( bOldMap );
+
+ return bRet;
+}
+
+// -----------------------------------------------------------------------------
+
+// define for debug drawings
+//#define DBG_TEST
+
+// see header comment. this works similar to base conversion of a
+// number, i.e. if the exponent is 10, then the number for every tile
+// size is given by the decimal place of the corresponding decimal
+// representation.
+bool GraphicObject::ImplRenderTileRecursive( VirtualDevice& rVDev, int nExponent, int nMSBFactor,
+ int nNumOrigTilesX, int nNumOrigTilesY,
+ int nRemainderTilesX, int nRemainderTilesY,
+ const Size& rTileSizePixel, const GraphicAttr* pAttr,
+ ULONG nFlags, ImplTileInfo& rTileInfo )
+{
+ // gets loaded with our tile bitmap
+ GraphicObject aTmpGraphic;
+
+ // stores a flag that renders the zero'th tile position
+ // (i.e. (0,0)+rCurrPos) only if we're at the bottom of the
+ // recursion stack. All other position already have that tile
+ // rendered, because the lower levels painted their generated tile
+ // there.
+ bool bNoFirstTileDraw( false );
+
+ // what's left when we're done with our tile size
+ const int nNewRemainderX( nRemainderTilesX % nMSBFactor );
+ const int nNewRemainderY( nRemainderTilesY % nMSBFactor );
+
+ // gets filled out from the recursive call with info of what's
+ // been generated
+ ImplTileInfo aTileInfo;
+
+ // current output position while drawing
+ Point aCurrPos;
+ int nX, nY;
+
+ // check for recursion's end condition: LSB place reached?
+ if( nMSBFactor == 1 )
+ {
+ aTmpGraphic = *this;
+
+ // set initial tile size -> orig size
+ aTileInfo.aTileSizePixel = rTileSizePixel;
+ aTileInfo.nTilesEmptyX = nNumOrigTilesX;
+ aTileInfo.nTilesEmptyY = nNumOrigTilesY;
+ }
+ else if( ImplRenderTileRecursive( rVDev, nExponent, nMSBFactor/nExponent,
+ nNumOrigTilesX, nNumOrigTilesY,
+ nNewRemainderX, nNewRemainderY,
+ rTileSizePixel, pAttr, nFlags, aTileInfo ) )
+ {
+ // extract generated tile -> see comment on the first loop below
+ BitmapEx aTileBitmap( rVDev.GetBitmap( aTileInfo.aTileTopLeft, aTileInfo.aTileSizePixel ) );
+
+ aTmpGraphic = GraphicObject( aTileBitmap );
+
+ // fill stripes left over from upstream levels:
+ //
+ // x0000
+ // 0
+ // 0
+ // 0
+ // 0
+ //
+ // where x denotes the place filled by our recursive predecessors
+
+ // check whether we have to fill stripes here. Although not
+ // obvious, there is one case where we can skip this step: if
+ // the previous recursion level (the one who filled our
+ // aTileInfo) had zero area to fill, then there are no white
+ // stripes left, naturally. This happens if the digit
+ // associated to that level has a zero, and can be checked via
+ // aTileTopLeft==aNextTileTopLeft.
+ if( aTileInfo.aTileTopLeft != aTileInfo.aNextTileTopLeft )
+ {
+ // now fill one row from aTileInfo.aNextTileTopLeft.X() all
+ // the way to the right
+ aCurrPos.X() = aTileInfo.aNextTileTopLeft.X();
+ aCurrPos.Y() = aTileInfo.aTileTopLeft.Y();
+ for( nX=0; nX < aTileInfo.nTilesEmptyX; nX += nMSBFactor )
+ {
+ if( !aTmpGraphic.Draw( &rVDev, aCurrPos, aTileInfo.aTileSizePixel, pAttr, nFlags ) )
+ return false;
+
+ aCurrPos.X() += aTileInfo.aTileSizePixel.Width();
+ }
+
+#ifdef DBG_TEST
+// rVDev.SetFillColor( COL_WHITE );
+ rVDev.SetFillColor();
+ rVDev.SetLineColor( Color( 255 * nExponent / nMSBFactor, 255 - 255 * nExponent / nMSBFactor, 128 - 255 * nExponent / nMSBFactor ) );
+ rVDev.DrawEllipse( Rectangle(aTileInfo.aNextTileTopLeft.X(), aTileInfo.aTileTopLeft.Y(),
+ aTileInfo.aNextTileTopLeft.X() - 1 + (aTileInfo.nTilesEmptyX/nMSBFactor)*aTileInfo.aTileSizePixel.Width(),
+ aTileInfo.aTileTopLeft.Y() + aTileInfo.aTileSizePixel.Height() - 1) );
+#endif
+
+ // now fill one column from aTileInfo.aNextTileTopLeft.Y() all
+ // the way to the bottom
+ aCurrPos.X() = aTileInfo.aTileTopLeft.X();
+ aCurrPos.Y() = aTileInfo.aNextTileTopLeft.Y();
+ for( nY=0; nY < aTileInfo.nTilesEmptyY; nY += nMSBFactor )
+ {
+ if( !aTmpGraphic.Draw( &rVDev, aCurrPos, aTileInfo.aTileSizePixel, pAttr, nFlags ) )
+ return false;
+
+ aCurrPos.Y() += aTileInfo.aTileSizePixel.Height();
+ }
+
+#ifdef DBG_TEST
+ rVDev.DrawEllipse( Rectangle(aTileInfo.aTileTopLeft.X(), aTileInfo.aNextTileTopLeft.Y(),
+ aTileInfo.aTileTopLeft.X() + aTileInfo.aTileSizePixel.Width() - 1,
+ aTileInfo.aNextTileTopLeft.Y() - 1 + (aTileInfo.nTilesEmptyY/nMSBFactor)*aTileInfo.aTileSizePixel.Height()) );
+#endif
+ }
+ else
+ {
+ // Thought that aTileInfo.aNextTileTopLeft tile has always
+ // been drawn already, but that's wrong: typically,
+ // _parts_ of that tile have been drawn, since the
+ // previous level generated the tile there. But when
+ // aTileInfo.aNextTileTopLeft!=aTileInfo.aTileTopLeft, the
+ // difference between these two values is missing in the
+ // lower right corner of this first tile. So, can do that
+ // only here.
+ bNoFirstTileDraw = true;
+ }
+ }
+ else
+ {
+ return false;
+ }
+
+ // calc number of original tiles in our drawing area without
+ // remainder
+ nRemainderTilesX -= nNewRemainderX;
+ nRemainderTilesY -= nNewRemainderY;
+
+ // fill tile info for calling method
+ rTileInfo.aTileTopLeft = aTileInfo.aNextTileTopLeft;
+ rTileInfo.aNextTileTopLeft = Point( rTileInfo.aTileTopLeft.X() + rTileSizePixel.Width()*nRemainderTilesX,
+ rTileInfo.aTileTopLeft.Y() + rTileSizePixel.Height()*nRemainderTilesY );
+ rTileInfo.aTileSizePixel = Size( rTileSizePixel.Width()*nMSBFactor*nExponent,
+ rTileSizePixel.Height()*nMSBFactor*nExponent );
+ rTileInfo.nTilesEmptyX = aTileInfo.nTilesEmptyX - nRemainderTilesX;
+ rTileInfo.nTilesEmptyY = aTileInfo.nTilesEmptyY - nRemainderTilesY;
+
+ // init output position
+ aCurrPos = aTileInfo.aNextTileTopLeft;
+
+ // fill our drawing area. Fill possibly more, to create the next
+ // bigger tile size -> see bitmap extraction above. This does no
+ // harm, since everything right or below our actual area is
+ // overdrawn by our caller. Just in case we're in the last level,
+ // we don't draw beyond the right or bottom border.
+ for( nY=0; nY < aTileInfo.nTilesEmptyY && nY < nExponent*nMSBFactor; nY += nMSBFactor )
+ {
+ aCurrPos.X() = aTileInfo.aNextTileTopLeft.X();
+
+ for( nX=0; nX < aTileInfo.nTilesEmptyX && nX < nExponent*nMSBFactor; nX += nMSBFactor )
+ {
+ if( bNoFirstTileDraw )
+ bNoFirstTileDraw = false; // don't draw first tile position
+ else if( !aTmpGraphic.Draw( &rVDev, aCurrPos, aTileInfo.aTileSizePixel, pAttr, nFlags ) )
+ return false;
+
+ aCurrPos.X() += aTileInfo.aTileSizePixel.Width();
+ }
+
+ aCurrPos.Y() += aTileInfo.aTileSizePixel.Height();
+ }
+
+#ifdef DBG_TEST
+// rVDev.SetFillColor( COL_WHITE );
+ rVDev.SetFillColor();
+ rVDev.SetLineColor( Color( 255 * nExponent / nMSBFactor, 255 - 255 * nExponent / nMSBFactor, 128 - 255 * nExponent / nMSBFactor ) );
+ rVDev.DrawRect( Rectangle((rTileInfo.aTileTopLeft.X())*rTileSizePixel.Width(),
+ (rTileInfo.aTileTopLeft.Y())*rTileSizePixel.Height(),
+ (rTileInfo.aNextTileTopLeft.X())*rTileSizePixel.Width()-1,
+ (rTileInfo.aNextTileTopLeft.Y())*rTileSizePixel.Height()-1) );
+#endif
+
+ return true;
+}
+
+// -----------------------------------------------------------------------------
+
+bool GraphicObject::ImplDrawTiled( OutputDevice* pOut, const Rectangle& rArea, const Size& rSizePixel,
+ const Size& rOffset, const GraphicAttr* pAttr, ULONG nFlags, int nTileCacheSize1D )
+{
+ // how many tiles to generate per recursion step
+ enum{ SubdivisionExponent=2 };
+
+ const MapMode aOutMapMode( pOut->GetMapMode() );
+ const MapMode aMapMode( aOutMapMode.GetMapUnit(), Point(), aOutMapMode.GetScaleX(), aOutMapMode.GetScaleY() );
+ bool bRet( false );
+
+ // #i42643# Casting to Int64, to avoid integer overflow for
+ // huge-DPI output devices
+ if( GetGraphic().GetType() == GRAPHIC_BITMAP &&
+ static_cast<sal_Int64>(rSizePixel.Width()) * rSizePixel.Height() <
+ static_cast<sal_Int64>(nTileCacheSize1D)*nTileCacheSize1D )
+ {
+ // First combine very small bitmaps into a larger tile
+ // ===================================================
+
+ VirtualDevice aVDev;
+ const int nNumTilesInCacheX( (nTileCacheSize1D + rSizePixel.Width()-1) / rSizePixel.Width() );
+ const int nNumTilesInCacheY( (nTileCacheSize1D + rSizePixel.Height()-1) / rSizePixel.Height() );
+
+ aVDev.SetOutputSizePixel( Size( nNumTilesInCacheX*rSizePixel.Width(),
+ nNumTilesInCacheY*rSizePixel.Height() ) );
+ aVDev.SetMapMode( aMapMode );
+
+ // draw bitmap content
+ if( ImplRenderTempTile( aVDev, SubdivisionExponent, nNumTilesInCacheX,
+ nNumTilesInCacheY, rSizePixel, pAttr, nFlags ) )
+ {
+ BitmapEx aTileBitmap( aVDev.GetBitmap( Point(0,0), aVDev.GetOutputSize() ) );
+
+ // draw alpha content, if any
+ if( IsTransparent() )
+ {
+ GraphicObject aAlphaGraphic;
+
+ if( GetGraphic().IsAlpha() )
+ aAlphaGraphic.SetGraphic( GetGraphic().GetBitmapEx().GetAlpha().GetBitmap() );
+ else
+ aAlphaGraphic.SetGraphic( GetGraphic().GetBitmapEx().GetMask() );
+
+ if( aAlphaGraphic.ImplRenderTempTile( aVDev, SubdivisionExponent, nNumTilesInCacheX,
+ nNumTilesInCacheY, rSizePixel, pAttr, nFlags ) )
+ {
+ // Combine bitmap and alpha/mask
+ if( GetGraphic().IsAlpha() )
+ aTileBitmap = BitmapEx( aTileBitmap.GetBitmap(),
+ AlphaMask( aVDev.GetBitmap( Point(0,0), aVDev.GetOutputSize() ) ) );
+ else
+ aTileBitmap = BitmapEx( aTileBitmap.GetBitmap(),
+ aVDev.GetBitmap( Point(0,0), aVDev.GetOutputSize() ).CreateMask( Color(COL_WHITE) ) );
+ }
+ }
+
+ // paint generated tile
+ GraphicObject aTmpGraphic( aTileBitmap );
+ bRet = aTmpGraphic.ImplDrawTiled( pOut, rArea,
+ aTileBitmap.GetSizePixel(),
+ rOffset, pAttr, nFlags, nTileCacheSize1D );
+ }
+ }
+ else
+ {
+ const Size aOutOffset( pOut->LogicToPixel( rOffset, aOutMapMode ) );
+ const Rectangle aOutArea( pOut->LogicToPixel( rArea, aOutMapMode ) );
+
+ // number of invisible (because out-of-area) tiles
+ int nInvisibleTilesX;
+ int nInvisibleTilesY;
+
+ // round towards -infty for negative offset
+ if( aOutOffset.Width() < 0 )
+ nInvisibleTilesX = (aOutOffset.Width() - rSizePixel.Width() + 1) / rSizePixel.Width();
+ else
+ nInvisibleTilesX = aOutOffset.Width() / rSizePixel.Width();
+
+ // round towards -infty for negative offset
+ if( aOutOffset.Height() < 0 )
+ nInvisibleTilesY = (aOutOffset.Height() - rSizePixel.Height() + 1) / rSizePixel.Height();
+ else
+ nInvisibleTilesY = aOutOffset.Height() / rSizePixel.Height();
+
+ // origin from where to 'virtually' start drawing in pixel
+ const Point aOutOrigin( pOut->LogicToPixel( Point( rArea.Left() - rOffset.Width(),
+ rArea.Top() - rOffset.Height() ) ) );
+ // position in pixel from where to really start output
+ const Point aOutStart( aOutOrigin.X() + nInvisibleTilesX*rSizePixel.Width(),
+ aOutOrigin.Y() + nInvisibleTilesY*rSizePixel.Height() );
+
+ pOut->Push( PUSH_CLIPREGION );
+ pOut->IntersectClipRegion( rArea );
+
+ // Paint all tiles
+ // ===============
+
+ bRet = ImplDrawTiled( *pOut, aOutStart,
+ (aOutArea.GetWidth() + aOutArea.Left() - aOutStart.X() + rSizePixel.Width() - 1) / rSizePixel.Width(),
+ (aOutArea.GetHeight() + aOutArea.Top() - aOutStart.Y() + rSizePixel.Height() - 1) / rSizePixel.Height(),
+ rSizePixel, pAttr, nFlags );
+
+ pOut->Pop();
+ }
+
+ return bRet;
+}
+
+// -----------------------------------------------------------------------------
+
+bool GraphicObject::ImplDrawTiled( OutputDevice& rOut, const Point& rPosPixel,
+ int nNumTilesX, int nNumTilesY,
+ const Size& rTileSizePixel, const GraphicAttr* pAttr, ULONG nFlags )
+{
+ Point aCurrPos( rPosPixel );
+ Size aTileSizeLogic( rOut.PixelToLogic( rTileSizePixel ) );
+ int nX, nY;
+
+ // #107607# Use logical coordinates for metafile playing, too
+ bool bDrawInPixel( rOut.GetConnectMetaFile() == NULL && GRAPHIC_BITMAP == GetType() );
+ BOOL bRet( FALSE );
+
+ // #105229# Switch off mapping (converting to logic and back to
+ // pixel might cause roundoff errors)
+ BOOL bOldMap( rOut.IsMapModeEnabled() );
+
+ if( bDrawInPixel )
+ rOut.EnableMapMode( FALSE );
+
+ for( nY=0; nY < nNumTilesY; ++nY )
+ {
+ aCurrPos.X() = rPosPixel.X();
+
+ for( nX=0; nX < nNumTilesX; ++nX )
+ {
+ // #105229# work with pixel coordinates here, mapping is disabled!
+ // #104004# don't disable mapping for metafile recordings
+ // #108412# don't quit the loop if one draw fails
+
+ // update return value. This method should return true, if
+ // at least one of the looped Draws succeeded.
+ bRet |= Draw( &rOut,
+ bDrawInPixel ? aCurrPos : rOut.PixelToLogic( aCurrPos ),
+ bDrawInPixel ? rTileSizePixel : aTileSizeLogic,
+ pAttr, nFlags );
+
+ aCurrPos.X() += rTileSizePixel.Width();
+ }
+
+ aCurrPos.Y() += rTileSizePixel.Height();
+ }
+
+ if( bDrawInPixel )
+ rOut.EnableMapMode( bOldMap );
+
+ return bRet;
+}
+
+// -----------------------------------------------------------------------------
+
+void GraphicObject::ImplTransformBitmap( BitmapEx& rBmpEx,
+ const GraphicAttr& rAttr,
+ const Size& rCropLeftTop,
+ const Size& rCropRightBottom,
+ const Rectangle& rCropRect,
+ const Size& rDstSize,
+ BOOL bEnlarge ) const
+{
+ // #107947# Extracted from svdograf.cxx
+
+ // #104115# Crop the bitmap
+ if( rAttr.IsCropped() )
+ {
+ rBmpEx.Crop( rCropRect );
+
+ // #104115# Negative crop sizes mean: enlarge bitmap and pad
+ if( bEnlarge && (
+ rCropLeftTop.Width() < 0 ||
+ rCropLeftTop.Height() < 0 ||
+ rCropRightBottom.Width() < 0 ||
+ rCropRightBottom.Height() < 0 ) )
+ {
+ Size aBmpSize( rBmpEx.GetSizePixel() );
+ sal_Int32 nPadLeft( rCropLeftTop.Width() < 0 ? -rCropLeftTop.Width() : 0 );
+ sal_Int32 nPadTop( rCropLeftTop.Height() < 0 ? -rCropLeftTop.Height() : 0 );
+ sal_Int32 nPadTotalWidth( aBmpSize.Width() + nPadLeft + (rCropRightBottom.Width() < 0 ? -rCropRightBottom.Width() : 0) );
+ sal_Int32 nPadTotalHeight( aBmpSize.Height() + nPadTop + (rCropRightBottom.Height() < 0 ? -rCropRightBottom.Height() : 0) );
+
+ BitmapEx aBmpEx2;
+
+ if( rBmpEx.IsTransparent() )
+ {
+ if( rBmpEx.IsAlpha() )
+ aBmpEx2 = BitmapEx( rBmpEx.GetBitmap(), rBmpEx.GetAlpha() );
+ else
+ aBmpEx2 = BitmapEx( rBmpEx.GetBitmap(), rBmpEx.GetMask() );
+ }
+ else
+ {
+ // #104115# Generate mask bitmap and init to zero
+ Bitmap aMask( aBmpSize, 1 );
+ aMask.Erase( Color(0,0,0) );
+
+ // #104115# Always generate transparent bitmap, we need the border transparent
+ aBmpEx2 = BitmapEx( rBmpEx.GetBitmap(), aMask );
+
+ // #104115# Add opaque mask to source bitmap, otherwise the destination remains transparent
+ rBmpEx = aBmpEx2;
+ }
+
+ aBmpEx2.SetSizePixel( Size(nPadTotalWidth, nPadTotalHeight) );
+ aBmpEx2.Erase( Color(0xFF,0,0,0) );
+ aBmpEx2.CopyPixel( Rectangle( Point(nPadLeft, nPadTop), aBmpSize ), Rectangle( Point(0, 0), aBmpSize ), &rBmpEx );
+ rBmpEx = aBmpEx2;
+ }
+ }
+
+ const Size aSizePixel( rBmpEx.GetSizePixel() );
+
+ if( rAttr.GetRotation() != 0 && !IsAnimated() )
+ {
+ if( aSizePixel.Width() && aSizePixel.Height() && rDstSize.Width() && rDstSize.Height() )
+ {
+ double fSrcWH = (double) aSizePixel.Width() / aSizePixel.Height();
+ double fDstWH = (double) rDstSize.Width() / rDstSize.Height();
+ double fScaleX = 1.0, fScaleY = 1.0;
+
+ // always choose scaling to shrink bitmap
+ if( fSrcWH < fDstWH )
+ fScaleY = aSizePixel.Width() / ( fDstWH * aSizePixel.Height() );
+ else
+ fScaleX = fDstWH * aSizePixel.Height() / aSizePixel.Width();
+
+ rBmpEx.Scale( fScaleX, fScaleY );
+ }
+ }
+}
+