diff options
-rw-r--r-- | cui/source/options/optmemory.cxx | 9 | ||||
-rw-r--r-- | include/svtools/GraphicManager.hxx | 117 | ||||
-rw-r--r-- | include/svtools/grfmgr.hxx | 132 | ||||
-rw-r--r-- | svtools/Library_svt.mk | 2 | ||||
-rw-r--r-- | svtools/source/graphic/GraphicManager.cxx (renamed from svtools/source/graphic/grfmgr2.cxx) | 1414 | ||||
-rw-r--r-- | svtools/source/graphic/grfcache.cxx | 15 | ||||
-rw-r--r-- | svtools/source/graphic/grfmgr.cxx | 597 |
7 files changed, 1093 insertions, 1193 deletions
diff --git a/cui/source/options/optmemory.cxx b/cui/source/options/optmemory.cxx index 9e8976d500dc..26c8d2450909 100644 --- a/cui/source/options/optmemory.cxx +++ b/cui/source/options/optmemory.cxx @@ -25,6 +25,7 @@ #include <svtools/langtab.hxx> #include <svl/zforlist.hxx> #include <svtools/grfmgr.hxx> +#include <svtools/GraphicManager.hxx> #include <svl/flagitem.hxx> #include <sfx2/dispatch.hxx> #include <unotools/lingucfg.hxx> @@ -182,11 +183,11 @@ sal_Bool OfaMemoryOptionsPage::FillItemSet( SfxItemSet& rSet ) // create a dummy graphic object to get access to the common GraphicManager GraphicObject aDummyObject; - GraphicManager& rGrfMgr = aDummyObject.GetGraphicManager(); + GraphicManager* rGrfMgr = GraphicManager::GetGlobalManager(); - rGrfMgr.SetMaxCacheSize(totalCacheSize); - rGrfMgr.SetMaxObjCacheSize(objectCacheSize, true); - rGrfMgr.SetCacheTimeout(objectReleaseTime); + rGrfMgr->SetMaxCacheSize(totalCacheSize); + rGrfMgr->SetMaxObjCacheSize(objectCacheSize, true); + rGrfMgr->SetCacheTimeout(objectReleaseTime); // OLECache officecfg::Office::Common::Cache::Writer::OLE_Objects::set( diff --git a/include/svtools/GraphicManager.hxx b/include/svtools/GraphicManager.hxx new file mode 100644 index 000000000000..ee75e4f7b2d5 --- /dev/null +++ b/include/svtools/GraphicManager.hxx @@ -0,0 +1,117 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef _GRAPHIC_MANAGER_HXX +#define _GRAPHIC_MANAGER_HXX + +class Animation; +class Graphic; +class GraphicObject; +class GraphicAttr; +class GraphicObject; +class GraphicCache; + +#include <vector> +#include <vcl/virdev.hxx> +#include <svtools/svtdllapi.h> + +#define GRAPHIC_MANAGER_CACHE_SIZE 15000000UL +#define GRAPHCI_MANAGER_MAX_OBJECT_CACHE_SIZE 3000000UL + +typedef ::std::vector< GraphicObject* > GraphicObjectList; + +class SVT_DLLPUBLIC GraphicManager +{ + + public: + GraphicManager( size_t nCacheSize = GRAPHIC_MANAGER_CACHE_SIZE, + size_t nMaxObjCacheSize = GRAPHCI_MANAGER_MAX_OBJECT_CACHE_SIZE ); + ~GraphicManager(); + + static void Adjust( Animation& rAnimation, const GraphicAttr& rAttr, + sal_uInt32 nAdjustmentFlags ); + static void Adjust( BitmapEx& rBmpEx, const GraphicAttr& rAttr, + sal_uInt32 nAdjustmentFlags ); + static void Adjust( GDIMetaFile& rMtf, const GraphicAttr& rAttr, + sal_uInt32 nAdjustmentFlags ); + + bool Draw( OutputDevice* pOutDev, const Point& rPoint, + const Size& rSize, GraphicObject& rGraphicObject, + const GraphicAttr& rGraphicAttr, const sal_uInt32 nFlags, + bool& rCached); + + bool DrawObj( OutputDevice* pOut, const Point& rPt, + const Size& rSz, GraphicObject& rObj, + const GraphicAttr& rAttr, const sal_uInt32 nFlags, + bool& rCached); + bool FillSwappedGraphicObject( const GraphicObject& rGraphicObject, Graphic& rSubstituteGraphicObject ); + OString GetUniqueID( const GraphicObject& rGraphicObject ) const; + void GraphicObjectWasSwappedIn( const GraphicObject& rGraphicObjet ); + void GraphicObjectWasSwappedOut( const GraphicObject& rGRaphicObject ); + inline bool HasObjects() const { return !maObjectList.empty(); } + bool IsInCache( OutputDevice* pOut, const Point& rPt, + const Size& rSz, const GraphicObject& rObj, + const GraphicAttr& rAttr ) const; + void RegisterObject( const GraphicObject& rGraphicObject, Graphic& rSubstituteGraphicObject, + const OString* pID = NULL, const GraphicObject* pCopyObj = NULL ); + void ReleaseFromCache( const GraphicObject& rObj ); + void SetCacheTimeout( int nTimeoutSeconds ); + void SetMaxCacheSize( size_t nNewCacheSize ); + void SetMaxObjCacheSize( size_t nNewMaxObjSize, + bool bDestroyGreaterCached = false); + void UnregisterObject( const GraphicObject& rGraphicObject ); + + static void Draw( OutputDevice* pOutDev, const Point& rPoint, + const Size& rSize, GDIMetaFile& rMtf, + const GraphicAttr& rAttr ); + + private: + GraphicObjectList maObjectList; + GraphicCache* mpCache; + + + bool SVT_DLLPRIVATE ImplCreateOutput( OutputDevice* pOutDev, const Point& rPoint, + const Size& rSize, const BitmapEx& rBmpEx, + const GraphicAttr& rAttr, const sal_uInt32 nFlags, + BitmapEx* pBmpEx = NULL); + bool SVT_DLLPRIVATE ImplCreateOutput( OutputDevice* pOutDev, const Point& rPoint, + const Size& rSize, const GDIMetaFile& rMtf, + const GraphicAttr& rAttr, const sal_uInt32 nFlags, + GDIMetaFile& rOutMtf, BitmapEx& rOutBmpEx); + + + static GraphicManager* mpGlobalManager; + static void InitGlobal(); + + public: + static GraphicManager * GetGlobalManager() + { + /* FIXME: this is racy */ + if(!GraphicManager::mpGlobalManager) + { + GraphicManager::InitGlobal(); + }; + return GraphicManager::mpGlobalManager; + } +}; + +#endif /* _GRAPHIC_MANAGER_HXX */ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ + diff --git a/include/svtools/grfmgr.hxx b/include/svtools/grfmgr.hxx index 0523cc24d804..fa0d653cc021 100644 --- a/include/svtools/grfmgr.hxx +++ b/include/svtools/grfmgr.hxx @@ -156,19 +156,13 @@ public: class SVT_DLLPUBLIC GraphicObject : public SvDataCopyStream { - friend class GraphicManager; - private: - - static GraphicManager* mpGlobalMgr; - Graphic maGraphic; GraphicAttr maAttr; Size maPrefSize; MapMode maPrefMapMode; sal_uLong mnSizeBytes; GraphicType meType; - GraphicManager* mpMgr; String* mpLink; Link* mpSwapStreamHdl; String* mpUserData; @@ -330,8 +324,6 @@ public: void FireSwapInRequest(); void FireSwapOutRequest(); - GraphicManager& GetGraphicManager() const { return *mpMgr; } - sal_Bool IsCached( OutputDevice* pOut, const Point& rPt, @@ -506,130 +498,6 @@ public: double fBottomCrop) const; }; -typedef ::std::vector< GraphicObject* > GraphicObjectList_impl; - -class SVT_DLLPUBLIC GraphicManager -{ - friend class GraphicObject; - friend class GraphicDisplayCacheEntry; - -private: - - GraphicObjectList_impl maObjList; - GraphicCache* mpCache; - - GraphicManager( const GraphicManager& ) {} - GraphicManager& operator=( const GraphicManager& ) { return *this; } - - sal_Bool SVT_DLLPRIVATE ImplDraw( - OutputDevice* pOut, - const Point& rPt, - const Size& rSz, - GraphicObject& rObj, - const GraphicAttr& rAttr, - const sal_uLong nFlags, - sal_Bool& rCached - ); - - sal_Bool SVT_DLLPRIVATE ImplCreateOutput( - OutputDevice* pOut, - const Point& rPt, - const Size& rSz, - const BitmapEx& rBmpEx, - const GraphicAttr& rAttr, - const sal_uLong nFlags, - BitmapEx* pBmpEx = NULL - ); - sal_Bool SVT_DLLPRIVATE ImplCreateOutput( - OutputDevice* pOut, - const Point& rPt, - const Size& rSz, - const GDIMetaFile& rMtf, - const GraphicAttr& rAttr, - const sal_uLong nFlags, - GDIMetaFile& rOutMtf, - BitmapEx& rOutBmpEx - ); - - static void SVT_DLLPRIVATE ImplAdjust( - BitmapEx& rBmpEx, - const GraphicAttr& rAttr, - sal_uLong nAdjustmentFlags - ); - static void SVT_DLLPRIVATE ImplAdjust( - GDIMetaFile& rMtf, - const GraphicAttr& rAttr, - sal_uLong nAdjustmentFlags - ); - static void SVT_DLLPRIVATE ImplAdjust( - Animation& rAnimation, - const GraphicAttr& rAttr, - sal_uLong nAdjustmentFlags - ); - - static void SVT_DLLPRIVATE ImplDraw( - OutputDevice* pOut, - const Point& rPt, - const Size& rSz, - const GDIMetaFile& rMtf, - const GraphicAttr& rAttr - ); - - // Only used by GraphicObject's Ctor's and Dtor's - void SVT_DLLPRIVATE ImplRegisterObj( - const GraphicObject& rObj, - Graphic& rSubstitute, - const OString* pID = NULL, - const GraphicObject* pCopyObj = NULL - ); - void SVT_DLLPRIVATE ImplUnregisterObj( const GraphicObject& rObj ); - inline sal_Bool SVT_DLLPRIVATE ImplHasObjects() const { return !maObjList.empty(); } - - // Only used in swap case by GraphicObject - void SVT_DLLPRIVATE ImplGraphicObjectWasSwappedOut( const GraphicObject& rObj ); - sal_Bool SVT_DLLPRIVATE ImplFillSwappedGraphicObject( - const GraphicObject& rObj, - Graphic& rSubstitute - ); - void SVT_DLLPRIVATE ImplGraphicObjectWasSwappedIn( const GraphicObject& rObj ); - - OString SVT_DLLPRIVATE ImplGetUniqueID( const GraphicObject& rObj ) const; - -public: - - GraphicManager( sal_uLong nCacheSize = 10000000UL, sal_uLong nMaxObjCacheSize = 2400000UL ); - ~GraphicManager(); - - void SetMaxCacheSize( sal_uLong nNewCacheSize ); - - void SetMaxObjCacheSize( - sal_uLong nNewMaxObjSize, - sal_Bool bDestroyGreaterCached = sal_False - ); - - void SetCacheTimeout( sal_uLong nTimeoutSeconds ); - - void ReleaseFromCache( const GraphicObject& rObj ); - - sal_Bool IsInCache( - OutputDevice* pOut, - const Point& rPt, - const Size& rSz, - const GraphicObject& rObj, - const GraphicAttr& rAttr - ) const; - - sal_Bool DrawObj( - OutputDevice* pOut, - const Point& rPt, - const Size& rSz, - GraphicObject& rObj, - const GraphicAttr& rAttr, - const sal_uLong nFlags, - sal_Bool& rCached - ); -}; - #endif // _GRFMGR_HXX /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svtools/Library_svt.mk b/svtools/Library_svt.mk index 89456ecae3d0..168a372f599a 100644 --- a/svtools/Library_svt.mk +++ b/svtools/Library_svt.mk @@ -150,12 +150,12 @@ $(eval $(call gb_Library_add_exception_objects,svt,\ svtools/source/filter/DocumentToGraphicRenderer \ svtools/source/filter/exportdialog \ svtools/source/graphic/descriptor \ + svtools/source/graphic/GraphicManager \ svtools/source/graphic/graphic \ svtools/source/graphic/graphicunofactory \ svtools/source/graphic/grfattr \ svtools/source/graphic/grfcache \ svtools/source/graphic/grfmgr \ - svtools/source/graphic/grfmgr2 \ svtools/source/graphic/provider \ svtools/source/graphic/renderer \ svtools/source/graphic/transformer \ diff --git a/svtools/source/graphic/grfmgr2.cxx b/svtools/source/graphic/GraphicManager.cxx index 45c368612b2c..46ec5d72125d 100644 --- a/svtools/source/graphic/grfmgr2.cxx +++ b/svtools/source/graphic/GraphicManager.cxx @@ -17,93 +17,93 @@ * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ -#include <vcl/bmpacc.hxx> -#include <tools/poly.hxx> -#include <vcl/outdev.hxx> -#include <vcl/window.hxx> -#include <vcl/gdimtf.hxx> +#include <sal/config.h> +#include <tools/solar.h> +#include <tools/helpers.hxx> +#include <svtools/GraphicManager.hxx> +#include <svtools/grfmgr.hxx> #include <vcl/metaact.hxx> #include <vcl/metric.hxx> -#include <vcl/animate.hxx> -#include <vcl/alpha.hxx> -#include <vcl/virdev.hxx> +#include <vcl/window.hxx> +#include <officecfg/Office/Common.hxx> +#include <vcl/bmpacc.hxx> #include "grfcache.hxx" -#include <svtools/grfmgr.hxx> - -// ----------- -// - defines - -// ----------- #define WATERMARK_LUM_OFFSET 50 #define WATERMARK_CON_OFFSET -70 -#define MAP( cVal0, cVal1, nFrac ) ((sal_uInt8)((((long)(cVal0)<<20L)+nFrac*((long)(cVal1)-(cVal0)))>>20L)) -// ------------------ -// - GraphicManager - -// ------------------ +GraphicManager* GraphicManager::mpGlobalManager = NULL; -GraphicManager::GraphicManager( sal_uLong nCacheSize, sal_uLong nMaxObjCacheSize ) : - mpCache( new GraphicCache( nCacheSize, nMaxObjCacheSize ) ) +void GraphicManager::InitGlobal() { + mpGlobalManager = new GraphicManager( (officecfg::Office::Common::Cache::GraphicManager:: + TotalCacheSize::get()), + (officecfg::Office::Common::Cache::GraphicManager:: + ObjectCacheSize::get())); + mpGlobalManager->SetCacheTimeout( officecfg::Office::Common::Cache::GraphicManager:: + ObjectReleaseTime::get()); } -GraphicManager::~GraphicManager() +GraphicManager::GraphicManager( size_t nCacheSize, size_t nMaxObjCacheSize ) + : mpCache( new GraphicCache( nCacheSize, nMaxObjCacheSize ) ) { - for( size_t i = 0, n = maObjList.size(); i < n; ++i ) - maObjList[ i ]->GraphicManagerDestroyed(); +} +GraphicManager::~GraphicManager() +{ delete mpCache; } -void GraphicManager::SetMaxCacheSize( sal_uLong nNewCacheSize ) +void GraphicManager::SetMaxCacheSize( size_t nNewCacheSize ) { mpCache->SetMaxDisplayCacheSize( nNewCacheSize ); } -void GraphicManager::SetMaxObjCacheSize( sal_uLong nNewMaxObjSize, sal_Bool bDestroyGreaterCached ) +void GraphicManager::SetMaxObjCacheSize( size_t nNewMaxObjSize, bool bDestroyGreaterCached ) { mpCache->SetMaxObjDisplayCacheSize( nNewMaxObjSize, bDestroyGreaterCached ); } -void GraphicManager::SetCacheTimeout( sal_uLong nTimeoutSeconds ) +void GraphicManager::SetCacheTimeout( int nTimeoutSeconds ) { mpCache->SetCacheTimeout( nTimeoutSeconds ); } -void GraphicManager::ReleaseFromCache( const GraphicObject& /*rObj*/ ) +void GraphicManager::ReleaseFromCache( const GraphicObject& /*rGraphicObject*/ ) { // !!! } -sal_Bool GraphicManager::IsInCache( OutputDevice* pOut, const Point& rPt, - const Size& rSz, const GraphicObject& rObj, - const GraphicAttr& rAttr ) const +bool GraphicManager::IsInCache( OutputDevice* pOutDev, const Point& rPoint, + const Size& rSize, const GraphicObject& rGraphicObject, + const GraphicAttr& rAttr ) const { - return mpCache->IsInDisplayCache( pOut, rPt, rSz, rObj, rAttr ); + return mpCache->IsInDisplayCache( pOutDev, rPoint, rSize, rGraphicObject, rAttr ); } -sal_Bool GraphicManager::DrawObj( OutputDevice* pOut, const Point& rPt, const Size& rSz, - GraphicObject& rObj, const GraphicAttr& rAttr, - const sal_uLong nFlags, sal_Bool& rCached ) +bool GraphicManager::DrawObj( OutputDevice* pOutDev, const Point& rPoint, const Size& rSize, + GraphicObject& rGraphicObject, const GraphicAttr& rAttr, + const sal_uInt32 nFlags, bool& rCached ) { - Point aPt( rPt ); - Size aSz( rSz ); - sal_Bool bRet = sal_False; + Point aPoint( rPoint ); + Size aSize( rSize ); + bool bRet = false; - rCached = sal_False; + rCached = false; - if( ( rObj.GetType() == GRAPHIC_BITMAP ) || ( rObj.GetType() == GRAPHIC_GDIMETAFILE ) ) + if( ( rGraphicObject.GetType() == GRAPHIC_BITMAP ) || + ( rGraphicObject.GetType() == GRAPHIC_GDIMETAFILE ) ) { // create output and fill cache - if( rObj.IsAnimated() || ( pOut->GetOutDevType() == OUTDEV_PRINTER ) || + if( rGraphicObject.IsAnimated() || + ( pOutDev->GetOutDevType() == OUTDEV_PRINTER ) || ( !( nFlags & GRFMGR_DRAW_NO_SUBSTITUTE ) && - ( ( nFlags & GRFMGR_DRAW_SUBSTITUTE ) || - !( nFlags & GRFMGR_DRAW_CACHED ) || - ( pOut->GetConnectMetaFile() && !pOut->IsOutputEnabled() ) ) ) ) + ( ( nFlags & GRFMGR_DRAW_SUBSTITUTE ) || !( nFlags & GRFMGR_DRAW_CACHED ) || + ( pOutDev->GetConnectMetaFile() && !pOutDev->IsOutputEnabled() ) ) ) ) { // simple output of transformed graphic - const Graphic aGraphic( rObj.GetTransformedGraphic( &rAttr ) ); + const Graphic aGraphic( rGraphicObject.GetTransformedGraphic( &rAttr ) ); if( aGraphic.IsSupportedGraphic() ) { @@ -111,154 +111,84 @@ sal_Bool GraphicManager::DrawObj( OutputDevice* pOut, const Point& rPt, const Si if( nRot10 ) { - Polygon aPoly( Rectangle( aPt, aSz ) ); + Polygon aPoly( Rectangle( aPoint, aSize ) ); - aPoly.Rotate( aPt, nRot10 ); + aPoly.Rotate( aPoint, nRot10 ); const Rectangle aRotBoundRect( aPoly.GetBoundRect() ); - aPt = aRotBoundRect.TopLeft(); - aSz = aRotBoundRect.GetSize(); + aPoint = aRotBoundRect.TopLeft(); + aSize = aRotBoundRect.GetSize(); } - aGraphic.Draw( pOut, aPt, aSz ); + aGraphic.Draw( pOutDev, aPoint, aSize ); } - bRet = sal_True; + bRet = true; } if( !bRet ) { // cached/direct drawing - if( !mpCache->DrawDisplayCacheObj( pOut, aPt, aSz, rObj, rAttr ) ) - bRet = ImplDraw( pOut, aPt, aSz, rObj, rAttr, nFlags, rCached ); + if( !mpCache->DrawDisplayCacheObj( pOutDev, aPoint, aSize, rGraphicObject, rAttr ) ) + { + bRet = Draw( pOutDev, aPoint, aSize, rGraphicObject, rAttr, nFlags, rCached ); + } else - bRet = rCached = sal_True; + { + bRet = rCached = true; + } } } return bRet; } -void GraphicManager::ImplRegisterObj( const GraphicObject& rObj, Graphic& rSubstitute, - const OString* pID, const GraphicObject* pCopyObj ) +void GraphicManager::RegisterObject( const GraphicObject& rGraphicObject, Graphic& rSubstituteGraphicObject, + const OString* pID, const GraphicObject* pCopyGraphicObject ) { - maObjList.push_back( (GraphicObject*)&rObj ); - mpCache->AddGraphicObject( rObj, rSubstitute, pID, pCopyObj ); + maObjectList.push_back( (GraphicObject*)&rGraphicObject ); + mpCache->AddGraphicObject( rGraphicObject, rSubstituteGraphicObject, pID, pCopyGraphicObject ); } -void GraphicManager::ImplUnregisterObj( const GraphicObject& rObj ) +void GraphicManager::UnregisterObject( const GraphicObject& rGraphicObject ) { - mpCache->ReleaseGraphicObject( rObj ); - for( GraphicObjectList_impl::iterator it = maObjList.begin(); it != maObjList.end(); ++it ) + mpCache->ReleaseGraphicObject( rGraphicObject ); + for( GraphicObjectList::iterator it = maObjectList.begin(); it != maObjectList.end(); ++it ) { - if ( *it == &rObj ) { - maObjList.erase( it ); + if ( *it == &rGraphicObject ) + { + maObjectList.erase( it ); break; } } } -void GraphicManager::ImplGraphicObjectWasSwappedOut( const GraphicObject& rObj ) +void GraphicManager::GraphicObjectWasSwappedOut( const GraphicObject& rGraphicObject ) { - mpCache->GraphicObjectWasSwappedOut( rObj ); + mpCache->GraphicObjectWasSwappedOut( rGraphicObject ); } -OString GraphicManager::ImplGetUniqueID( const GraphicObject& rObj ) const +OString GraphicManager::GetUniqueID( const GraphicObject& rGraphicObject ) const { - return mpCache->GetUniqueID( rObj ); + return mpCache->GetUniqueID( rGraphicObject ); } -sal_Bool GraphicManager::ImplFillSwappedGraphicObject( const GraphicObject& rObj, Graphic& rSubstitute ) +bool GraphicManager::FillSwappedGraphicObject( const GraphicObject& rGraphicObject, + Graphic& rSubstituteGraphicObject ) { - return( mpCache->FillSwappedGraphicObject( rObj, rSubstitute ) ); + return( mpCache->FillSwappedGraphicObject( rGraphicObject, rSubstituteGraphicObject ) ); } -void GraphicManager::ImplGraphicObjectWasSwappedIn( const GraphicObject& rObj ) +void GraphicManager::GraphicObjectWasSwappedIn( const GraphicObject& rGraphicObject ) { - mpCache->GraphicObjectWasSwappedIn( rObj ); + mpCache->GraphicObjectWasSwappedIn( rGraphicObject ); } -sal_Bool GraphicManager::ImplDraw( OutputDevice* pOut, const Point& rPt, - const Size& rSz, GraphicObject& rObj, - const GraphicAttr& rAttr, - const sal_uLong nFlags, sal_Bool& rCached ) -{ - const Graphic& rGraphic = rObj.GetGraphic(); - sal_Bool bRet = sal_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 = sal_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 ) - { - // Use bitmap output method, if metafile basically contains only a single - // bitmap (allows caching the resulting pixmap). - BitmapEx aDstBmpEx; - - if( ImplCreateOutput( pOut, rPt, rSz, aContainedBmpEx, rAttr, nFlags, &aDstBmpEx ) ) - { - rCached = mpCache->CreateDisplayCacheObj( pOut, rPt, rSz, rObj, rAttr, aDstBmpEx ); - bRet = sal_True; - } - } - else - { - rCached = mpCache->CreateDisplayCacheObj( pOut, rPt, rSz, rObj, rAttr, aDstMtf ); - bRet = sal_True; - } - } - } - - if( !bRet ) - { - const Graphic aGraphic( rObj.GetTransformedGraphic( &rAttr ) ); - - if( aGraphic.IsSupportedGraphic() ) - { - aGraphic.Draw( pOut, rPt, rSz ); - bRet = sal_True; - } - } - } - } - - return bRet; -} +#define MAP( cVal0, cVal1, nFrac ) ((sal_uInt8)((((long)(cVal0)<<20L)+nFrac*((long)(cVal1)-(cVal0)))>>20L)) -sal_Bool ImplCreateRotatedScaled( const BitmapEx& rBmpEx, const GraphicAttr& rAttributes, - sal_uInt16 nRot10, const Size& rUnrotatedSzPix, - long nStartX, long nEndX, long nStartY, long nEndY, - BitmapEx& rOutBmpEx ) +bool ImplCreateRotatedScaled( const BitmapEx& rBmpEx, const GraphicAttr& rAttributes, + sal_uInt16 nRot10, const Size& rUnrotatedSzPix, + long nStartX, long nEndX, long nStartY, long nEndY, + BitmapEx& rOutBmpEx ) { const long aUnrotatedWidth = rUnrotatedSzPix.Width(); const long aUnrotatedHeight = rUnrotatedSzPix.Height(); @@ -814,7 +744,148 @@ sal_Bool ImplCreateRotatedScaled( const BitmapEx& rBmpEx, const GraphicAttr& rAt return bRet; } -sal_Bool GraphicManager::ImplCreateOutput( OutputDevice* pOutputDevice, +bool GraphicManager::Draw( OutputDevice* pOutDev, const Point& rPoint, + const Size& rSize, GraphicObject& rGraphicObject, + const GraphicAttr& rAttr, + const sal_uInt32 nFlags, bool& rCached ) +{ + const Graphic& rGraphic = rGraphicObject.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( !(pOutDev->GetDrawMode() & ( DRAWMODE_BLACKBITMAP | DRAWMODE_WHITEBITMAP )) && + mpCache->IsDisplayCacheable( pOutDev, rPoint, rSize, rGraphicObject, rAttr ) ) + { + BitmapEx aDstBmpEx; + + if( ImplCreateOutput( pOutDev, rPoint, rSize, aSrcBmpEx, rAttr, nFlags, &aDstBmpEx ) ) + { + rCached = mpCache->CreateDisplayCacheObj( pOutDev, rPoint, rSize, rGraphicObject, rAttr, aDstBmpEx ); + bRet = true; + } + } + + if( !bRet ) + { + bRet = ImplCreateOutput( pOutDev, rPoint, rSize, aSrcBmpEx, rAttr, nFlags ); + } + } + else + { + const GDIMetaFile& rSrcMtf = rGraphic.GetGDIMetaFile(); + + if( mpCache->IsDisplayCacheable( pOutDev, rPoint, rSize, rGraphicObject, rAttr ) ) + { + GDIMetaFile aDstMtf; + BitmapEx aContainedBmpEx; + + if( ImplCreateOutput( pOutDev, rPoint, rSize, rSrcMtf, rAttr, nFlags, aDstMtf, aContainedBmpEx ) ) + { + if( !!aContainedBmpEx ) + { + // Use bitmap output method, if metafile basically contains only a single + // bitmap (allows caching the resulting pixmap). + BitmapEx aDstBmpEx; + + if( ImplCreateOutput( pOutDev, rPoint, rSize, aContainedBmpEx, rAttr, nFlags, &aDstBmpEx ) ) + { + rCached = mpCache->CreateDisplayCacheObj( pOutDev, rPoint, rSize, rGraphicObject, rAttr, aDstBmpEx ); + bRet = true; + } + } + else + { + rCached = mpCache->CreateDisplayCacheObj( pOutDev, rPoint, rSize, rGraphicObject, rAttr, aDstMtf ); + bRet = true; + } + } + } + + if( !bRet ) + { + const Graphic aGraphic( rGraphicObject.GetTransformedGraphic( &rAttr ) ); + + if( aGraphic.IsSupportedGraphic() ) + { + aGraphic.Draw( pOutDev, rPoint, rSize ); + bRet = true; + } + } + } + } + + return bRet; +} + +// This function checks whether the bitmap is usable for skipping +// mtf rendering by using just this one bitmap (i.e. in case the metafile +// contains just this one pixmap that covers the entire metafile area). +static BitmapEx checkMetadataBitmap( const BitmapEx& rBmpEx, + Point rSrcPoint, + Size rSrcSize, + const Point& rDestPoint, + const Size& rDestSize, + const Size& rRefSize, + bool& o_rbNonBitmapActionEncountered ) +{ +// NOTE: If you do changes in this function, change checkMetadataBitmap() in grfcache.cxx too. + BitmapEx aBmpEx; + if( rSrcSize == Size()) + rSrcSize = rBmpEx.GetSizePixel(); + + if( rDestPoint != Point( 0, 0 )) + { // The pixmap in the metafile has an offset (and so would not cover) + // the entire result -> fall back to mtf rendering. + o_rbNonBitmapActionEncountered = true; + return aBmpEx; + } + if( rDestSize != rRefSize ) + { // The pixmap is not fullscale (does not cover the entire metafile area). + // HACK: The code here should refuse to use the bitmap directly + // and fall back to mtf rendering, but there seem to be metafiles + // that do not specify exactly their area (the Windows API requires apps + // the specify it manually, the rectangle is specified as topleft/bottomright + // rather than topleft/size [which may be confusing], and the docs + // on the exact meaning are somewhat confusing as well), so if it turns + // out this metafile really contains just one bitmap and no other painting, + // and if the sizes almost match, just use the pixmap (which will be scaled + // to fit exactly the requested size, so there should not be any actual problem + // caused by this small difference). This will allow caching of the resulting + // (scaled) pixmap, which can make a noticeable performance difference. + if( rBmpEx.GetSizePixel().Width() > 100 && rBmpEx.GetSizePixel().Height() > 100 + && abs( rDestSize.Width() - rRefSize.Width()) < 5 + && abs( rDestSize.Height() - rRefSize.Height()) < 5 ) + ; // ok, assume it's close enough + else + { // fall back to mtf rendering + o_rbNonBitmapActionEncountered = true; + 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; +} + +bool GraphicManager::ImplCreateOutput( OutputDevice* pOutputDevice, const Point& rPoint, const Size& rSize, const BitmapEx& rBitmapEx, const GraphicAttr& rAttributes, const sal_uLong /*nFlags*/, BitmapEx* pBmpEx ) @@ -945,11 +1016,14 @@ sal_Bool GraphicManager::ImplCreateOutput( OutputDevice* pOutputDevice, { // Attribute adjustment if necessary if( rAttributes.IsSpecialDrawMode() || rAttributes.IsAdjusted() || rAttributes.IsTransparent() ) - ImplAdjust( aOutBmpEx, rAttributes, ADJUSTMENT_DRAWMODE | ADJUSTMENT_COLORS | ADJUSTMENT_TRANSPARENCY ); - + { + Adjust( aOutBmpEx, rAttributes, ADJUSTMENT_DRAWMODE | ADJUSTMENT_COLORS | ADJUSTMENT_TRANSPARENCY ); + } // OutDev adjustment if necessary if( pOutputDevice->GetOutDevType() != OUTDEV_PRINTER && pOutputDevice->GetBitCount() <= 8 && aOutBmpEx.GetBitCount() >= 8 ) + { aOutBmpEx.Dither( BMP_DITHER_MATRIX ); + } } } @@ -971,71 +1045,10 @@ sal_Bool GraphicManager::ImplCreateOutput( OutputDevice* pOutputDevice, return bRet; } -// This function checks whether the bitmap is usable for skipping -// mtf rendering by using just this one bitmap (i.e. in case the metafile -// contains just this one pixmap that covers the entire metafile area). -static BitmapEx checkMetadataBitmap( const BitmapEx& rBmpEx, - Point rSrcPoint, - Size rSrcSize, - const Point& rDestPoint, - const Size& rDestSize, - const Size& rRefSize, - bool& o_rbNonBitmapActionEncountered ) -{ -// NOTE: If you do changes in this function, change checkMetadataBitmap() in grfcache.cxx too. - BitmapEx aBmpEx; - if( rSrcSize == Size()) - rSrcSize = rBmpEx.GetSizePixel(); - - if( rDestPoint != Point( 0, 0 )) - { // The pixmap in the metafile has an offset (and so would not cover) - // the entire result -> fall back to mtf rendering. - o_rbNonBitmapActionEncountered = true; - return aBmpEx; - } - if( rDestSize != rRefSize ) - { // The pixmap is not fullscale (does not cover the entire metafile area). - // HACK: The code here should refuse to use the bitmap directly - // and fall back to mtf rendering, but there seem to be metafiles - // that do not specify exactly their area (the Windows API requires apps - // the specify it manually, the rectangle is specified as topleft/bottomright - // rather than topleft/size [which may be confusing], and the docs - // on the exact meaning are somewhat confusing as well), so if it turns - // out this metafile really contains just one bitmap and no other painting, - // and if the sizes almost match, just use the pixmap (which will be scaled - // to fit exactly the requested size, so there should not be any actual problem - // caused by this small difference). This will allow caching of the resulting - // (scaled) pixmap, which can make a noticeable performance difference. - if( rBmpEx.GetSizePixel().Width() > 100 && rBmpEx.GetSizePixel().Height() > 100 - && abs( rDestSize.Width() - rRefSize.Width()) < 5 - && abs( rDestSize.Height() - rRefSize.Height()) < 5 ) - ; // ok, assume it's close enough - else - { // fall back to mtf rendering - o_rbNonBitmapActionEncountered = true; - 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; -} - -sal_Bool GraphicManager::ImplCreateOutput( OutputDevice* pOut, - const Point& rPt, const Size& rSz, +bool GraphicManager::ImplCreateOutput( OutputDevice* pOutDev, + const Point& rPoint, const Size& rSize, const GDIMetaFile& rMtf, const GraphicAttr& rAttr, - const sal_uLong /*nFlags*/, GDIMetaFile& rOutMtf, BitmapEx& rOutBmpEx ) + const sal_uInt32 /*nFlags*/, GDIMetaFile& rOutMtf, BitmapEx& rOutBmpEx ) { const Size aNewSize( rMtf.GetPrefSize() ); @@ -1045,16 +1058,16 @@ sal_Bool GraphicManager::ImplCreateOutput( OutputDevice* pOut, // are no bitmaps. sal_Int32 nNumBitmaps(0); bool bNonBitmapActionEncountered(false); - if( aNewSize.Width() && aNewSize.Height() && rSz.Width() && rSz.Height() ) + if( aNewSize.Width() && aNewSize.Height() && rSize.Width() && rSize.Height() ) { const double fGrfWH = (double) aNewSize.Width() / aNewSize.Height(); - const double fOutWH = (double) rSz.Width() / rSz.Height(); + const double fOutWH = (double) rSize.Width() / rSize.Height(); const double fScaleX = fOutWH / fGrfWH; const double fScaleY = 1.0; const MapMode rPrefMapMode( rMtf.GetPrefMapMode() ); - const Size rSizePix( pOut->LogicToPixel( aNewSize, rPrefMapMode ) ); + const Size rSizePix( pOutDev->LogicToPixel( aNewSize, rPrefMapMode ) ); // NOTE: If you do changes in this function, check GraphicDisplayCacheEntry::IsCacheableAsBitmap // in grfcache.cxx too. @@ -1076,238 +1089,178 @@ sal_Bool GraphicManager::ImplCreateOutput( OutputDevice* pOut, MetaAction* pModAct = NULL; switch( pAct->GetType() ) { - case META_FONT_ACTION: + case META_FONT_ACTION: { // taking care of font width default if scaling metafile. MetaFontAction* pA = (MetaFontAction*)pAct; Font aFont( pA->GetFont() ); if ( !aFont.GetWidth() ) { - FontMetric aFontMetric( pOut->GetFontMetric( aFont ) ); + FontMetric aFontMetric( pOutDev->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 = checkMetadataBitmap( - BitmapEx( pAction->GetBitmap()), - Point(), Size(), - pOut->LogicToPixel( pAction->GetPoint(), - rPrefMapMode ), - pAction->GetBitmap().GetSizePixel(), - rSizePix, - bNonBitmapActionEncountered ); - } - ++nNumBitmaps; - break; + // FALLTHROUGH intended + case META_NULL_ACTION: + case META_LINECOLOR_ACTION: + case META_FILLCOLOR_ACTION: + case META_TEXTCOLOR_ACTION: + case META_TEXTFILLCOLOR_ACTION: + case META_TEXTALIGN_ACTION: + case META_TEXTLINECOLOR_ACTION: + case META_TEXTLINE_ACTION: + case META_PUSH_ACTION: + case META_POP_ACTION: + case META_LAYOUTMODE_ACTION: + case META_TEXTLANGUAGE_ACTION: + case META_COMMENT_ACTION: + break; + + // bitmap output methods + case META_BMP_ACTION: + if( !nNumBitmaps && !bNonBitmapActionEncountered ) + { + MetaBmpAction* pAction = (MetaBmpAction*)pAct; + + rOutBmpEx = checkMetadataBitmap( BitmapEx( pAction->GetBitmap()), + Point(), Size(), + pOutDev->LogicToPixel( pAction->GetPoint(), + rPrefMapMode ), + pAction->GetBitmap().GetSizePixel(), + rSizePix, + bNonBitmapActionEncountered ); + } + ++nNumBitmaps; + break; - case META_BMPSCALE_ACTION: - if( !nNumBitmaps && !bNonBitmapActionEncountered ) - { - MetaBmpScaleAction* pAction = (MetaBmpScaleAction*)pAct; - - rOutBmpEx = checkMetadataBitmap( - BitmapEx( pAction->GetBitmap()), - Point(), Size(), - pOut->LogicToPixel( pAction->GetPoint(), - rPrefMapMode ), - pOut->LogicToPixel( pAction->GetSize(), - rPrefMapMode ), - rSizePix, - bNonBitmapActionEncountered ); - } - ++nNumBitmaps; - break; + case META_BMPSCALE_ACTION: + if( !nNumBitmaps && !bNonBitmapActionEncountered ) + { + MetaBmpScaleAction* pAction = (MetaBmpScaleAction*)pAct; + + rOutBmpEx = checkMetadataBitmap( BitmapEx( pAction->GetBitmap()), + Point(), Size(), + pOutDev->LogicToPixel( pAction->GetPoint(), + rPrefMapMode ), + pOutDev->LogicToPixel( pAction->GetSize(), + rPrefMapMode ), + rSizePix, + bNonBitmapActionEncountered ); + } + ++nNumBitmaps; + break; - case META_BMPSCALEPART_ACTION: - if( !nNumBitmaps && !bNonBitmapActionEncountered ) - { - MetaBmpScalePartAction* pAction = (MetaBmpScalePartAction*)pAct; - - rOutBmpEx = checkMetadataBitmap( - BitmapEx( pAction->GetBitmap() ), - pAction->GetSrcPoint(), - pAction->GetSrcSize(), - pOut->LogicToPixel( pAction->GetDestPoint(), - rPrefMapMode ), - pOut->LogicToPixel( pAction->GetDestSize(), - rPrefMapMode ), - rSizePix, - bNonBitmapActionEncountered ); - } - ++nNumBitmaps; - break; + case META_BMPSCALEPART_ACTION: + if( !nNumBitmaps && !bNonBitmapActionEncountered ) + { + MetaBmpScalePartAction* pAction = (MetaBmpScalePartAction*)pAct; + + rOutBmpEx = checkMetadataBitmap( BitmapEx( pAction->GetBitmap() ), + pAction->GetSrcPoint(), + pAction->GetSrcSize(), + pOutDev->LogicToPixel( pAction->GetDestPoint(), + rPrefMapMode ), + pOutDev->LogicToPixel( pAction->GetDestSize(), + rPrefMapMode ), + rSizePix, + bNonBitmapActionEncountered ); + } + ++nNumBitmaps; + break; - case META_BMPEX_ACTION: - if( !nNumBitmaps && !bNonBitmapActionEncountered ) - { - MetaBmpExAction* pAction = (MetaBmpExAction*)pAct; - - rOutBmpEx = checkMetadataBitmap( - pAction->GetBitmapEx(), - Point(), Size(), - pOut->LogicToPixel( pAction->GetPoint(), - rPrefMapMode ), - pAction->GetBitmapEx().GetSizePixel(), - rSizePix, - bNonBitmapActionEncountered ); - } - ++nNumBitmaps; - break; + case META_BMPEX_ACTION: + if( !nNumBitmaps && !bNonBitmapActionEncountered ) + { + MetaBmpExAction* pAction = (MetaBmpExAction*)pAct; + + rOutBmpEx = checkMetadataBitmap( pAction->GetBitmapEx(), + Point(), Size(), + pOutDev->LogicToPixel( pAction->GetPoint(), + rPrefMapMode ), + pAction->GetBitmapEx().GetSizePixel(), + rSizePix, + bNonBitmapActionEncountered ); + } + ++nNumBitmaps; + break; - case META_BMPEXSCALE_ACTION: - if( !nNumBitmaps && !bNonBitmapActionEncountered ) - { - MetaBmpExScaleAction* pAction = (MetaBmpExScaleAction*)pAct; - - rOutBmpEx = checkMetadataBitmap( - pAction->GetBitmapEx(), - Point(), Size(), - pOut->LogicToPixel( pAction->GetPoint(), - rPrefMapMode ), - pOut->LogicToPixel( pAction->GetSize(), - rPrefMapMode ), - rSizePix, - bNonBitmapActionEncountered ); - } - ++nNumBitmaps; - break; + case META_BMPEXSCALE_ACTION: + if( !nNumBitmaps && !bNonBitmapActionEncountered ) + { + MetaBmpExScaleAction* pAction = (MetaBmpExScaleAction*)pAct; + + rOutBmpEx = checkMetadataBitmap( pAction->GetBitmapEx(), + Point(), Size(), + pOutDev->LogicToPixel( pAction->GetPoint(), + rPrefMapMode ), + pOutDev->LogicToPixel( pAction->GetSize(), + rPrefMapMode ), + rSizePix, + bNonBitmapActionEncountered ); + } + ++nNumBitmaps; + break; - case META_BMPEXSCALEPART_ACTION: - if( !nNumBitmaps && !bNonBitmapActionEncountered ) - { - MetaBmpExScalePartAction* pAction = (MetaBmpExScalePartAction*)pAct; - - rOutBmpEx = checkMetadataBitmap( pAction->GetBitmapEx(), - pAction->GetSrcPoint(), - pAction->GetSrcSize(), - pOut->LogicToPixel( pAction->GetDestPoint(), - rPrefMapMode ), - pOut->LogicToPixel( pAction->GetDestSize(), - rPrefMapMode ), - rSizePix, - bNonBitmapActionEncountered ); - } - ++nNumBitmaps; - break; + case META_BMPEXSCALEPART_ACTION: + if( !nNumBitmaps && !bNonBitmapActionEncountered ) + { + MetaBmpExScalePartAction* pAction = (MetaBmpExScalePartAction*)pAct; + + rOutBmpEx = checkMetadataBitmap( pAction->GetBitmapEx(), + pAction->GetSrcPoint(), + pAction->GetSrcSize(), + pOutDev->LogicToPixel( pAction->GetDestPoint(), + rPrefMapMode ), + pOutDev->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; + // 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: + case META_POINT_ACTION: + case META_LINE_ACTION: + case META_RECT_ACTION: + case META_ROUNDRECT_ACTION: + case META_ELLIPSE_ACTION: + case META_ARC_ACTION: + case META_PIE_ACTION: + case META_CHORD_ACTION: + case META_POLYLINE_ACTION: + case META_POLYGON_ACTION: + case META_POLYPOLYGON_ACTION: + case META_TEXT_ACTION: + case META_TEXTARRAY_ACTION: + case META_STRETCHTEXT_ACTION: + case META_TEXTRECT_ACTION: + case META_MASK_ACTION: + case META_MASKSCALE_ACTION: + case META_MASKSCALEPART_ACTION: + case META_GRADIENT_ACTION: + case META_HATCH_ACTION: + case META_WALLPAPER_ACTION: + case META_TRANSPARENT_ACTION: + case META_EPS_ACTION: + case META_FLOATTRANSPARENT_ACTION: + case META_GRADIENTEX_ACTION: + case META_CLIPREGION_ACTION: + case META_ISECTRECTCLIPREGION_ACTION: + case META_ISECTREGIONCLIPREGION_ACTION: + case META_MOVECLIPREGION_ACTION: + case META_MAPMODE_ACTION: + case META_REFPOINT_ACTION: + default: + bNonBitmapActionEncountered = true; + break; } if ( pModAct ) { @@ -1324,7 +1277,9 @@ sal_Bool GraphicManager::ImplCreateOutput( OutputDevice* pOut, pDeleteAction->Delete(); } else + { pModAct = pAct; + } } pModAct->Scale( fScaleX, fScaleY ); } @@ -1335,16 +1290,17 @@ sal_Bool GraphicManager::ImplCreateOutput( OutputDevice* pOut, 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 ); + { + Adjust( rOutMtf, rAttr, ADJUSTMENT_ALL ); + } + Draw( pOutDev, rPoint, rSize, rOutMtf, rAttr ); rOutBmpEx = BitmapEx(); } - return sal_True; + return true; } -void GraphicManager::ImplAdjust( BitmapEx& rBmpEx, const GraphicAttr& rAttr, sal_uLong nAdjustmentFlags ) +void GraphicManager::Adjust( BitmapEx& rBmpEx, const GraphicAttr& rAttr, sal_uInt32 nAdjustmentFlags ) { GraphicAttr aAttr( rAttr ); @@ -1352,22 +1308,20 @@ void GraphicManager::ImplAdjust( BitmapEx& rBmpEx, const GraphicAttr& rAttr, sal { switch( aAttr.GetDrawMode() ) { - case( GRAPHICDRAWMODE_MONO ): - rBmpEx.Convert( BMP_CONVERSION_1BIT_THRESHOLD ); + case GRAPHICDRAWMODE_MONO: + rBmpEx.Convert( BMP_CONVERSION_1BIT_THRESHOLD ); break; - case( GRAPHICDRAWMODE_GREYS ): - rBmpEx.Convert( BMP_CONVERSION_8BIT_GREYS ); + 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 ); - } + case GRAPHICDRAWMODE_WATERMARK: + aAttr.SetLuminance( aAttr.GetLuminance() + WATERMARK_LUM_OFFSET ); + aAttr.SetContrast( aAttr.GetContrast() + WATERMARK_CON_OFFSET ); break; - default: + default: break; } } @@ -1391,11 +1345,13 @@ void GraphicManager::ImplAdjust( BitmapEx& rBmpEx, const GraphicAttr& rAttr, sal if( ( nAdjustmentFlags & ADJUSTMENT_TRANSPARENCY ) && aAttr.IsTransparent() ) { - AlphaMask aAlpha; - sal_uInt8 cTrans = aAttr.GetTransparency(); + AlphaMask aAlpha; + sal_uInt8 cTrans = aAttr.GetTransparency(); if( !rBmpEx.IsTransparent() ) + { aAlpha = AlphaMask( rBmpEx.GetSizePixel(), &cTrans ); + } else if( !rBmpEx.IsAlpha() ) { aAlpha = rBmpEx.GetMask(); @@ -1408,7 +1364,7 @@ void GraphicManager::ImplAdjust( BitmapEx& rBmpEx, const GraphicAttr& rAttr, sal if( pA ) { - sal_uLong nTrans = cTrans, nNewTrans; + sal_uLong nTrans = cTrans, nNewTrans; const long nWidth = pA->Width(), nHeight = pA->Height(); if( pA->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL ) @@ -1447,7 +1403,7 @@ void GraphicManager::ImplAdjust( BitmapEx& rBmpEx, const GraphicAttr& rAttr, sal } } -void GraphicManager::ImplAdjust( GDIMetaFile& rMtf, const GraphicAttr& rAttr, sal_uLong nAdjustmentFlags ) +void GraphicManager::Adjust( GDIMetaFile& rMtf, const GraphicAttr& rAttr, sal_uInt32 nAdjustmentFlags ) { GraphicAttr aAttr( rAttr ); @@ -1455,22 +1411,20 @@ void GraphicManager::ImplAdjust( GDIMetaFile& rMtf, const GraphicAttr& rAttr, sa { switch( aAttr.GetDrawMode() ) { - case( GRAPHICDRAWMODE_MONO ): - rMtf.Convert( MTF_CONVERSION_1BIT_THRESHOLD ); + case GRAPHICDRAWMODE_MONO: + rMtf.Convert( MTF_CONVERSION_1BIT_THRESHOLD ); break; - case( GRAPHICDRAWMODE_GREYS ): - rMtf.Convert( MTF_CONVERSION_8BIT_GREYS ); + 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 ); - } + case GRAPHICDRAWMODE_WATERMARK: + aAttr.SetLuminance( aAttr.GetLuminance() + WATERMARK_LUM_OFFSET ); + aAttr.SetContrast( aAttr.GetContrast() + WATERMARK_CON_OFFSET ); break; - default: + default: break; } } @@ -1498,7 +1452,7 @@ void GraphicManager::ImplAdjust( GDIMetaFile& rMtf, const GraphicAttr& rAttr, sa } } -void GraphicManager::ImplAdjust( Animation& rAnimation, const GraphicAttr& rAttr, sal_uLong nAdjustmentFlags ) +void GraphicManager::Adjust( Animation& rAnimation, const GraphicAttr& rAttr, sal_uInt32 nAdjustmentFlags ) { GraphicAttr aAttr( rAttr ); @@ -1506,22 +1460,20 @@ void GraphicManager::ImplAdjust( Animation& rAnimation, const GraphicAttr& rAttr { switch( aAttr.GetDrawMode() ) { - case( GRAPHICDRAWMODE_MONO ): - rAnimation.Convert( BMP_CONVERSION_1BIT_THRESHOLD ); + case GRAPHICDRAWMODE_MONO: + rAnimation.Convert( BMP_CONVERSION_1BIT_THRESHOLD ); break; - case( GRAPHICDRAWMODE_GREYS ): - rAnimation.Convert( BMP_CONVERSION_8BIT_GREYS ); + 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 ); - } + case GRAPHICDRAWMODE_WATERMARK: + aAttr.SetLuminance( aAttr.GetLuminance() + WATERMARK_LUM_OFFSET ); + aAttr.SetContrast( aAttr.GetContrast() + WATERMARK_CON_OFFSET ); break; - default: + default: break; } } @@ -1549,511 +1501,29 @@ void GraphicManager::ImplAdjust( Animation& rAnimation, const GraphicAttr& rAttr } } -void GraphicManager::ImplDraw( OutputDevice* pOut, const Point& rPt, const Size& rSz, - const GDIMetaFile& rMtf, const GraphicAttr& rAttr ) +void GraphicManager::Draw( OutputDevice* pOutDev, const Point& rPoint, const Size& rSize, + GDIMetaFile& rMtf, const GraphicAttr& rAttr ) { - sal_uInt16 nRot10 = rAttr.GetRotation() % 3600; - Point aOutPt( rPt ); - Size aOutSz( rSz ); + sal_uInt16 nRot10 = rAttr.GetRotation() % 3600; + Point aOutPoint( rPoint ); + Size aOutSize( rSize ); if( nRot10 ) { - Polygon aPoly( Rectangle( aOutPt, aOutSz ) ); + Polygon aPoly( Rectangle( aOutPoint, aOutSize ) ); - aPoly.Rotate( aOutPt, nRot10 ); + aPoly.Rotate( aOutPoint, nRot10 ); const Rectangle aRotBoundRect( aPoly.GetBoundRect() ); - aOutPt = aRotBoundRect.TopLeft(); - aOutSz = aRotBoundRect.GetSize(); + aOutPoint = aRotBoundRect.TopLeft(); + aOutSize = aRotBoundRect.GetSize(); } - pOut->Push( PUSH_CLIPREGION ); - pOut->IntersectClipRegion( Rectangle( aOutPt, aOutSz ) ); + pOutDev->Push( PUSH_CLIPREGION ); + pOutDev->IntersectClipRegion( Rectangle( aOutPoint, aOutSize ) ); - ( (GDIMetaFile&) rMtf ).WindStart(); - ( (GDIMetaFile&) rMtf ).Play( pOut, aOutPt, aOutSz ); - ( (GDIMetaFile&) rMtf ).WindStart(); + rMtf.WindStart(); + rMtf.Play( pOutDev, aOutPoint, aOutSize ); + rMtf.WindStart(); - pOut->Pop(); + pOutDev->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, sal_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) - sal_Bool bOldMap( rVDev.IsMapModeEnabled() ); - rVDev.EnableMapMode( sal_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, - sal_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, sal_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, sal_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( sal_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, - sal_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 ); - } - } -} - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svtools/source/graphic/grfcache.cxx b/svtools/source/graphic/grfcache.cxx index f0d462967ca5..b397e904d013 100644 --- a/svtools/source/graphic/grfcache.cxx +++ b/svtools/source/graphic/grfcache.cxx @@ -17,8 +17,9 @@ * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ +#include <memory> + #include <salhelper/timer.hxx> -#include <svtools/grfmgr.hxx> #include <tools/debug.hxx> #include <vcl/metaact.hxx> #include <vcl/outdev.hxx> @@ -26,7 +27,9 @@ #include <rtl/strbuf.hxx> #include "grfcache.hxx" #include <rtl/crc.h> -#include <memory> + +#include <svtools/grfmgr.hxx> +#include <svtools/GraphicManager.hxx> #define RELEASE_TIMEOUT 10000 #define MAX_BMP_EXTENT 4096 @@ -143,7 +146,7 @@ class GraphicCacheEntry { private: - GraphicObjectList_impl maGraphicObjectList; + GraphicObjectList maGraphicObjectList; GraphicID maID; GfxLink maGfxLink; @@ -324,7 +327,7 @@ void GraphicCacheEntry::AddGraphicObjectReference( const GraphicObject& rObj, Gr bool GraphicCacheEntry::ReleaseGraphicObjectReference( const GraphicObject& rObj ) { for( - GraphicObjectList_impl::iterator it = maGraphicObjectList.begin(); + GraphicObjectList::iterator it = maGraphicObjectList.begin(); it != maGraphicObjectList.end(); ++it ) { @@ -809,7 +812,9 @@ GraphicDisplayCacheEntry::~GraphicDisplayCacheEntry() void GraphicDisplayCacheEntry::Draw( OutputDevice* pOut, const Point& rPt, const Size& rSz ) const { if( mpMtf ) - GraphicManager::ImplDraw( pOut, rPt, rSz, *mpMtf, maAttr ); + { + GraphicManager::Draw( pOut, rPt, rSz, *mpMtf, maAttr ); + } else if( mpBmpEx ) { if( maAttr.IsRotated() ) diff --git a/svtools/source/graphic/grfmgr.cxx b/svtools/source/graphic/grfmgr.cxx index 6577c0ef1d89..e2ed6af0bdcd 100644 --- a/svtools/source/graphic/grfmgr.cxx +++ b/svtools/source/graphic/grfmgr.cxx @@ -32,6 +32,7 @@ #include <vcl/metaact.hxx> #include <vcl/virdev.hxx> #include <svtools/grfmgr.hxx> +#include <svtools/GraphicManager.hxx> #include <vcl/pdfextoutdevdata.hxx> @@ -45,8 +46,6 @@ using com::sun::star::uno::Sequence; using com::sun::star::container::XNameContainer; using com::sun::star::beans::XPropertySet; -GraphicManager* GraphicObject::mpGlobalMgr = NULL; - struct GrfSimpleCacheObj { Graphic maGraphic; @@ -58,6 +57,35 @@ struct GrfSimpleCacheObj TYPEINIT1_AUTOFACTORY( GraphicObject, SvDataCopyStream ); +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 +}; + + GraphicObject::GraphicObject( const GraphicManager* pMgr ) : mpLink ( NULL ), mpUserData ( NULL ) @@ -106,14 +134,7 @@ GraphicObject::GraphicObject( const OString& rUniqueID, const GraphicManager* pM GraphicObject::~GraphicObject() { - if( mpMgr ) - { - mpMgr->ImplUnregisterObj( *this ); - - if( ( mpMgr == mpGlobalMgr ) && !mpGlobalMgr->ImplHasObjects() ) - delete mpGlobalMgr, mpGlobalMgr = NULL; - } - + GraphicManager::GetGlobalManager()->UnregisterObject(*this); delete mpSwapOutTimer; delete mpSwapStreamHdl; delete mpLink; @@ -123,7 +144,6 @@ GraphicObject::~GraphicObject() void GraphicObject::ImplConstruct() { - mpMgr = NULL; mpSwapStreamHdl = NULL; mpSwapOutTimer = NULL; mpSimpleCache = NULL; @@ -146,52 +166,19 @@ void GraphicObject::ImplAssignGraphicData() mnAnimationLoopCount = ( mbAnimated ? maGraphic.GetAnimationLoopCount() : 0 ); } -void GraphicObject::ImplSetGraphicManager( const GraphicManager* pMgr, const OString* pID, const GraphicObject* pCopyObj ) +void GraphicObject::ImplSetGraphicManager( const GraphicManager* /* pMgr */, const OString* pID, const GraphicObject* pCopyObj ) { - if( !mpMgr || ( pMgr != mpMgr ) ) - { - if( !pMgr && mpMgr && ( mpMgr == mpGlobalMgr ) ) - return; - else - { - if( mpMgr ) - { - mpMgr->ImplUnregisterObj( *this ); - - if( ( mpMgr == mpGlobalMgr ) && !mpGlobalMgr->ImplHasObjects() ) - delete mpGlobalMgr, mpGlobalMgr = NULL; - } - - if( !pMgr ) - { - if( !mpGlobalMgr ) - { - mpGlobalMgr = new GraphicManager( - (officecfg::Office::Common::Cache::GraphicManager:: - TotalCacheSize::get()), - (officecfg::Office::Common::Cache::GraphicManager:: - ObjectCacheSize::get())); - mpGlobalMgr->SetCacheTimeout( - officecfg::Office::Common::Cache::GraphicManager:: - ObjectReleaseTime::get()); - } - - mpMgr = mpGlobalMgr; - } - else - mpMgr = (GraphicManager*) pMgr; - - mpMgr->ImplRegisterObj( *this, maGraphic, pID, pCopyObj ); - } - } + GraphicManager::GetGlobalManager()->RegisterObject(*this, maGraphic, pID, pCopyObj); } void GraphicObject::ImplAutoSwapIn() { if( IsSwappedOut() ) { - if( mpMgr && mpMgr->ImplFillSwappedGraphicObject( *this, maGraphic ) ) + if( GraphicManager::GetGlobalManager()->FillSwappedGraphicObject( *this, maGraphic ) ) + { mbAutoSwapped = sal_False; + } else { mbIsInSwapIn = sal_True; @@ -242,8 +229,10 @@ void GraphicObject::ImplAutoSwapIn() mbIsInSwapIn = sal_False; - if( !mbAutoSwapped && mpMgr ) - mpMgr->ImplGraphicObjectWasSwappedIn( *this ); + if( !mbAutoSwapped) + { + GraphicManager::GetGlobalManager()->GraphicObjectWasSwappedIn( *this ); + } } } } @@ -321,7 +310,7 @@ GraphicObject& GraphicObject::operator=( const GraphicObject& rGraphicObj ) { if( &rGraphicObj != this ) { - mpMgr->ImplUnregisterObj( *this ); + GraphicManager::GetGlobalManager()->UnregisterObject( *this ); delete mpSwapStreamHdl, mpSwapStreamHdl = NULL; delete mpSimpleCache, mpSimpleCache = NULL; @@ -334,9 +323,8 @@ GraphicObject& GraphicObject::operator=( const GraphicObject& rGraphicObj ) mpUserData = rGraphicObj.mpUserData ? new String( *rGraphicObj.mpUserData ) : NULL; ImplAssignGraphicData(); mbAutoSwapped = sal_False; - mpMgr = rGraphicObj.mpMgr; - mpMgr->ImplRegisterObj( *this, maGraphic, NULL, &rGraphicObj ); + GraphicManager::GetGlobalManager()->RegisterObject( *this, maGraphic, NULL, &rGraphicObj ); } return *this; @@ -371,8 +359,7 @@ OString GraphicObject::GetUniqueID() const OString aRet; - if( mpMgr ) - aRet = mpMgr->ImplGetUniqueID( *this ); + aRet = GraphicManager::GetGlobalManager()->GetUniqueID( *this ); return aRet; } @@ -468,9 +455,6 @@ void GraphicObject::FireSwapOutRequest() void GraphicObject::GraphicManagerDestroyed() { - // we're alive, but our manager doesn't live anymore ==> connect to default manager - mpMgr = NULL; - ImplSetGraphicManager( NULL ); } sal_Bool GraphicObject::IsCached( OutputDevice* pOut, const Point& rPt, const Size& rSz, @@ -488,7 +472,7 @@ sal_Bool GraphicObject::IsCached( OutputDevice* pOut, const Point& rPt, const Si sal_Bool bRectClip; ImplGetCropParams( pOut, aPt, aSz, pAttr, aClipPolyPoly, bRectClip ); } - bRet = mpMgr->IsInCache( pOut, aPt, aSz, *this, ( pAttr ? *pAttr : GetAttr() ) ); + bRet = GraphicManager::GetGlobalManager()->IsInCache( pOut, aPt, aSz, *this, ( pAttr ? *pAttr : GetAttr() ) ); } else bRet = sal_False; @@ -499,7 +483,7 @@ sal_Bool GraphicObject::IsCached( OutputDevice* pOut, const Point& rPt, const Si void GraphicObject::ReleaseFromCache() { - mpMgr->ReleaseFromCache( *this ); + GraphicManager::GetGlobalManager()->ReleaseFromCache( *this ); } bool GraphicObject::Draw( OutputDevice* pOut, const Point& rPt, const Size& rSz, @@ -509,8 +493,8 @@ bool GraphicObject::Draw( OutputDevice* pOut, const Point& rPt, const Size& rSz, Point aPt( rPt ); Size aSz( rSz ); const sal_uInt32 nOldDrawMode = pOut->GetDrawMode(); - sal_Bool bCropped = aAttr.IsCropped(); - sal_Bool bCached = sal_False; + bool bCropped = aAttr.IsCropped(); + bool bCached = false; bool bRet; // #i29534# Provide output rects for PDF writer @@ -559,7 +543,7 @@ bool GraphicObject::Draw( OutputDevice* pOut, const Point& rPt, const Size& rSz, } } - bRet = mpMgr->DrawObj( pOut, aPt, aSz, *this, aAttr, nFlags, bCached ); + bRet = GraphicManager::GetGlobalManager()->DrawObj( pOut, aPt, aSz, *this, aAttr, nFlags, bCached ); if( bCropped ) pOut->Pop(); @@ -736,7 +720,7 @@ const Graphic& GraphicObject::GetGraphic() const void GraphicObject::SetGraphic( const Graphic& rGraphic, const GraphicObject* pCopyObj ) { - mpMgr->ImplUnregisterObj( *this ); + GraphicManager::GetGlobalManager()->UnregisterObject( *this ); if( mpSwapOutTimer ) mpSwapOutTimer->Stop(); @@ -747,7 +731,7 @@ void GraphicObject::SetGraphic( const Graphic& rGraphic, const GraphicObject* pC delete mpLink, mpLink = NULL; delete mpSimpleCache, mpSimpleCache = NULL; - mpMgr->ImplRegisterObj( *this, maGraphic, 0, pCopyObj); + GraphicManager::GetGlobalManager()->RegisterObject( *this, maGraphic, 0, pCopyObj); if( mpSwapOutTimer ) mpSwapOutTimer->Start(); @@ -986,21 +970,21 @@ Graphic GraphicObject::GetTransformedGraphic( const GraphicAttr* pAttr ) const / if( IsAnimated() ) { Animation aAnimation( maGraphic.GetAnimation() ); - GraphicManager::ImplAdjust( aAnimation, aAttr, ADJUSTMENT_ALL ); + GraphicManager::Adjust( aAnimation, aAttr, ADJUSTMENT_ALL ); aAnimation.SetLoopCount( mnAnimationLoopCount ); aGraphic = aAnimation; } else { BitmapEx aBmpEx( maGraphic.GetBitmapEx() ); - GraphicManager::ImplAdjust( aBmpEx, aAttr, ADJUSTMENT_ALL ); + GraphicManager::Adjust( aBmpEx, aAttr, ADJUSTMENT_ALL ); aGraphic = aBmpEx; } } else { GDIMetaFile aMtf( maGraphic.GetGDIMetaFile() ); - GraphicManager::ImplAdjust( aMtf, aAttr, ADJUSTMENT_ALL ); + GraphicManager::Adjust( aMtf, aAttr, ADJUSTMENT_ALL ); aGraphic = aMtf; } } @@ -1024,9 +1008,10 @@ sal_Bool GraphicObject::SwapOut() { sal_Bool bRet = ( !mbAutoSwapped ? maGraphic.SwapOut() : sal_False ); - if( bRet && mpMgr ) - mpMgr->ImplGraphicObjectWasSwappedOut( *this ); - + if( bRet ) + { + GraphicManager::GetGlobalManager()->GraphicObjectWasSwappedOut( *this ); + } return bRet; } @@ -1034,8 +1019,10 @@ sal_Bool GraphicObject::SwapOut( SvStream* pOStm ) { sal_Bool bRet = ( !mbAutoSwapped ? maGraphic.SwapOut( pOStm ) : sal_False ); - if( bRet && mpMgr ) - mpMgr->ImplGraphicObjectWasSwappedOut( *this ); + if( bRet ) + { + GraphicManager::GetGlobalManager()->GraphicObjectWasSwappedOut( *this ); + } return bRet; } @@ -1049,14 +1036,16 @@ sal_Bool GraphicObject::SwapIn() ImplAutoSwapIn(); bRet = sal_True; } - else if( mpMgr && mpMgr->ImplFillSwappedGraphicObject( *this, maGraphic ) ) + else if( GraphicManager::GetGlobalManager()->FillSwappedGraphicObject( *this, maGraphic ) ) bRet = sal_True; else { bRet = maGraphic.SwapIn(); - if( bRet && mpMgr ) - mpMgr->ImplGraphicObjectWasSwappedIn( *this ); + if( bRet) + { + GraphicManager::GetGlobalManager()->GraphicObjectWasSwappedIn( *this ); + } } if( bRet ) @@ -1071,8 +1060,7 @@ void GraphicObject::SetSwapState() { mbAutoSwapped = sal_True; - if( mpMgr ) - mpMgr->ImplGraphicObjectWasSwappedOut( *this ); + GraphicManager::GetGlobalManager()->GraphicObjectWasSwappedOut( *this ); } } @@ -1242,4 +1230,455 @@ basegfx::B2DVector GraphicObject::calculateCropScaling( return basegfx::B2DVector(fFactorX,fFactorY); } +bool GraphicObject::ImplRenderTempTile( VirtualDevice& rVDev, int nExponent, + int nNumTilesX, int nNumTilesY, + const Size& rTileSizePixel, + const GraphicAttr* pAttr, sal_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) + sal_Bool bOldMap( rVDev.IsMapModeEnabled() ); + rVDev.EnableMapMode( sal_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, + sal_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, sal_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, sal_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( sal_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, + sal_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 ); + } + } +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |