include/vcl/GraphicObject.hxx | 143 --- include/vcl/graph.hxx | 2 solenv/clang-format/blacklist | 2 svtools/qa/unit/GraphicObjectTest.cxx | 157 --- sw/source/core/doc/notxtfrm.cxx | 23 vcl/Library_vcl.mk | 1 vcl/inc/impgraph.hxx | 34 vcl/source/gdi/graph.cxx | 8 vcl/source/gdi/impgraph.cxx | 70 + vcl/source/graphic/GraphicObject.cxx | 313 ++++-- vcl/source/graphic/GraphicObject2.cxx | 1552 ---------------------------------- vcl/source/graphic/grfcache.cxx | 1221 -------------------------- vcl/source/graphic/grfcache.hxx | 136 -- 13 files changed, 317 insertions(+), 3345 deletions(-)
New commits: commit ea3d755ac949c1b6dada5c341e018f8c23f5d395 Author: Tomaž Vajngerl <[email protected]> Date: Sat Mar 31 17:27:01 2018 +0900 vcl: detach usage and remove GraphicManager and GraphicCache Also remove some GraphicObjectTest because they call into GraphicManager which now doesn't exist anymore. Change-Id: Ia434736d8611df629af3e897c878a7fb8bbe4706 Reviewed-on: https://gerrit.libreoffice.org/52243 Tested-by: Jenkins <[email protected]> Reviewed-by: Tomaž Vajngerl <[email protected]> diff --git a/include/vcl/GraphicObject.hxx b/include/vcl/GraphicObject.hxx index fbd063687e34..64f912e4876d 100644 --- a/include/vcl/GraphicObject.hxx +++ b/include/vcl/GraphicObject.hxx @@ -169,13 +169,9 @@ public: class VCL_DLLPUBLIC GraphicObject { - friend class GraphicManager; friend class SdrGrafObj; private: - - static GraphicManager* mpGlobalMgr; - Graphic maGraphic; GraphicAttr maAttr; Size maPrefSize; @@ -304,10 +300,6 @@ private: ) const; DECL_LINK( ImplAutoSwapOutHdl, Timer*, void ); - - // Handle evtl. needed AfterDataChanges, needs to be called when new - // graphic data is swapped in/added to the GraphicManager - void VCL_DLLPRIVATE ImplAfterDataChange(); protected: SvStream* GetSwapStream() const; @@ -329,20 +321,6 @@ public: void FireSwapInRequest(); void FireSwapOutRequest(); - GraphicManager& GetGraphicManager() const - { - (void)this; // avoid loplugin:staticmethods because first GraphicManager ctor creates - // mpGlobalMgr and the last GraphicManager dtor destroys it - return *mpGlobalMgr; - } - - bool IsCached( - OutputDevice const * pOut, - const Size& rSz, - const GraphicAttr* pAttr, - GraphicManagerDrawFlags nFlags = GraphicManagerDrawFlags::STANDARD - ) const; - const Graphic& GetGraphic() const; void SetGraphic( const Graphic& rGraphic, const GraphicObject* pCopyObj = nullptr); void SetGraphic( const Graphic& rGraphic, const OUString& rLink ); @@ -477,127 +455,6 @@ public: double fTopCrop, double fRightCrop, double fBottomCrop) const; - - // read access - sal_uLong GetDataChangeTimeStamp() const { return mnDataChangeTimeStamp; } -}; - -class VCL_DLLPUBLIC GraphicManager -{ - friend class GraphicObject; - friend class GraphicDisplayCacheEntry; - -private: - - std::unordered_set< GraphicObject* > maObjList; - sal_uLong mnUsedSize; // currently used memory footprint of all swapped in graphics - std::unique_ptr<GraphicCache> mpCache; - - GraphicManager( const GraphicManager& ) = delete; - GraphicManager& operator=( const GraphicManager& ) = delete; - - bool VCL_DLLPRIVATE ImplDraw( - OutputDevice* pOut, - const Point& rPt, - const Size& rSz, - GraphicObject const & rObj, - const GraphicAttr& rAttr, - bool& rCached - ); - - static bool VCL_DLLPRIVATE ImplCreateOutput( - OutputDevice* pOut, - const Point& rPt, - const Size& rSz, - const BitmapEx& rBmpEx, - const GraphicAttr& rAttr, - BitmapEx* pBmpEx = nullptr - ); - static bool VCL_DLLPRIVATE ImplCreateOutput( - OutputDevice* pOut, - const Point& rPt, - const Size& rSz, - const GDIMetaFile& rMtf, - const GraphicAttr& rAttr, - GDIMetaFile& rOutMtf, - BitmapEx& rOutBmpEx - ); - - static void VCL_DLLPRIVATE ImplAdjust( - BitmapEx& rBmpEx, - const GraphicAttr& rAttr, - GraphicAdjustmentFlags nAdjustmentFlags - ); - static void VCL_DLLPRIVATE ImplAdjust( - GDIMetaFile& rMtf, - const GraphicAttr& rAttr, - GraphicAdjustmentFlags nAdjustmentFlags - ); - static void VCL_DLLPRIVATE ImplAdjust( - Animation& rAnimation, - const GraphicAttr& rAttr, - GraphicAdjustmentFlags nAdjustmentFlags - ); - - static void VCL_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 VCL_DLLPRIVATE ImplRegisterObj( - const GraphicObject& rObj, - Graphic& rSubstitute, - const OString* pID, - const GraphicObject* pCopyObj - ); - void VCL_DLLPRIVATE ImplUnregisterObj( const GraphicObject& rObj ); - bool VCL_DLLPRIVATE ImplHasObjects() const { return !maObjList.empty(); } - - // Only used in swap case by GraphicObject - void VCL_DLLPRIVATE ImplGraphicObjectWasSwappedOut( const GraphicObject& rObj ); - void VCL_DLLPRIVATE ImplGraphicObjectWasSwappedIn( const GraphicObject& rObj ); - - OString VCL_DLLPRIVATE ImplGetUniqueID( const GraphicObject& rObj ) const; - - // This method allows to check memory footprint for all currently swapped in GraphicObjects on this GraphicManager - // which are based on Bitmaps. This is needed on 32Bit systems and only does something on those systems. The problem - // to solve is that normally the SwapOut is timer-driven, but even with short timer settings there are situations - // where this does not trigger - or in other words: A maximum limitation for GraphicManagers was not in place before. - // For 32Bit systems this leads to situations where graphics will be missing. This method will actively swap out - // the longest swapped in graphics until a maximum memory boundary (derived from user settings in tools/options/memory) - // is no longer exceeded - void VCL_DLLPRIVATE ImplCheckSizeOfSwappedInGraphics(const GraphicObject* pGraphicToIgnore); -public: - - GraphicManager( sal_uLong nCacheSize, sal_uLong nMaxObjCacheSize ); - ~GraphicManager(); - - void SetMaxCacheSize( sal_uLong nNewCacheSize ); - sal_uLong GetMaxCacheSize() const; - - void SetCacheTimeout( sal_uLong nTimeoutSeconds ); - - bool IsInCache( - OutputDevice const * pOut, - const Point& rPt, - const Size& rSz, - const GraphicObject& rObj, - const GraphicAttr& rAttr - ) const; - - bool DrawObj( - OutputDevice* pOut, - const Point& rPt, - const Size& rSz, - GraphicObject const & rObj, - const GraphicAttr& rAttr, - const GraphicManagerDrawFlags nFlags, - bool& rCached - ); }; namespace vcl diff --git a/include/vcl/graph.hxx b/include/vcl/graph.hxx index 4915fa0e347a..9be22958b446 100644 --- a/include/vcl/graph.hxx +++ b/include/vcl/graph.hxx @@ -201,6 +201,8 @@ public: OUString getOriginURL() const; void setOriginURL(OUString const & rOriginURL); + OString getUniqueID() const; + public: std::shared_ptr<GraphicReader>& GetContext(); diff --git a/solenv/clang-format/blacklist b/solenv/clang-format/blacklist index 50e828ba480e..91618660943c 100644 --- a/solenv/clang-format/blacklist +++ b/solenv/clang-format/blacklist @@ -18213,8 +18213,6 @@ vcl/source/graphic/UnoGraphicObject.cxx vcl/source/graphic/UnoGraphicProvider.cxx vcl/source/graphic/UnoGraphicTransformer.cxx vcl/source/graphic/grfattr.cxx -vcl/source/graphic/grfcache.cxx -vcl/source/graphic/grfcache.hxx vcl/source/helper/canvasbitmap.cxx vcl/source/helper/canvastools.cxx vcl/source/helper/commandinfoprovider.cxx diff --git a/svtools/qa/unit/GraphicObjectTest.cxx b/svtools/qa/unit/GraphicObjectTest.cxx index ee119e46c793..6d748b8d180d 100644 --- a/svtools/qa/unit/GraphicObjectTest.cxx +++ b/svtools/qa/unit/GraphicObjectTest.cxx @@ -38,9 +38,7 @@ class GraphicObjectTest: public test::BootstrapFixture, public unotest::MacrosTe public: void testSwap(); - void testSizeBasedAutoSwap(); void testTdf88836(); - void testTdf88935(); void testPdf(); @@ -57,9 +55,7 @@ private: private: CPPUNIT_TEST_SUITE(GraphicObjectTest); CPPUNIT_TEST(testSwap); - CPPUNIT_TEST(testSizeBasedAutoSwap); CPPUNIT_TEST(testTdf88836); - CPPUNIT_TEST(testTdf88935); CPPUNIT_TEST(testPdf); CPPUNIT_TEST_SUITE_END(); }; @@ -147,92 +143,6 @@ void GraphicObjectTest::testSwap() } } -void GraphicObjectTest::testSizeBasedAutoSwap() -{ - // Set cache size to a very small value to check what happens - { - std::shared_ptr< comphelper::ConfigurationChanges > aBatch(comphelper::ConfigurationChanges::create()); - officecfg::Office::Common::Cache::GraphicManager::TotalCacheSize::set(sal_Int32(1), aBatch); - aBatch->commit(); - } - - uno::Reference< lang::XComponent > xComponent = - loadFromDesktop(m_directories.getURLFromSrc("svtools/qa/unit/data/document_with_two_images.odt"), "com.sun.star.text.TextDocument"); - - SwXTextDocument* pTxtDoc = dynamic_cast<SwXTextDocument *>(xComponent.get()); - CPPUNIT_ASSERT(pTxtDoc); - SwDoc* pDoc = pTxtDoc->GetDocShell()->GetDoc(); - CPPUNIT_ASSERT(pDoc); - SwNodes& aNodes = pDoc->GetNodes(); - - // Find images - const GraphicObject* pGrafObj1 = nullptr; - const GraphicObject* pGrafObj2 = nullptr; - for( sal_uLong nIndex = 0; nIndex < aNodes.Count(); ++nIndex) - { - if( aNodes[nIndex]->IsGrfNode() ) - { - SwGrfNode* pGrfNode = aNodes[nIndex]->GetGrfNode(); - CPPUNIT_ASSERT(pGrfNode); - if( !pGrafObj1 ) - { - pGrafObj1 = &pGrfNode->GetGrfObj(); - } - else - { - pGrafObj2 = &pGrfNode->GetGrfObj(); - } - } - } - CPPUNIT_ASSERT_MESSAGE("Missing image", pGrafObj1 != nullptr && pGrafObj2 != nullptr); - - { - // First image should be swapped out - CPPUNIT_ASSERT(pGrafObj1->IsSwappedOut()); - CPPUNIT_ASSERT_EQUAL(sal_uLong(697230), pGrafObj1->GetSizeBytes()); - - // Still swapped out: size is cached - CPPUNIT_ASSERT(pGrafObj1->IsSwappedOut()); - } - - { - // Second image should be in the memory - // Size based swap out is triggered by swap in, so the last swapped in image should be - // in the memory despite of size limit is reached. - CPPUNIT_ASSERT(!pGrafObj2->IsSwappedOut()); - CPPUNIT_ASSERT_EQUAL(sal_uLong(1620000), pGrafObj2->GetSizeBytes()); - } - - // Swap in first image -> second image will be swapped out - { - pGrafObj1->GetGraphic(); // GetGraphic calls swap in on a const object - CPPUNIT_ASSERT(!pGrafObj1->IsSwappedOut()); - CPPUNIT_ASSERT(pGrafObj2->IsSwappedOut()); - } - - // Swap in second image -> first image will be swapped out - { - pGrafObj2->GetGraphic(); // GetGraphic calls swap in on a const object - CPPUNIT_ASSERT(!pGrafObj2->IsSwappedOut()); - CPPUNIT_ASSERT(pGrafObj1->IsSwappedOut()); - } - - // Use bigger cache - { - GraphicManager& rGrfMgr = pGrafObj1->GetGraphicManager(); - rGrfMgr.SetMaxCacheSize((pGrafObj1->GetSizeBytes()+pGrafObj2->GetSizeBytes())*10); - } - // Swap in both images -> both should be swapped in - { - pGrafObj1->GetGraphic(); - pGrafObj2->GetGraphic(); - CPPUNIT_ASSERT(!pGrafObj1->IsSwappedOut()); - CPPUNIT_ASSERT(!pGrafObj2->IsSwappedOut()); - } - - xComponent->dispose(); -} - void GraphicObjectTest::testTdf88836() { // Construction with empty bitmap -> type should be GraphicType::NONE @@ -242,73 +152,6 @@ void GraphicObjectTest::testTdf88836() CPPUNIT_ASSERT_EQUAL(int(GraphicType::NONE), int(aGraphic.GetType())); } -void GraphicObjectTest::testTdf88935() -{ - // Cache size was not updated by deletion of graphic objects - - // Load a file with two images - uno::Reference< lang::XComponent > xComponent = - loadFromDesktop(m_directories.getURLFromSrc("svtools/qa/unit/data/document_with_two_images.odt"), "com.sun.star.text.TextDocument"); - SwXTextDocument* pTxtDoc = dynamic_cast<SwXTextDocument *>(xComponent.get()); - CPPUNIT_ASSERT(pTxtDoc); - SwDoc* pDoc = pTxtDoc->GetDocShell()->GetDoc(); - CPPUNIT_ASSERT(pDoc); - SwNodes& aNodes = pDoc->GetNodes(); - - // Find images - const GraphicObject* pGraphObj1 = nullptr; - const GraphicObject* pGraphObj2 = nullptr; - for( sal_uLong nIndex = 0; nIndex < aNodes.Count(); ++nIndex) - { - if( aNodes[nIndex]->IsGrfNode() ) - { - SwGrfNode* pGrfNode = aNodes[nIndex]->GetGrfNode(); - CPPUNIT_ASSERT(pGrfNode); - if( !pGraphObj1 ) - { - pGraphObj1 = &pGrfNode->GetGrfObj(); - } - else - { - pGraphObj2 = &pGrfNode->GetGrfObj(); - } - } - } - CPPUNIT_ASSERT_MESSAGE("Missing image", pGraphObj1 != nullptr && pGraphObj2 != nullptr); - - // Set cache size - { - GraphicManager& rGrfMgr = pGraphObj1->GetGraphicManager(); - rGrfMgr.SetMaxCacheSize((pGraphObj1->GetSizeBytes()+pGraphObj2->GetSizeBytes())*10); - } - - // Both images fit into the cache - { - pGraphObj1->GetGraphic(); - pGraphObj2->GetGraphic(); - CPPUNIT_ASSERT(!pGraphObj1->IsSwappedOut()); - CPPUNIT_ASSERT(!pGraphObj2->IsSwappedOut()); - } - - // Create and remove some copy of the first image - for( int i = 0; i < 50; ++i ) - { - GraphicObject aGraphObj3(*pGraphObj1); - CPPUNIT_ASSERT(aGraphObj3.SwapOut()); - CPPUNIT_ASSERT(aGraphObj3.SwapIn()); - } - - // Both images fit into the cache - { - pGraphObj1->GetGraphic(); - pGraphObj2->GetGraphic(); - CPPUNIT_ASSERT(!pGraphObj1->IsSwappedOut()); - CPPUNIT_ASSERT(!pGraphObj2->IsSwappedOut()); - } - - xComponent->dispose(); -} - void GraphicObjectTest::testPdf() { #if HAVE_FEATURE_PDFIUM diff --git a/sw/source/core/doc/notxtfrm.cxx b/sw/source/core/doc/notxtfrm.cxx index 4aae97a40690..6d503dce45fa 100644 --- a/sw/source/core/doc/notxtfrm.cxx +++ b/sw/source/core/doc/notxtfrm.cxx @@ -743,29 +743,8 @@ void SwNoTextFrame::Modify( const SfxPoolItem* pOld, const SfxPoolItem* pNew ) case RES_GRF_REREAD_AND_INCACHE: if( SwNodeType::Grf == GetNode()->GetNodeType() ) { + // TODO: Remove - due to GraphicObject refactoring bComplete = false; - SwGrfNode* pNd = static_cast<SwGrfNode*>( GetNode()); - - SwViewShell* pVSh = pNd->GetDoc()->getIDocumentLayoutAccess().GetCurrentViewShell(); - if( pVSh ) - { - GraphicAttr aAttr; - if( pNd->GetGrfObj().IsCached( pVSh->GetOut(), - getFramePrintArea().SSize(), &pNd->GetGraphicAttr( aAttr, this ) )) - { - for(SwViewShell& rShell : pVSh->GetRingContainer()) - { - SET_CURR_SHELL( &rShell ); - if( rShell.GetWin() ) - { - if( rShell.IsPreview() ) - ::RepaintPagePreview( &rShell, getFrameArea().SVRect() ); - else - rShell.GetWin()->Invalidate( getFrameArea().SVRect() ); - } - } - } - } } break; diff --git a/vcl/Library_vcl.mk b/vcl/Library_vcl.mk index 82971a424eb3..b6212ba959a4 100644 --- a/vcl/Library_vcl.mk +++ b/vcl/Library_vcl.mk @@ -304,7 +304,6 @@ $(eval $(call gb_Library_add_exception_objects,vcl,\ vcl/source/graphic/GraphicLoader \ vcl/source/graphic/GraphicObject \ vcl/source/graphic/GraphicObject2 \ - vcl/source/graphic/grfcache \ vcl/source/graphic/grfattr \ vcl/source/graphic/UnoGraphic \ vcl/source/graphic/UnoGraphicDescriptor \ diff --git a/vcl/inc/impgraph.hxx b/vcl/inc/impgraph.hxx index 6c76275abbb2..834113130bbe 100644 --- a/vcl/inc/impgraph.hxx +++ b/vcl/inc/impgraph.hxx @@ -31,9 +31,35 @@ class GfxLink; struct ImpSwapFile; class GraphicConversionParameters; +class GraphicID +{ +private: + sal_uInt32 mnID1; + sal_uInt32 mnID2; + sal_uInt32 mnID3; + BitmapChecksum mnID4; + +public: + GraphicID(ImpGraphic& rGraphic); + + bool operator==(const GraphicID& rID) const + { + return rID.mnID1 == mnID1 && rID.mnID2 == mnID2 && + rID.mnID3 == mnID3 && rID.mnID4 == mnID4; + } + + bool IsEmpty() const + { + return 0 == mnID4; + } + + OString getIDString() const; +}; + class ImpGraphic final { friend class Graphic; + friend class GraphicID; private: @@ -51,6 +77,7 @@ private: VectorGraphicDataPtr maVectorGraphicData; css::uno::Sequence<sal_Int8> maPdfData; OUString msOriginURL; + std::unique_ptr<GraphicID> mpGraphicID; private: @@ -81,6 +108,13 @@ private: msOriginURL = rOriginURL; } + OString getUniqueID() + { + if (!mpGraphicID) + mpGraphicID.reset(new GraphicID(*this)); + return mpGraphicID->getIDString(); + } + void ImplCreateSwapInfo(); void ImplClearGraphics(); void ImplClear(); diff --git a/vcl/source/gdi/graph.cxx b/vcl/source/gdi/graph.cxx index a444ed0d70cf..150bc049d722 100644 --- a/vcl/source/gdi/graph.cxx +++ b/vcl/source/gdi/graph.cxx @@ -612,6 +612,14 @@ void Graphic::setOriginURL(OUString const & rOriginURL) } } +OString Graphic::getUniqueID() const +{ + OString aUniqueString; + if (mxImpGraphic) + aUniqueString = mxImpGraphic->getUniqueID(); + return aUniqueString; +} + namespace { struct Id: public rtl::Static<cppu::OImplementationId, Id> {}; diff --git a/vcl/source/gdi/impgraph.cxx b/vcl/source/gdi/impgraph.cxx index 3fd0c7a1d034..0a2acd9538fd 100644 --- a/vcl/source/gdi/impgraph.cxx +++ b/vcl/source/gdi/impgraph.cxx @@ -101,6 +101,76 @@ Size GraphicReader::GetPreviewSize() const return aSize; } +GraphicID::GraphicID(ImpGraphic & rGraphic) +{ + mnID1 = static_cast<sal_uLong>(rGraphic.ImplGetType()) << 28; + mnID2 = mnID3 = mnID4 = 0; + + if (rGraphic.ImplGetType() == GraphicType::Bitmap) + { + if (rGraphic.getVectorGraphicData().get()) + { + const VectorGraphicDataPtr& rVectorGraphicDataPtr = rGraphic.getVectorGraphicData(); + const basegfx::B2DRange& rRange = rVectorGraphicDataPtr->getRange(); + + mnID1 |= rVectorGraphicDataPtr->getVectorGraphicDataArrayLength(); + mnID2 = basegfx::fround(rRange.getWidth()); + mnID3 = basegfx::fround(rRange.getHeight()); + mnID4 = vcl_get_checksum(0, rVectorGraphicDataPtr->getVectorGraphicDataArray().getConstArray(), rVectorGraphicDataPtr->getVectorGraphicDataArrayLength()); + } + else if (rGraphic.ImplIsAnimated()) + { + const Animation aAnimation(rGraphic.ImplGetAnimation()); + + mnID1 |= ( aAnimation.Count() & 0x0fffffff ); + mnID2 = aAnimation.GetDisplaySizePixel().Width(); + mnID3 = aAnimation.GetDisplaySizePixel().Height(); + mnID4 = rGraphic.ImplGetChecksum(); + } + else + { + const BitmapEx aBmpEx(rGraphic.ImplGetBitmapEx(GraphicConversionParameters())); + + mnID1 |= ( ( ( static_cast<sal_uLong>(aBmpEx.GetTransparentType()) << 8 ) | ( aBmpEx.IsAlpha() ? 1 : 0 ) ) & 0x0fffffff ); + mnID2 = aBmpEx.GetSizePixel().Width(); + mnID3 = aBmpEx.GetSizePixel().Height(); + mnID4 = rGraphic.ImplGetChecksum(); + } + } + else if (rGraphic.ImplGetType() == GraphicType::GdiMetafile) + { + const GDIMetaFile& rMtf = rGraphic.ImplGetGDIMetaFile(); + + mnID1 |= ( rMtf.GetActionSize() & 0x0fffffff ); + mnID2 = rMtf.GetPrefSize().Width(); + mnID3 = rMtf.GetPrefSize().Height(); + mnID4 = rGraphic.ImplGetChecksum(); + } +} + +OString GraphicID::getIDString() const +{ + static const char aHexData[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + + OStringBuffer aHexStr; + sal_Int32 nShift, nIndex = 0; + aHexStr.setLength(24 + (2 * BITMAP_CHECKSUM_SIZE)); + + for( nShift = 28; nShift >= 0; nShift -= 4 ) + aHexStr[nIndex++] = aHexData[ ( mnID1 >> static_cast<sal_uInt32>(nShift) ) & 0xf ]; + + for( nShift = 28; nShift >= 0; nShift -= 4 ) + aHexStr[nIndex++] = aHexData[ ( mnID2 >> static_cast<sal_uInt32>(nShift) ) & 0xf ]; + + for( nShift = 28; nShift >= 0; nShift -= 4 ) + aHexStr[nIndex++] = aHexData[ ( mnID3 >> static_cast<sal_uInt32>(nShift) ) & 0xf ]; + + for( nShift = ( 8 * BITMAP_CHECKSUM_SIZE ) - 4; nShift >= 0; nShift -= 4 ) + aHexStr[nIndex++] = aHexData[ ( mnID4 >> static_cast<sal_uInt32>(nShift) ) & 0xf ]; + + return aHexStr.makeStringAndClear(); +} + ImpGraphic::ImpGraphic() : meType ( GraphicType::NONE ), mnSizeBytes ( 0 ), diff --git a/vcl/source/graphic/GraphicObject.cxx b/vcl/source/graphic/GraphicObject.cxx index d302d6952877..b609608d1f67 100644 --- a/vcl/source/graphic/GraphicObject.cxx +++ b/vcl/source/graphic/GraphicObject.cxx @@ -49,6 +49,9 @@ using com::sun::star::uno::Sequence; using com::sun::star::container::XNameContainer; using com::sun::star::beans::XPropertySet; +#define WATERMARK_LUM_OFFSET 50 +#define WATERMARK_CON_OFFSET -70 + namespace vcl { namespace graphic @@ -96,7 +99,198 @@ void SearchForGraphics(uno::Reference<uno::XInterface> const & xInterface, }} // end namespace vcl::graphic -GraphicManager* GraphicObject::mpGlobalMgr = nullptr; +namespace +{ + +bool lclDrawObj( OutputDevice* pOut, const Point& rPt, const Size& rSz, + GraphicObject const & rObj, const GraphicAttr& rAttr) +{ + Point aPt( rPt ); + Size aSz( rSz ); + bool bRet = false; + + if( ( rObj.GetType() == GraphicType::Bitmap ) || ( rObj.GetType() == GraphicType::GdiMetafile ) ) + { + // simple output of transformed graphic + const Graphic aGraphic( rObj.GetTransformedGraphic( &rAttr ) ); + + if( aGraphic.IsSupportedGraphic() ) + { + const sal_uInt16 nRot10 = rAttr.GetRotation() % 3600; + + if( nRot10 ) + { + tools::Polygon aPoly( tools::Rectangle( aPt, aSz ) ); + + aPoly.Rotate( aPt, nRot10 ); + const tools::Rectangle aRotBoundRect( aPoly.GetBoundRect() ); + aPt = aRotBoundRect.TopLeft(); + aSz = aRotBoundRect.GetSize(); + } + + aGraphic.Draw( pOut, aPt, aSz ); + } + + bRet = true; + } + + return bRet; +} + +void lclImplAdjust( BitmapEx& rBmpEx, const GraphicAttr& rAttr, GraphicAdjustmentFlags nAdjustmentFlags ) +{ + GraphicAttr aAttr( rAttr ); + + if( ( nAdjustmentFlags & GraphicAdjustmentFlags::DRAWMODE ) && aAttr.IsSpecialDrawMode() ) + { + switch( aAttr.GetDrawMode() ) + { + case GraphicDrawMode::Mono: + rBmpEx.Convert( BmpConversion::N1BitThreshold ); + break; + + case GraphicDrawMode::Greys: + rBmpEx.Convert( BmpConversion::N8BitGreys ); + break; + + case GraphicDrawMode::Watermark: + { + aAttr.SetLuminance( aAttr.GetLuminance() + WATERMARK_LUM_OFFSET ); + aAttr.SetContrast( aAttr.GetContrast() + WATERMARK_CON_OFFSET ); + } + break; + + default: + break; + } + } + + if( ( nAdjustmentFlags & GraphicAdjustmentFlags::COLORS ) && aAttr.IsAdjusted() ) + { + rBmpEx.Adjust( aAttr.GetLuminance(), aAttr.GetContrast(), + aAttr.GetChannelR(), aAttr.GetChannelG(), aAttr.GetChannelB(), + aAttr.GetGamma(), aAttr.IsInvert() ); + } + + if( ( nAdjustmentFlags & GraphicAdjustmentFlags::MIRROR ) && aAttr.IsMirrored() ) + { + rBmpEx.Mirror( aAttr.GetMirrorFlags() ); + } + + if( ( nAdjustmentFlags & GraphicAdjustmentFlags::ROTATE ) && aAttr.IsRotated() ) + { + rBmpEx.Rotate( aAttr.GetRotation(), COL_TRANSPARENT ); + } + + if( ( nAdjustmentFlags & GraphicAdjustmentFlags::TRANSPARENCY ) && aAttr.IsTransparent() ) + { + rBmpEx.AdjustTransparency(aAttr.GetTransparency()); + } +} + +void lclImplAdjust( GDIMetaFile& rMtf, const GraphicAttr& rAttr, GraphicAdjustmentFlags nAdjustmentFlags ) +{ + GraphicAttr aAttr( rAttr ); + + if( ( nAdjustmentFlags & GraphicAdjustmentFlags::DRAWMODE ) && aAttr.IsSpecialDrawMode() ) + { + switch( aAttr.GetDrawMode() ) + { + case GraphicDrawMode::Mono: + rMtf.Convert( MtfConversion::N1BitThreshold ); + break; + + case GraphicDrawMode::Greys: + rMtf.Convert( MtfConversion::N8BitGreys ); + break; + + case GraphicDrawMode::Watermark: + { + aAttr.SetLuminance( aAttr.GetLuminance() + WATERMARK_LUM_OFFSET ); + aAttr.SetContrast( aAttr.GetContrast() + WATERMARK_CON_OFFSET ); + } + break; + + default: + break; + } + } + + if( ( nAdjustmentFlags & GraphicAdjustmentFlags::COLORS ) && aAttr.IsAdjusted() ) + { + rMtf.Adjust( aAttr.GetLuminance(), aAttr.GetContrast(), + aAttr.GetChannelR(), aAttr.GetChannelG(), aAttr.GetChannelB(), + aAttr.GetGamma(), aAttr.IsInvert() ); + } + + if( ( nAdjustmentFlags & GraphicAdjustmentFlags::MIRROR ) && aAttr.IsMirrored() ) + { + rMtf.Mirror( aAttr.GetMirrorFlags() ); + } + + if( ( nAdjustmentFlags & GraphicAdjustmentFlags::ROTATE ) && aAttr.IsRotated() ) + { + rMtf.Rotate( aAttr.GetRotation() ); + } + + if( ( nAdjustmentFlags & GraphicAdjustmentFlags::TRANSPARENCY ) && aAttr.IsTransparent() ) + { + OSL_FAIL( "Missing implementation: Mtf-Transparency" ); + } +} + +void lclImplAdjust( Animation& rAnimation, const GraphicAttr& rAttr, GraphicAdjustmentFlags nAdjustmentFlags ) +{ + GraphicAttr aAttr( rAttr ); + + if( ( nAdjustmentFlags & GraphicAdjustmentFlags::DRAWMODE ) && aAttr.IsSpecialDrawMode() ) + { + switch( aAttr.GetDrawMode() ) + { + case GraphicDrawMode::Mono: + rAnimation.Convert( BmpConversion::N1BitThreshold ); + break; + + case GraphicDrawMode::Greys: + rAnimation.Convert( BmpConversion::N8BitGreys ); + break; + + case GraphicDrawMode::Watermark: + { + aAttr.SetLuminance( aAttr.GetLuminance() + WATERMARK_LUM_OFFSET ); + aAttr.SetContrast( aAttr.GetContrast() + WATERMARK_CON_OFFSET ); + } + break; + + default: + break; + } + } + + if( ( nAdjustmentFlags & GraphicAdjustmentFlags::COLORS ) && aAttr.IsAdjusted() ) + { + rAnimation.Adjust( aAttr.GetLuminance(), aAttr.GetContrast(), + aAttr.GetChannelR(), aAttr.GetChannelG(), aAttr.GetChannelB(), + aAttr.GetGamma(), aAttr.IsInvert() ); + } + + if( ( nAdjustmentFlags & GraphicAdjustmentFlags::MIRROR ) && aAttr.IsMirrored() ) + { + rAnimation.Mirror( aAttr.GetMirrorFlags() ); + } + + if( ( nAdjustmentFlags & GraphicAdjustmentFlags::ROTATE ) && aAttr.IsRotated() ) + { + OSL_FAIL( "Missing implementation: Animation-Rotation" ); + } + + if( ( nAdjustmentFlags & GraphicAdjustmentFlags::TRANSPARENCY ) && aAttr.IsTransparent() ) + { + OSL_FAIL( "Missing implementation: Animation-Transparency" ); + } +} + +} // end anonymous namespace struct GrfSimpleCacheObj { @@ -107,19 +301,6 @@ struct GrfSimpleCacheObj maGraphic( rGraphic ), maAttr( rAttr ) {} }; -// unique increasing ID for being able to detect the GraphicObject with the -// oldest last data changes -static sal_uLong aIncrementingTimeOfLastDataChange = 1; - -void GraphicObject::ImplAfterDataChange() -{ - // set unique timestamp ID of last data change - mnDataChangeTimeStamp = aIncrementingTimeOfLastDataChange++; - - // check memory footprint of all GraphicObjects managed and evtl. take action - mpGlobalMgr->ImplCheckSizeOfSwappedInGraphics(this); -} - GraphicObject::GraphicObject() : mbAutoSwapped(false) , mbIsInSwapIn(false) @@ -127,7 +308,6 @@ GraphicObject::GraphicObject() { ImplEnsureGraphicManager(); ImplAssignGraphicData(); - mpGlobalMgr->ImplRegisterObj(*this, maGraphic, nullptr, nullptr); } GraphicObject::GraphicObject(const Graphic& rGraphic) @@ -138,7 +318,6 @@ GraphicObject::GraphicObject(const Graphic& rGraphic) { ImplEnsureGraphicManager(); ImplAssignGraphicData(); - mpGlobalMgr->ImplRegisterObj(*this, maGraphic, nullptr, nullptr); } GraphicObject::GraphicObject(const GraphicObject& rGraphicObj) @@ -152,20 +331,12 @@ GraphicObject::GraphicObject(const GraphicObject& rGraphicObj) , mbIsInSwapOut(false) { ImplAssignGraphicData(); - mpGlobalMgr->ImplRegisterObj(*this, maGraphic, nullptr, &rGraphicObj); if( rGraphicObj.HasUserData() && rGraphicObj.IsSwappedOut() ) SetSwapState(); } GraphicObject::~GraphicObject() { - mpGlobalMgr->ImplUnregisterObj( *this ); - - if (!mpGlobalMgr->ImplHasObjects()) - { - delete mpGlobalMgr; - mpGlobalMgr = nullptr; - } } void GraphicObject::ImplAssignGraphicData() @@ -178,33 +349,10 @@ void GraphicObject::ImplAssignGraphicData() mbAnimated = maGraphic.IsAnimated(); mbEPS = maGraphic.IsEPS(); mnAnimationLoopCount = ( mbAnimated ? maGraphic.GetAnimationLoopCount() : 0 ); - - // Handle evtl. needed AfterDataChanges - ImplAfterDataChange(); } void GraphicObject::ImplEnsureGraphicManager() { - if (mpGlobalMgr) - return; - - sal_uLong nCacheSize = 20000; - sal_uLong nMaxObjCacheSize = 20000; - sal_uLong nTimeoutSeconds = 20000; - if (!utl::ConfigManager::IsFuzzing()) - { - try - { - nCacheSize = officecfg::Office::Common::Cache::GraphicManager::TotalCacheSize::get(); - nMaxObjCacheSize = officecfg::Office::Common::Cache::GraphicManager::ObjectCacheSize::get(); - nTimeoutSeconds = officecfg::Office::Common::Cache::GraphicManager::ObjectReleaseTime::get(); - } - catch (...) - { - } - } - mpGlobalMgr = new GraphicManager(nCacheSize, nMaxObjCacheSize); - mpGlobalMgr->SetCacheTimeout(nTimeoutSeconds); } void GraphicObject::ImplAutoSwapIn() @@ -259,9 +407,6 @@ void GraphicObject::ImplAutoSwapIn() } mbIsInSwapIn = false; - - if (!mbAutoSwapped) - mpGlobalMgr->ImplGraphicObjectWasSwappedIn( *this ); } ImplAssignGraphicData(); } @@ -339,8 +484,6 @@ GraphicObject& GraphicObject::operator=( const GraphicObject& rGraphicObj ) { if( &rGraphicObj != this ) { - mpGlobalMgr->ImplUnregisterObj( *this ); - maSwapStreamHdl = Link<const GraphicObject*, SvStream*>(); mxSimpleCache.reset(); @@ -350,7 +493,6 @@ GraphicObject& GraphicObject::operator=( const GraphicObject& rGraphicObj ) maUserData = rGraphicObj.maUserData; ImplAssignGraphicData(); mbAutoSwapped = false; - mpGlobalMgr->ImplRegisterObj( *this, maGraphic, nullptr, &rGraphicObj ); if( rGraphicObj.HasUserData() && rGraphicObj.IsSwappedOut() ) SetSwapState(); } @@ -370,7 +512,7 @@ OString GraphicObject::GetUniqueID() const if ( !IsInSwapIn() && IsEPS() ) const_cast<GraphicObject*>(this)->FireSwapInRequest(); - return mpGlobalMgr->ImplGetUniqueID(*this); + return GetGraphic().getUniqueID(); } SvStream* GraphicObject::GetSwapStream() const @@ -455,29 +597,6 @@ void GraphicObject::FireSwapOutRequest() ImplAutoSwapOutHdl( nullptr ); } -bool GraphicObject::IsCached( OutputDevice const * pOut, const Size& rSz, - const GraphicAttr* pAttr, GraphicManagerDrawFlags nFlags ) const -{ - bool bRet; - - if( nFlags & GraphicManagerDrawFlags::CACHED ) - { - Point aPt; - Size aSz( rSz ); - if ( pAttr && pAttr->IsCropped() ) - { - tools::PolyPolygon aClipPolyPoly; - bool bRectClip; - ImplGetCropParams( pOut, aPt, aSz, pAttr, aClipPolyPoly, bRectClip ); - } - bRet = mpGlobalMgr->IsInCache( pOut, aPt, aSz, *this, ( pAttr ? *pAttr : GetAttr() ) ); - } - else - bRet = false; - - return bRet; -} - bool GraphicObject::Draw( OutputDevice* pOut, const Point& rPt, const Size& rSz, const GraphicAttr* pAttr, GraphicManagerDrawFlags nFlags ) { @@ -486,7 +605,6 @@ bool GraphicObject::Draw( OutputDevice* pOut, const Point& rPt, const Size& rSz, Size aSz( rSz ); const DrawModeFlags nOldDrawMode = pOut->GetDrawMode(); bool bCropped = aAttr.IsCropped(); - bool bCached = false; bool bRet; // #i29534# Provide output rects for PDF writer @@ -535,23 +653,13 @@ bool GraphicObject::Draw( OutputDevice* pOut, const Point& rPt, const Size& rSz, } } - bRet = mpGlobalMgr->DrawObj( pOut, aPt, aSz, *this, aAttr, nFlags, bCached ); + bRet = lclDrawObj(pOut, aPt, aSz, *this, aAttr); if( bCropped ) pOut->Pop(); pOut->SetDrawMode( nOldDrawMode ); - // #i29534# Moved below OutDev restoration, to avoid multiple swap-ins - // (code above needs to call GetGraphic twice) - if( bCached ) - { - if (mxSwapOutTimer) - mxSwapOutTimer->Start(); - else - FireSwapOutRequest(); - } - return bRet; } @@ -656,10 +764,8 @@ const Graphic& GraphicObject::GetGraphic() const return maGraphic; } -void GraphicObject::SetGraphic( const Graphic& rGraphic, const GraphicObject* pCopyObj ) +void GraphicObject::SetGraphic( const Graphic& rGraphic, const GraphicObject* /*pCopyObj*/ ) { - mpGlobalMgr->ImplUnregisterObj( *this ); - if (mxSwapOutTimer) mxSwapOutTimer->Stop(); @@ -669,12 +775,8 @@ void GraphicObject::SetGraphic( const Graphic& rGraphic, const GraphicObject* pC maLink.clear(); mxSimpleCache.reset(); - mpGlobalMgr->ImplRegisterObj( *this, maGraphic, nullptr, pCopyObj); - if (mxSwapOutTimer) mxSwapOutTimer->Start(); - - } void GraphicObject::SetGraphic( const Graphic& rGraphic, const OUString& rLink ) @@ -913,7 +1015,7 @@ Graphic GraphicObject::GetTransformedGraphic( const Size& rDestSize, const MapMo return aTransGraphic; } -Graphic GraphicObject::GetTransformedGraphic( const GraphicAttr* pAttr ) const // TODO: Change to Impl +Graphic GraphicObject::GetTransformedGraphic( const GraphicAttr* pAttr ) const { GetGraphic(); @@ -929,21 +1031,21 @@ Graphic GraphicObject::GetTransformedGraphic( const GraphicAttr* pAttr ) const / if( IsAnimated() ) { Animation aAnimation( maGraphic.GetAnimation() ); - GraphicManager::ImplAdjust( aAnimation, aAttr, GraphicAdjustmentFlags::ALL ); + lclImplAdjust( aAnimation, aAttr, GraphicAdjustmentFlags::ALL ); aAnimation.SetLoopCount( mnAnimationLoopCount ); aGraphic = aAnimation; } else { BitmapEx aBmpEx( maGraphic.GetBitmapEx() ); - GraphicManager::ImplAdjust( aBmpEx, aAttr, GraphicAdjustmentFlags::ALL ); + lclImplAdjust( aBmpEx, aAttr, GraphicAdjustmentFlags::ALL ); aGraphic = aBmpEx; } } else { GDIMetaFile aMtf( maGraphic.GetGDIMetaFile() ); - GraphicManager::ImplAdjust( aMtf, aAttr, GraphicAdjustmentFlags::ALL ); + lclImplAdjust( aMtf, aAttr, GraphicAdjustmentFlags::ALL ); aGraphic = aMtf; } } @@ -967,9 +1069,6 @@ bool GraphicObject::SwapOut() { const bool bRet = !mbAutoSwapped && maGraphic.SwapOut(); - if (bRet) - mpGlobalMgr->ImplGraphicObjectWasSwappedOut( *this ); - return bRet; } @@ -988,9 +1087,6 @@ bool GraphicObject::SwapOut( SvStream* pOStm ) { bRet = bRet && maGraphic.SwapOut( pOStm ); } - - if (bRet) - mpGlobalMgr->ImplGraphicObjectWasSwappedOut(*this); } catch(...) { @@ -1012,9 +1108,6 @@ bool GraphicObject::SwapIn() else { bRet = maGraphic.SwapIn(); - - if (bRet) - mpGlobalMgr->ImplGraphicObjectWasSwappedIn(*this); } if( bRet ) @@ -1035,8 +1128,6 @@ void GraphicObject::SetSwapState() if( !IsSwappedOut() ) { mbAutoSwapped = true; - - mpGlobalMgr->ImplGraphicObjectWasSwappedOut(*this); } } diff --git a/vcl/source/graphic/GraphicObject2.cxx b/vcl/source/graphic/GraphicObject2.cxx index e46b035f60b7..da5f61f588a1 100644 --- a/vcl/source/graphic/GraphicObject2.cxx +++ b/vcl/source/graphic/GraphicObject2.cxx @@ -31,1562 +31,10 @@ #include <vcl/animate.hxx> #include <vcl/alpha.hxx> #include <vcl/virdev.hxx> -#include "grfcache.hxx" #include <vcl/GraphicObject.hxx> #include <bitmapwriteaccess.hxx> #include <memory> - -#define WATERMARK_LUM_OFFSET 50 -#define WATERMARK_CON_OFFSET -70 - -namespace { - -constexpr sal_uInt8 MAP(long cVal0, long cVal1, long nFrac) { - return static_cast<sal_uInt8>(((cVal0<<20)+nFrac*(cVal1-cVal0))>>20); -} - -} - -GraphicManager::GraphicManager( sal_uLong nCacheSize, sal_uLong nMaxObjCacheSize ) : - mnUsedSize(0), - mpCache( new GraphicCache( nCacheSize, nMaxObjCacheSize ) ) -{ -} - -GraphicManager::~GraphicManager() -{ - assert(maObjList.empty()); - mpCache.reset(); -} - -void GraphicManager::SetMaxCacheSize( sal_uLong nNewCacheSize ) -{ - mpCache->SetMaxDisplayCacheSize( nNewCacheSize ); -} - -sal_uLong GraphicManager::GetMaxCacheSize() const -{ - return mpCache->GetMaxDisplayCacheSize(); -} - -void GraphicManager::SetCacheTimeout( sal_uLong nTimeoutSeconds ) -{ - mpCache->SetCacheTimeout( nTimeoutSeconds ); -} - -bool GraphicManager::IsInCache( OutputDevice const * pOut, const Point& rPt, - const Size& rSz, const GraphicObject& rObj, - const GraphicAttr& rAttr ) const -{ - return mpCache->IsInDisplayCache( pOut, rPt, rSz, rObj, rAttr ); -} - -bool GraphicManager::DrawObj( OutputDevice* pOut, const Point& rPt, const Size& rSz, - GraphicObject const & rObj, const GraphicAttr& rAttr, - const GraphicManagerDrawFlags nFlags, bool& rCached ) -{ - Point aPt( rPt ); - Size aSz( rSz ); - bool bRet = false; - - rCached = false; - - if( ( rObj.GetType() == GraphicType::Bitmap ) || ( rObj.GetType() == GraphicType::GdiMetafile ) ) - { - // create output and fill cache - - if( rObj.IsAnimated() || ( pOut->GetOutDevType() == OUTDEV_PRINTER ) || - ( !( nFlags & GraphicManagerDrawFlags::NO_SUBSTITUTE ) && - ( ( nFlags & GraphicManagerDrawFlags::SUBSTITUTE ) || - !( nFlags & GraphicManagerDrawFlags::CACHED ) || - ( pOut->GetConnectMetaFile() && !pOut->IsOutputEnabled() ) ) ) ) - { - // simple output of transformed graphic - const Graphic aGraphic( rObj.GetTransformedGraphic( &rAttr ) ); - - if( aGraphic.IsSupportedGraphic() ) - { - const sal_uInt16 nRot10 = rAttr.GetRotation() % 3600; - - if( nRot10 ) - { - tools::Polygon aPoly( tools::Rectangle( aPt, aSz ) ); - - aPoly.Rotate( aPt, nRot10 ); - const tools::Rectangle aRotBoundRect( aPoly.GetBoundRect() ); - aPt = aRotBoundRect.TopLeft(); - aSz = aRotBoundRect.GetSize(); - } - - aGraphic.Draw( pOut, aPt, aSz ); - } - - bRet = true; - } - - if( !bRet ) - { - // cached/direct drawing - if( !mpCache->DrawDisplayCacheObj( pOut, aPt, aSz, rObj, rAttr ) ) - bRet = ImplDraw( pOut, aPt, aSz, rObj, rAttr, rCached ); - else - bRet = rCached = true; - } - } - - return bRet; -} - -void GraphicManager::ImplRegisterObj( const GraphicObject& rObj, Graphic& rSubstitute, - const OString* pID, const GraphicObject* pCopyObj ) -{ - assert(maObjList.find(const_cast<GraphicObject*>(&rObj)) == maObjList.end()); - - maObjList.emplace( const_cast<GraphicObject*>(&rObj) ); - - mpCache->AddGraphicObject( rObj, rSubstitute, pID, pCopyObj ); - if( !rObj.IsSwappedOut() ) - mnUsedSize += rObj.maGraphic.GetSizeBytes(); -} - -void GraphicManager::ImplUnregisterObj( const GraphicObject& rObj ) -{ - mpCache->ReleaseGraphicObject( rObj ); - if( !rObj.IsSwappedOut() ) - { - assert(mnUsedSize >= rObj.maGraphic.GetSizeBytes()); - mnUsedSize -= rObj.maGraphic.GetSizeBytes(); - } - if ( 0 < maObjList.erase( const_cast<GraphicObject*>(&rObj) ) ) - return; - - assert(false); // surely it should have been registered? -} - -void GraphicManager::ImplGraphicObjectWasSwappedOut( const GraphicObject& rObj ) -{ - mpCache->GraphicObjectWasSwappedOut( rObj ); - assert(mnUsedSize >= rObj.GetSizeBytes()); - mnUsedSize -= rObj.GetSizeBytes(); -} - -OString GraphicManager::ImplGetUniqueID( const GraphicObject& rObj ) const -{ - return mpCache->GetUniqueID( rObj ); -} - -namespace -{ - struct simpleSortByDataChangeTimeStamp - { - bool operator() (GraphicObject const * p1, GraphicObject const * p2) const - { - return p1->GetDataChangeTimeStamp() < p2->GetDataChangeTimeStamp(); - } - }; -} // end of anonymous namespace - -void GraphicManager::ImplCheckSizeOfSwappedInGraphics(const GraphicObject* pGraphicToIgnore) -{ - // detect maximum allowed memory footprint. Use the user-settings of MaxCacheSize (defaulted - // to 200MB). - const sal_uLong nMaxCacheSize(GetMaxCacheSize()); - - if(mnUsedSize <= nMaxCacheSize) - return; - - // Copy the object list for now, because maObjList can change in the meantime unexpectedly. - std::vector< GraphicObject* > aCandidates(maObjList.begin(), maObjList.end()); - // if we use more currently, sort by last DataChangeTimeStamp - // sort by DataChangeTimeStamp so that the oldest get removed first - std::sort(aCandidates.begin(), aCandidates.end(), simpleSortByDataChangeTimeStamp()); - - for(decltype(aCandidates)::size_type a(0); mnUsedSize >= nMaxCacheSize && a < aCandidates.size(); a++) - { - // swap out until we have no more or the goal to use less than nMaxCacheSize - // is reached - GraphicObject* pObj = aCandidates[a]; - if( pObj == pGraphicToIgnore ) - { - continue; - } - if (maObjList.find(pObj) == maObjList.end()) - { - // object has been deleted when swapping out another one - continue; - } - - // do not swap out when we have less than 16KB data objects - if(pObj->GetSizeBytes() >= (16 * 1024)) - { - pObj->FireSwapOutRequest(); - } - } -} - -void GraphicManager::ImplGraphicObjectWasSwappedIn( const GraphicObject& rObj ) -{ - mpCache->GraphicObjectWasSwappedIn( rObj ); - mnUsedSize += rObj.maGraphic.GetSizeBytes(); -} - -bool GraphicManager::ImplDraw( OutputDevice* pOut, const Point& rPt, - const Size& rSz, GraphicObject const & rObj, - const GraphicAttr& rAttr, - bool& rCached ) -{ - const Graphic& rGraphic = rObj.GetGraphic(); - bool bRet = false; - - if( rGraphic.IsSupportedGraphic() && !rObj.IsSwappedOut() ) - { - if( GraphicType::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() & ( DrawModeFlags::BlackBitmap | DrawModeFlags::WhiteBitmap )) && - mpCache->IsDisplayCacheable( pOut, rPt, rSz, rObj, rAttr ) ) - { - BitmapEx aDstBmpEx; - - if( ImplCreateOutput( pOut, rPt, rSz, aSrcBmpEx, rAttr, &aDstBmpEx ) ) - { - rCached = mpCache->CreateDisplayCacheObj( pOut, rPt, rSz, rObj, rAttr, aDstBmpEx ); - bRet = true; - } - } - - if( !bRet ) - bRet = ImplCreateOutput( pOut, rPt, rSz, aSrcBmpEx, rAttr ); - } - 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, 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, &aDstBmpEx ) ) - { - rCached = mpCache->CreateDisplayCacheObj( pOut, rPt, rSz, rObj, rAttr, aDstBmpEx ); - bRet = true; - } - } - else - { - rCached = mpCache->CreateDisplayCacheObj( pOut, rPt, rSz, rObj, rAttr, aDstMtf ); - bRet = true; - } - } - } - - if( !bRet ) - { - const Graphic aGraphic( rObj.GetTransformedGraphic( &rAttr ) ); - - if( aGraphic.IsSupportedGraphic() ) - { - aGraphic.Draw( pOut, rPt, rSz ); - bRet = true; - } - } - } - } - - return bRet; -} - -bool 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(); - const long aBitmapWidth = rBmpEx.GetSizePixel().Width(); - const long aBitmapHeight = rBmpEx.GetSizePixel().Height(); - - long nTmpX, nTmpY, nTmpFX, nTmpFY, nTmp; - double fTmp; - - bool bHMirr( rAttributes.GetMirrorFlags() & BmpMirrorFlags::Horizontal ); - bool bVMirr( rAttributes.GetMirrorFlags() & BmpMirrorFlags::Vertical ); - - std::unique_ptr<long[]> pMapIX(new long[ aUnrotatedWidth ]); - std::unique_ptr<long[]> pMapFX(new long[ aUnrotatedWidth ]); - std::unique_ptr<long[]> pMapIY(new long[ aUnrotatedHeight ]); - std::unique_ptr<long[]> pMapFY(new long[ aUnrotatedHeight ]); - - double fRevScaleX; - double fRevScaleY; - - bool scaleByAveraging = false; - - if(aBitmapWidth > 1 && aUnrotatedWidth > 1) - { - fRevScaleX = static_cast<double>( aBitmapWidth - 1 ) / static_cast<double>( aUnrotatedWidth - 1 ); - // create horizontal mapping table - long x; - for( x = 0, nTmpX = aBitmapWidth - 1, nTmp = aBitmapWidth - 2 >= 0 ? aBitmapWidth -2 : 0L; x < aUnrotatedWidth; x++ ) - { - fTmp = x * fRevScaleX; - - if( bHMirr ) - fTmp = nTmpX - fTmp; - - pMapIX[ x ] = MinMax( fTmp, 0, nTmp ); - pMapFX[ x ] = static_cast<long>( ( fTmp - pMapIX[ x ] ) * 1048576.0 ); - } - scaleByAveraging |= fRevScaleX > 5.0/3.0; - } - else - { - if(aBitmapWidth == 1) - { - fRevScaleX = 1.0 / static_cast<double>(aUnrotatedWidth); - for ( long x = 0; x < aUnrotatedWidth ; x++) - { - pMapIX[x] = 0; - pMapFX[x] = 0; - } - scaleByAveraging = true; - } - else - { - fRevScaleX = static_cast<double>(aBitmapWidth) / static_cast<double>(aUnrotatedWidth); - fTmp = static_cast<double>(aBitmapWidth) / 2.0; - - pMapIX[ 0 ] = static_cast<long>(fTmp); - pMapFX[ 0 ] = static_cast<long>( ( fTmp - pMapIX[ 0 ] ) * 1048576.0 ); - scaleByAveraging = true; - } - } - if(aBitmapHeight > 1 && aUnrotatedHeight > 1) - { - fRevScaleY = static_cast<double>( aBitmapHeight - 1 ) / static_cast<double>( aUnrotatedHeight - 1 ); - // create vertical mapping table - long y; - for( y = 0, nTmpY = aBitmapHeight - 1, nTmp = aBitmapHeight - 2 >= 0 ? aBitmapHeight - 2 : 0L; y < aUnrotatedHeight; y++ ) - { - fTmp = y * fRevScaleY; - - if( bVMirr ) - fTmp = nTmpY - fTmp; - - pMapIY[ y ] = MinMax( fTmp, 0, nTmp ); - pMapFY[ y ] = static_cast<long>( ( fTmp - pMapIY[ y ] ) * 1048576.0 ); - } - scaleByAveraging |= fRevScaleY > 5.0/3.0; - } - else - { - if(aBitmapHeight == 1) - { - fRevScaleY = 1.0 / static_cast<double>(aUnrotatedHeight); - for (long y = 0; y < aUnrotatedHeight; ++y) - { - pMapIY[y] = 0; - pMapFY[y] = 0; - } - scaleByAveraging = true; - } - else - { - fRevScaleY = static_cast<double>(aBitmapHeight) / static_cast<double>(aUnrotatedHeight); - fTmp = static_cast<double>(aBitmapHeight) / 2.0; - - pMapIY[ 0 ] = static_cast<long>(fTmp); - pMapFY[ 0 ] = static_cast<long>( ( fTmp - pMapIY[ 0 ] ) * 1048576.0 ); - scaleByAveraging = true; - } - } - - Bitmap aBmp( rBmpEx.GetBitmap() ); - Bitmap aOutBmp; - BitmapReadAccess* pReadAccess = aBmp.AcquireReadAccess(); - BitmapWriteAccess* pWriteAccess; - - const double fCosAngle = cos( nRot10 * F_PI1800 ); - const double fSinAngle = sin( nRot10 * F_PI1800 ); - const long aTargetWidth = nEndX - nStartX + 1; - const long aTargetHeight = nEndY - nStartY + 1; - std::unique_ptr<long[]> pCosX(new long[ aTargetWidth ]); - std::unique_ptr<long[]> pSinX(new long[ aTargetWidth ]); - std::unique_ptr<long[]> pCosY(new long[ aTargetHeight ]); - std::unique_ptr<long[]> pSinY(new long[ aTargetHeight ]); - long nUnRotX, nUnRotY, nSinY, nCosY; - sal_uInt8 cR0, cG0, cB0, cR1, cG1, cB1; - bool bRet = false; - - tools::Polygon aPoly( tools::Rectangle( Point(), rUnrotatedSzPix ) ); - aPoly.Rotate( Point(), nRot10 ); - tools::Rectangle aNewBound( aPoly.GetBoundRect() ); - - // create horizontal mapping table - long x; - for( x = 0, nTmpX = aNewBound.Left() + nStartX; x < aTargetWidth; x++ ) - { - pCosX[ x ] = FRound( fCosAngle * ( fTmp = nTmpX++ << 8 ) ); - pSinX[ x ] = FRound( fSinAngle * fTmp ); - } - - // create vertical mapping table - long y; - for( y = 0, nTmpY = aNewBound.Top() + nStartY; y < aTargetHeight; y++ ) - { - pCosY[ y ] = FRound( fCosAngle * ( fTmp = nTmpY++ << 8 ) ); - pSinY[ y ] = FRound( fSinAngle * fTmp ); - } - - if( pReadAccess ) - { - aOutBmp = Bitmap( Size( aTargetWidth, aTargetHeight ), 24 ); - pWriteAccess = aOutBmp.AcquireWriteAccess(); - - if( pWriteAccess ) - { - BitmapColor aColRes; - - if ( !scaleByAveraging ) - { - if( pReadAccess->HasPalette() ) - { - for( y = 0; y < aTargetHeight; y++ ) - { - nSinY = pSinY[ y ]; - nCosY = pCosY[ y ]; - - Scanline pScanline = pWriteAccess->GetScanline( y ); - for( x = 0; x < aTargetWidth; x++ ) - { - nUnRotX = ( pCosX[ x ] - nSinY ) >> 8; - nUnRotY = ( pSinX[ x ] + nCosY ) >> 8; - - if( ( nUnRotX >= 0 ) && ( nUnRotX < aUnrotatedWidth ) && - ( nUnRotY >= 0 ) && ( nUnRotY < aUnrotatedHeight ) ) - { - nTmpX = pMapIX[ nUnRotX ]; - nTmpFX = pMapFX[ nUnRotX ]; - nTmpY = pMapIY[ nUnRotY ]; - nTmpFY = pMapFY[ nUnRotY ]; - - const BitmapColor& rCol0 = pReadAccess->GetPaletteColor( pReadAccess->GetPixelIndex( nTmpY, nTmpX ) ); - const BitmapColor& rCol1 = pReadAccess->GetPaletteColor( pReadAccess->GetPixelIndex( nTmpY, ++nTmpX ) ); - cR0 = MAP( rCol0.GetRed(), rCol1.GetRed(), nTmpFX ); - cG0 = MAP( rCol0.GetGreen(), rCol1.GetGreen(), nTmpFX ); - cB0 = MAP( rCol0.GetBlue(), rCol1.GetBlue(), nTmpFX ); - - const BitmapColor& rCol3 = pReadAccess->GetPaletteColor( pReadAccess->GetPixelIndex( ++nTmpY, nTmpX ) ); - const BitmapColor& rCol2 = pReadAccess->GetPaletteColor( pReadAccess->GetPixelIndex( nTmpY, --nTmpX ) ); - cR1 = MAP( rCol2.GetRed(), rCol3.GetRed(), nTmpFX ); - cG1 = MAP( rCol2.GetGreen(), rCol3.GetGreen(), nTmpFX ); - cB1 = MAP( rCol2.GetBlue(), rCol3.GetBlue(), nTmpFX ); - - aColRes.SetRed( MAP( cR0, cR1, nTmpFY ) ); - aColRes.SetGreen( MAP( cG0, cG1, nTmpFY ) ); - aColRes.SetBlue( MAP( cB0, cB1, nTmpFY ) ); - pWriteAccess->SetPixelOnData( pScanline, x, aColRes ); - } - } - } - } - else - { - BitmapColor aCol0, aCol1; - - for( y = 0; y < aTargetHeight; y++ ) - { - nSinY = pSinY[ y ]; - nCosY = pCosY[ y ]; - - Scanline pScanline = pWriteAccess->GetScanline( y ); - for( x = 0; x < aTargetWidth; x++ ) - { - nUnRotX = ( pCosX[ x ] - nSinY ) >> 8; - nUnRotY = ( pSinX[ x ] + nCosY ) >> 8; - - if( ( nUnRotX >= 0 ) && ( nUnRotX < aUnrotatedWidth ) && - ( nUnRotY >= 0 ) && ( nUnRotY < aUnrotatedHeight ) ) - { - nTmpX = pMapIX[ nUnRotX ]; - nTmpFX = pMapFX[ nUnRotX ]; - nTmpY = pMapIY[ nUnRotY ]; - nTmpFY = pMapFY[ nUnRotY ]; - - aCol0 = pReadAccess->GetPixel( nTmpY, nTmpX ); - aCol1 = pReadAccess->GetPixel( nTmpY, ++nTmpX ); - cR0 = MAP( aCol0.GetRed(), aCol1.GetRed(), nTmpFX ); - cG0 = MAP( aCol0.GetGreen(), aCol1.GetGreen(), nTmpFX ); - cB0 = MAP( aCol0.GetBlue(), aCol1.GetBlue(), nTmpFX ); - - aCol1 = pReadAccess->GetPixel( ++nTmpY, nTmpX ); - aCol0 = pReadAccess->GetPixel( nTmpY, --nTmpX ); - cR1 = MAP( aCol0.GetRed(), aCol1.GetRed(), nTmpFX ); - cG1 = MAP( aCol0.GetGreen(), aCol1.GetGreen(), nTmpFX ); - cB1 = MAP( aCol0.GetBlue(), aCol1.GetBlue(), nTmpFX ); - - aColRes.SetRed( MAP( cR0, cR1, nTmpFY ) ); - aColRes.SetGreen( MAP( cG0, cG1, nTmpFY ) ); - aColRes.SetBlue( MAP( cB0, cB1, nTmpFY ) ); - pWriteAccess->SetPixelOnData( pScanline, x, aColRes ); - } - } - } - } - } - else // scaleByAveraging - { - double aSumRed, aSumGreen, aSumBlue, aCount; - BitmapColor aColor; - BitmapColor aResultColor; - - for( y = 0; y < aTargetHeight; y++ ) - { - nSinY = pSinY[ y ]; - nCosY = pCosY[ y ]; - - Scanline pScanline = pWriteAccess->GetScanline( y ); - for( x = 0; x < aTargetWidth; x++ ) - { - double aUnrotatedX = ( pCosX[ x ] - nSinY ) / 256.0; - double aUnrotatedY = ( pSinX[ x ] + nCosY ) / 256.0; - - if ( bHMirr ) - aUnrotatedX = aUnrotatedWidth - aUnrotatedX - 1; - if ( bVMirr ) - aUnrotatedY = aUnrotatedHeight - aUnrotatedY - 1; - - if( ( aUnrotatedX >= 0 ) && ( aUnrotatedX < aUnrotatedWidth ) && - ( aUnrotatedY >= 0 ) && ( aUnrotatedY < aUnrotatedHeight ) ) - { - double dYStart = ((aUnrotatedY + 0.5) * fRevScaleY) - 0.5; - double dYEnd = ((aUnrotatedY + 1.5) * fRevScaleY) - 0.5; - - int yStart = MinMax( dYStart, 0, aBitmapHeight - 1); - int yEnd = MinMax( dYEnd, 0, aBitmapHeight - 1); - - double dXStart = ((aUnrotatedX + 0.5) * fRevScaleX) - 0.5; - double dXEnd = ((aUnrotatedX + 1.5) * fRevScaleX) - 0.5; - - int xStart = MinMax( dXStart, 0, aBitmapWidth - 1); - int xEnd = MinMax( dXEnd, 0, aBitmapWidth - 1); - - aSumRed = aSumGreen = aSumBlue = 0.0; - aCount = 0; - - for (int yIn = yStart; yIn <= yEnd; yIn++) - { - Scanline pScanlineRead = pReadAccess->GetScanline( yIn ); - for (int xIn = xStart; xIn <= xEnd; xIn++) - { - if( pReadAccess->HasPalette() ) - aColor = pReadAccess->GetPaletteColor( pReadAccess->GetIndexFromData( pScanlineRead, xIn ) ); - else - aColor = pReadAccess->GetPixelFromData( pScanlineRead, xIn ); - - aSumRed += aColor.GetRed(); - aSumGreen += aColor.GetGreen(); - aSumBlue += aColor.GetBlue(); - - aCount++; - } - } - - aResultColor.SetRed( MinMax( aSumRed / aCount, 0, 255) ); - aResultColor.SetGreen( MinMax( aSumGreen / aCount, 0, 255) ); - aResultColor.SetBlue( MinMax( aSumBlue / aCount, 0, 255) ); - - pWriteAccess->SetPixelOnData( pScanline, x, aResultColor ); - } - } - } - } - - Bitmap::ReleaseAccess( pWriteAccess ); - bRet = true; - } - - Bitmap::ReleaseAccess( pReadAccess ); - } - - // mask processing - if( bRet && ( rBmpEx.IsTransparent() || ( nRot10 != 0 && nRot10 != 900 && nRot10 != 1800 && nRot10 != 2700 ) ) ) - { - bRet = false; - - if( rBmpEx.IsAlpha() ) - { - AlphaMask aAlpha( rBmpEx.GetAlpha() ); - AlphaMask aOutAlpha; - - pReadAccess = aAlpha.AcquireReadAccess(); - - if( pReadAccess ) - { - aOutAlpha = AlphaMask( Size( aTargetWidth, aTargetHeight ) ); - pWriteAccess = aOutAlpha.AcquireWriteAccess(); - - if( pWriteAccess ) - { - if( pReadAccess->GetScanlineFormat() == ScanlineFormat::N8BitPal && - pWriteAccess->GetScanlineFormat() == ScanlineFormat::N8BitPal ) - { - if ( !scaleByAveraging ) - { - Scanline pLine0, pLine1, pLineW; - - for( long nY = 0; nY < aTargetHeight; nY++ ) - { - nSinY = pSinY[ nY ]; - nCosY = pCosY[ nY ]; - pLineW = pWriteAccess->GetScanline( nY ); - - for( long nX = 0; nX < aTargetWidth; nX++ ) - { - nUnRotX = ( pCosX[ nX ] - nSinY ) >> 8; - nUnRotY = ( pSinX[ nX ] + nCosY ) >> 8; - - if( ( nUnRotX >= 0 ) && ( nUnRotX < aUnrotatedWidth ) && - ( nUnRotY >= 0 ) && ( nUnRotY < aUnrotatedHeight ) ) - { - nTmpX = pMapIX[ nUnRotX ]; - nTmpFX = pMapFX[ nUnRotX ]; - nTmpY = pMapIY[ nUnRotY ]; - nTmpFY = pMapFY[ nUnRotY ]; - - pLine0 = pReadAccess->GetScanline( nTmpY++ ); - pLine1 = pReadAccess->GetScanline( nTmpY ); - - const long nAlpha0 = pLine0[ nTmpX ]; - const long nAlpha2 = pLine1[ nTmpX++ ]; - const long nAlpha1 = pLine0[ nTmpX ]; - const long nAlpha3 = pLine1[ nTmpX ]; - const long n0 = MAP( nAlpha0, nAlpha1, nTmpFX ); - const long n1 = MAP( nAlpha2, nAlpha3, nTmpFX ); - - *pLineW++ = MAP( n0, n1, nTmpFY ); - } - else - *pLineW++ = 255; - } - } - } - else // scaleByAveraging - { - const BitmapColor aTrans( pWriteAccess->GetBestMatchingColor( COL_WHITE ) ); - BitmapColor aResultColor( 0 ); - double aSum, aCount; - - for( y = 0; y < aTargetHeight; y++ ) - { - nSinY = pSinY[ y ]; - nCosY = pCosY[ y ]; - Scanline pScanline = pWriteAccess->GetScanline( y ); - - for( x = 0; x < aTargetWidth; x++ ) - { - - double aUnrotatedX = ( pCosX[ x ] - nSinY ) / 256.0; - double aUnrotatedY = ( pSinX[ x ] + nCosY ) / 256.0; - - if ( bHMirr ) - aUnrotatedX = aUnrotatedWidth - aUnrotatedX - 1; - if ( bVMirr ) - aUnrotatedY = aUnrotatedHeight - aUnrotatedY - 1; - - if( ( aUnrotatedX >= 0 ) && ( aUnrotatedX < aUnrotatedWidth ) && - ( aUnrotatedY >= 0 ) && ( aUnrotatedY < aUnrotatedHeight ) ) - { - double dYStart = ((aUnrotatedY + 0.5) * fRevScaleY) - 0.5; - double dYEnd = ((aUnrotatedY + 1.5) * fRevScaleY) - 0.5; - - int yStart = MinMax( dYStart, 0, aBitmapHeight - 1); - int yEnd = MinMax( dYEnd, 0, aBitmapHeight - 1); - - double dXStart = ((aUnrotatedX + 0.5) * fRevScaleX) - 0.5; - double dXEnd = ((aUnrotatedX + 1.5) * fRevScaleX) - 0.5; - - int xStart = MinMax( dXStart, 0, aBitmapWidth - 1); - int xEnd = MinMax( dXEnd, 0, aBitmapWidth - 1); - - aSum = 0.0; - aCount = 0; - - for (int yIn = yStart; yIn <= yEnd; yIn++) - { - Scanline pScanlineRead = pReadAccess->GetScanline( yIn ); - for (int xIn = xStart; xIn <= xEnd; xIn++) - { - aSum += pReadAccess->GetPixelFromData( pScanlineRead, xIn ).GetIndex(); - aCount++; - } - } - aResultColor.SetIndex( MinMax( aSum / aCount, 0, 255) ); - pWriteAccess->SetPixelOnData( pScanline, x, aResultColor ); - } - else - { - pWriteAccess->SetPixelOnData( pScanline, x, aTrans ); - } - } - } - } - } - else - { - const BitmapColor aTrans( pWriteAccess->GetBestMatchingColor( COL_WHITE ) ); - BitmapColor aAlphaVal( 0 ); - - for( long nY = 0; nY < aTargetHeight; nY++ ) - { - nSinY = pSinY[ nY ]; - nCosY = pCosY[ nY ]; - Scanline pScanline = pWriteAccess->GetScanline( nY ); - - for( long nX = 0; nX < aTargetWidth; nX++ ) - { - nUnRotX = ( pCosX[ nX ] - nSinY ) >> 8; - nUnRotY = ( pSinX[ nX ] + nCosY ) >> 8; - - if( ( nUnRotX >= 0 ) && ( nUnRotX < aUnrotatedWidth ) && - ( nUnRotY >= 0 ) && ( nUnRotY < aUnrotatedHeight ) ) - { - nTmpX = pMapIX[ nUnRotX ]; - nTmpFX = pMapFX[ nUnRotX ]; - nTmpY = pMapIY[ nUnRotY ]; - nTmpFY = pMapFY[ nUnRotY ]; - - const long nAlpha0 = pReadAccess->GetPixel( nTmpY, nTmpX ).GetIndex(); - const long nAlpha1 = pReadAccess->GetPixel( nTmpY, ++nTmpX ).GetIndex(); - const long nAlpha3 = pReadAccess->GetPixel( ++nTmpY, nTmpX ).GetIndex(); - const long nAlpha2 = pReadAccess->GetPixel( nTmpY, --nTmpX ).GetIndex(); - const long n0 = MAP( nAlpha0, nAlpha1, nTmpFX ); - const long n1 = MAP( nAlpha2, nAlpha3, nTmpFX ); - - aAlphaVal.SetIndex( MAP( n0, n1, nTmpFY ) ); - pWriteAccess->SetPixelOnData( pScanline, nX, aAlphaVal ); - } - else - pWriteAccess->SetPixelOnData( pScanline, nX, aTrans ); - } - } - } - - aOutAlpha.ReleaseAccess( pWriteAccess ); - bRet = true; - } - - aAlpha.ReleaseAccess( pReadAccess ); - } - - if( bRet ) - rOutBmpEx = BitmapEx( aOutBmp, aOutAlpha ); - } - else - { - Bitmap aOutMsk( Size( aTargetWidth, aTargetHeight ), 1 ); - pWriteAccess = aOutMsk.AcquireWriteAccess(); - - if( pWriteAccess ) - { - Bitmap aMsk( rBmpEx.GetMask() ); - const BitmapColor aB( pWriteAccess->GetBestMatchingColor( COL_BLACK ) ); - const BitmapColor aW( pWriteAccess->GetBestMatchingColor( COL_WHITE ) ); - BitmapReadAccess* pMAcc = nullptr; - - if( !aMsk || ( ( pMAcc = aMsk.AcquireReadAccess() ) != nullptr ) ) - { - std::unique_ptr<long[]> pMapLX(new long[ aUnrotatedWidth ]); - std::unique_ptr<long[]> pMapLY(new long[ aUnrotatedHeight ]); - BitmapColor aTestB; - - if( pMAcc ) - aTestB = pMAcc->GetBestMatchingColor( COL_BLACK ); - - // create new horizontal mapping table - for( long nX = 0; nX < aUnrotatedWidth; nX++ ) - pMapLX[ nX ] = FRound( static_cast<double>(pMapIX[ nX ]) + pMapFX[ nX ] / 1048576.0 ); - - // create new vertical mapping table - for( long nY = 0; nY < aUnrotatedHeight; nY++ ) - pMapLY[ nY ] = FRound( static_cast<double>(pMapIY[ nY ]) + pMapFY[ nY ] / 1048576.0 ); - - // do mask rotation - for( long nY = 0; nY < aTargetHeight; nY++ ) - { - nSinY = pSinY[ nY ]; - nCosY = pCosY[ nY ]; - Scanline pScanline = pWriteAccess->GetScanline( nY ); - - for( long nX = 0; nX < aTargetWidth; nX++ ) - { - nUnRotX = ( pCosX[ nX ] - nSinY ) >> 8; - nUnRotY = ( pSinX[ nX ] + nCosY ) >> 8; - - if( ( nUnRotX >= 0 ) && ( nUnRotX < aUnrotatedWidth ) && - ( nUnRotY >= 0 ) && ( nUnRotY < aUnrotatedHeight ) ) - { - if( pMAcc ) - { - if( pMAcc->GetPixel( pMapLY[ nUnRotY ], pMapLX[ nUnRotX ] ) == aTestB ) - pWriteAccess->SetPixelOnData( pScanline, nX, aB ); - else - pWriteAccess->SetPixelOnData( pScanline, nX, aW ); - } - else - pWriteAccess->SetPixelOnData( pScanline, nX, aB ); - } - else - pWriteAccess->SetPixelOnData( pScanline, nX, aW ); - } - } - - pMapLX.reset(); - pMapLY.reset(); - - if( pMAcc ) - Bitmap::ReleaseAccess( pMAcc ); - - bRet = true; - } - - Bitmap::ReleaseAccess( pWriteAccess ); - } - - if( bRet ) - rOutBmpEx = BitmapEx( aOutBmp, aOutMsk ); - } - - if( !bRet ) - rOutBmpEx = aOutBmp; - } - else - rOutBmpEx = aOutBmp; - - return bRet; -} - -bool GraphicManager::ImplCreateOutput( OutputDevice* pOutputDevice, - const Point& rPoint, const Size& rSize, - const BitmapEx& rBitmapEx, const GraphicAttr& rAttributes, - BitmapEx* pBmpEx ) -{ - sal_uInt16 nRot10 = rAttributes.GetRotation() % 3600; - - Point aOutputPointPix; - Size aOutputSizePix; - Point aUnrotatedPointPix( pOutputDevice->LogicToPixel( rPoint ) ); - Size aUnrotatedSizePix( pOutputDevice->LogicToPixel( rSize ) ); - - bool bRet = false; - - if( nRot10 ) - { - tools::Polygon aPoly( tools::Rectangle( rPoint, rSize ) ); - aPoly.Rotate( rPoint, nRot10 ); - const tools::Rectangle aRotBoundRect( aPoly.GetBoundRect() ); - aOutputPointPix = pOutputDevice->LogicToPixel( aRotBoundRect.TopLeft() ); - aOutputSizePix = pOutputDevice->LogicToPixel( aRotBoundRect.GetSize() ); - } - else - { - aOutputPointPix = aUnrotatedPointPix; - aOutputSizePix = aUnrotatedSizePix; - } - - if( aUnrotatedSizePix.Width() && aUnrotatedSizePix.Height() ) - { - BitmapEx aOutBmpEx; - Point aOutPoint; - Size aOutSize; - const Size& rBmpSzPix = rBitmapEx.GetSizePixel(); - const long nW = rBmpSzPix.Width(); - const long nH = rBmpSzPix.Height(); - long nStartX = -1, nStartY = -1, nEndX = -1, nEndY = -1; - bool bHMirr( rAttributes.GetMirrorFlags() & BmpMirrorFlags::Horizontal ); - bool bVMirr( rAttributes.GetMirrorFlags() & BmpMirrorFlags::Vertical ); - - // calculate output sizes - if( !pBmpEx ) - { - tools::Rectangle aOutRect( Point(), pOutputDevice->GetOutputSizePixel() ); - tools::Rectangle aBmpRect( aOutputPointPix, aOutputSizePix ); - - if( pOutputDevice->GetOutDevType() == OUTDEV_WINDOW ) - { - const vcl::Region aPaintRgn( static_cast<vcl::Window*>( pOutputDevice )->GetPaintRegion() ); - if( !aPaintRgn.IsNull() ) - aOutRect.Intersection( pOutputDevice->LogicToPixel( aPaintRgn.GetBoundRect() ) ); - } - - aOutRect.Intersection( aBmpRect ); - - if( !aOutRect.IsEmpty() ) - { - aOutPoint = pOutputDevice->PixelToLogic( aOutRect.TopLeft() ); - aOutSize = pOutputDevice->PixelToLogic( aOutRect.GetSize() ); - nStartX = aOutRect.Left() - aBmpRect.Left(); - nStartY = aOutRect.Top() - aBmpRect.Top(); - nEndX = aOutRect.Right() - aBmpRect.Left(); - nEndY = aOutRect.Bottom() - aBmpRect.Top(); - } - else - { - nStartX = -1; // invalid - } - } - else - { - aOutPoint = pOutputDevice->PixelToLogic( aOutputPointPix ); - aOutSize = pOutputDevice->PixelToLogic( aOutputSizePix ); - nStartX = nStartY = 0; - nEndX = aOutputSizePix.Width() - 1; - nEndY = aOutputSizePix.Height() - 1; - } - - // do transformation - if( nStartX >= 0 ) - { - const bool bSimple = ( 1 == nW || 1 == nH ); - - if( nRot10 ) - { - if( bSimple ) - { - bRet = ( aOutBmpEx = rBitmapEx ).Scale( aUnrotatedSizePix ); - - if( bRet ) - aOutBmpEx.Rotate( nRot10, COL_TRANSPARENT ); - } - else - { - bRet = ImplCreateRotatedScaled( rBitmapEx, rAttributes, - nRot10, aUnrotatedSizePix, - nStartX, nEndX, nStartY, nEndY, - aOutBmpEx ); - } - } - else - { - if( !bHMirr && !bVMirr && aOutputSizePix == rBmpSzPix ) - { - aOutPoint = pOutputDevice->PixelToLogic( aOutputPointPix ); - aOutSize = pOutputDevice->PixelToLogic( aOutputSizePix ); - aOutBmpEx = rBitmapEx; - bRet = true; - } - else - { - if( bSimple ) - { - bRet = ( aOutBmpEx = rBitmapEx ).Scale( Size( nEndX - nStartX + 1, nEndY - nStartY + 1 ) ); - } - else - { - bRet = ImplCreateRotatedScaled( rBitmapEx, rAttributes, - nRot10, aUnrotatedSizePix, - nStartX, nEndX, nStartY, nEndY, - aOutBmpEx ); - } - } - } - - if( bRet ) - { - // Attribute adjustment if necessary - if( rAttributes.IsSpecialDrawMode() || rAttributes.IsAdjusted() || rAttributes.IsTransparent() ) - ImplAdjust( aOutBmpEx, rAttributes, GraphicAdjustmentFlags::DRAWMODE | GraphicAdjustmentFlags::COLORS | GraphicAdjustmentFlags::TRANSPARENCY ); - - // OutDev adjustment if necessary - if( pOutputDevice->GetOutDevType() != OUTDEV_PRINTER && pOutputDevice->GetBitCount() <= 8 && aOutBmpEx.GetBitCount() >= 8 ) - aOutBmpEx.Dither(); - } - } - - // Create output - if( bRet ) - { - if( !pBmpEx ) - pOutputDevice->DrawBitmapEx( aOutPoint, aOutSize, aOutBmpEx ); - else - { - if( !rAttributes.IsTransparent() && !aOutBmpEx.IsAlpha() ) - aOutBmpEx = BitmapEx( aOutBmpEx.GetBitmap().CreateDisplayBitmap( pOutputDevice ), aOutBmpEx.GetMask() ); - - pOutputDevice->DrawBitmapEx( aOutPoint, aOutSize, *pBmpEx = aOutBmpEx ); - } - } - } - - 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 - && std::abs( rDestSize.Width() - rRefSize.Width()) < 5 - && std::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 tools::Rectangle aCropRect( rSrcPoint, - rSrcSize ); - aBmpEx.Crop( aCropRect ); - } - - return aBmpEx; -} - -bool GraphicManager::ImplCreateOutput( OutputDevice* pOut, - const Point& rPt, const Size& rSz, - const GDIMetaFile& rMtf, const GraphicAttr& rAttr, - GDIMetaFile& rOutMtf, BitmapEx& rOutBmpEx ) -{ - const Size aNewSize( rMtf.GetPrefSize() ); - - rOutMtf = rMtf; - - // Count bitmap actions, and flag actions that paint, but - // are no bitmaps. - sal_Int32 nNumBitmaps(0); - bool bNonBitmapActionEncountered(false); - if( aNewSize.Width() && aNewSize.Height() && rSz.Width() && rSz.Height() ) - { - const double fGrfWH = static_cast<double>(aNewSize.Width()) / aNewSize.Height(); - const double fOutWH = static_cast<double>(rSz.Width()) / rSz.Height(); - - const double fScaleX = fOutWH / fGrfWH; - const double fScaleY = 1.0; - - const MapMode& rPrefMapMode( rMtf.GetPrefMapMode() ); - const Size rSizePix( pOut->LogicToPixel( aNewSize, rPrefMapMode ) ); - -// NOTE: If you do changes in this function, check GraphicDisplayCacheEntry::IsCacheableAsBitmap -// in grfcache.cxx too. - - // Determine whether the metafile basically displays - // a single bitmap (in which case that bitmap is simply used directly - // instead of playing the metafile). Note that - // the solution, as implemented here, is quite suboptimal (the - // cases where a mtf consisting basically of a single bitmap, - // that fail to pass the test below, are probably frequent). A - // better solution would involve FSAA, but that's currently - // expensive, and might trigger bugs on display drivers, if - // VDevs get bigger than the actual screen. - sal_uInt32 nCurPos; - MetaAction* pAct; - for( nCurPos = 0, pAct = rOutMtf.FirstAction(); pAct; - pAct = rOutMtf.NextAction(), nCurPos++ ) - { - MetaAction* pModAct = nullptr; - switch( pAct->GetType() ) - { - case MetaActionType::FONT: - { - // taking care of font width default if scaling metafile. - MetaFontAction* pA = static_cast<MetaFontAction*>(pAct); - vcl::Font aFont( pA->GetFont() ); - if ( !aFont.GetAverageFontWidth() ) - { - FontMetric aFontMetric( pOut->GetFontMetric( aFont ) ); - aFont.SetAverageFontWidth( aFontMetric.GetAverageFontWidth() ); - pModAct = new MetaFontAction( aFont ); - } - SAL_FALLTHROUGH; - } - case MetaActionType::NONE: - SAL_FALLTHROUGH; - - // OutDev state changes (which don't affect bitmap - // output) - case MetaActionType::LINECOLOR: - SAL_FALLTHROUGH; - case MetaActionType::FILLCOLOR: - SAL_FALLTHROUGH; - case MetaActionType::TEXTCOLOR: - SAL_FALLTHROUGH; - case MetaActionType::TEXTFILLCOLOR: - SAL_FALLTHROUGH; - case MetaActionType::TEXTALIGN: - SAL_FALLTHROUGH; - case MetaActionType::TEXTLINECOLOR: - SAL_FALLTHROUGH; - case MetaActionType::TEXTLINE: - SAL_FALLTHROUGH; - case MetaActionType::PUSH: - SAL_FALLTHROUGH; - case MetaActionType::POP: - SAL_FALLTHROUGH; - case MetaActionType::LAYOUTMODE: - SAL_FALLTHROUGH; - case MetaActionType::TEXTLANGUAGE: - SAL_FALLTHROUGH; - case MetaActionType::COMMENT: - break; - - // bitmap output methods - case MetaActionType::BMP: - if( !nNumBitmaps && !bNonBitmapActionEncountered ) - { - MetaBmpAction* pAction = static_cast<MetaBmpAction*>(pAct); - - rOutBmpEx = checkMetadataBitmap( - BitmapEx( pAction->GetBitmap()), - Point(), Size(), - pOut->LogicToPixel( pAction->GetPoint(), - rPrefMapMode ), - pAction->GetBitmap().GetSizePixel(), - rSizePix, - bNonBitmapActionEncountered ); - } - ++nNumBitmaps; - break; - - case MetaActionType::BMPSCALE: - if( !nNumBitmaps && !bNonBitmapActionEncountered ) - { - MetaBmpScaleAction* pAction = static_cast<MetaBmpScaleAction*>(pAct); - - rOutBmpEx = checkMetadataBitmap( - BitmapEx( pAction->GetBitmap()), - Point(), Size(), - pOut->LogicToPixel( pAction->GetPoint(), - rPrefMapMode ), - pOut->LogicToPixel( pAction->GetSize(), - rPrefMapMode ), - rSizePix, - bNonBitmapActionEncountered ); - } - ++nNumBitmaps; - break; - - case MetaActionType::BMPSCALEPART: - if( !nNumBitmaps && !bNonBitmapActionEncountered ) - { - MetaBmpScalePartAction* pAction = static_cast<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 MetaActionType::BMPEX: - if( !nNumBitmaps && !bNonBitmapActionEncountered ) - { - MetaBmpExAction* pAction = static_cast<MetaBmpExAction*>(pAct); - - rOutBmpEx = checkMetadataBitmap( - pAction->GetBitmapEx(), - Point(), Size(), - pOut->LogicToPixel( pAction->GetPoint(), - rPrefMapMode ), - pAction->GetBitmapEx().GetSizePixel(), - rSizePix, - bNonBitmapActionEncountered ); - } - ++nNumBitmaps; - break; - - case MetaActionType::BMPEXSCALE: - if( !nNumBitmaps && !bNonBitmapActionEncountered ) - { - MetaBmpExScaleAction* pAction = static_cast<MetaBmpExScaleAction*>(pAct); - - rOutBmpEx = checkMetadataBitmap( - pAction->GetBitmapEx(), - Point(), Size(), - pOut->LogicToPixel( pAction->GetPoint(), - rPrefMapMode ), - pOut->LogicToPixel( pAction->GetSize(), - rPrefMapMode ), - rSizePix, - bNonBitmapActionEncountered ); - } - ++nNumBitmaps; - break; - - case MetaActionType::BMPEXSCALEPART: - if( !nNumBitmaps && !bNonBitmapActionEncountered ) - { - MetaBmpExScalePartAction* pAction = static_cast<MetaBmpExScalePartAction*>(pAct); - - rOutBmpEx = checkMetadataBitmap( pAction->GetBitmapEx(), - pAction->GetSrcPoint(), - pAction->GetSrcSize(), - pOut->LogicToPixel( pAction->GetDestPoint(), - rPrefMapMode ), - pOut->LogicToPixel( pAction->GetDestSize(), - rPrefMapMode ), - rSizePix, - bNonBitmapActionEncountered ); - } - ++nNumBitmaps; - break; - - // these actions actually output something (that's - // different from a bitmap) - case MetaActionType::RASTEROP: - if( static_cast<MetaRasterOpAction*>(pAct)->GetRasterOp() == RasterOp::OverPaint ) - break; - SAL_FALLTHROUGH; - case MetaActionType::PIXEL: - SAL_FALLTHROUGH; - case MetaActionType::POINT: - SAL_FALLTHROUGH; - case MetaActionType::LINE: - SAL_FALLTHROUGH; - case MetaActionType::RECT: - SAL_FALLTHROUGH; - case MetaActionType::ROUNDRECT: - SAL_FALLTHROUGH; - case MetaActionType::ELLIPSE: - SAL_FALLTHROUGH; - case MetaActionType::ARC: - SAL_FALLTHROUGH; - case MetaActionType::PIE: - SAL_FALLTHROUGH; - case MetaActionType::CHORD: - SAL_FALLTHROUGH; - case MetaActionType::POLYLINE: - SAL_FALLTHROUGH; - case MetaActionType::POLYGON: - SAL_FALLTHROUGH; - case MetaActionType::POLYPOLYGON: - SAL_FALLTHROUGH; - - case MetaActionType::TEXT: - SAL_FALLTHROUGH; - case MetaActionType::TEXTARRAY: - SAL_FALLTHROUGH; - case MetaActionType::STRETCHTEXT: - SAL_FALLTHROUGH; - case MetaActionType::TEXTRECT: - SAL_FALLTHROUGH; - - case MetaActionType::MASK: - SAL_FALLTHROUGH; - case MetaActionType::MASKSCALE: - SAL_FALLTHROUGH; - case MetaActionType::MASKSCALEPART: - SAL_FALLTHROUGH; - - case MetaActionType::GRADIENT: - SAL_FALLTHROUGH; - case MetaActionType::HATCH: - SAL_FALLTHROUGH; - case MetaActionType::WALLPAPER: - SAL_FALLTHROUGH; - - case MetaActionType::Transparent: - SAL_FALLTHROUGH; - case MetaActionType::EPS: - SAL_FALLTHROUGH; - case MetaActionType::FLOATTRANSPARENT: - SAL_FALLTHROUGH; - case MetaActionType::GRADIENTEX: - SAL_FALLTHROUGH; - - // OutDev state changes that _do_ affect bitmap - // output - case MetaActionType::CLIPREGION: - SAL_FALLTHROUGH; - case MetaActionType::ISECTRECTCLIPREGION: - SAL_FALLTHROUGH; - case MetaActionType::ISECTREGIONCLIPREGION: - SAL_FALLTHROUGH; - case MetaActionType::MOVECLIPREGION: - SAL_FALLTHROUGH; - - case MetaActionType::MAPMODE: - SAL_FALLTHROUGH; - case MetaActionType::REFPOINT: - SAL_FALLTHROUGH; - default: - bNonBitmapActionEncountered = true; - break; - } - if ( pModAct ) - { - MetaAction* pDeleteAction = rOutMtf.ReplaceAction( pModAct, nCurPos ); - assert(pDeleteAction); - pDeleteAction->Delete(); - } - else - { - if( pAct->GetRefCount() > 1 ) - { - MetaAction* pDeleteAction = rOutMtf.ReplaceAction( pModAct = pAct->Clone(), nCurPos ); - assert(pDeleteAction); - pDeleteAction->Delete(); - } - else - pModAct = pAct; - } - pModAct->Scale( fScaleX, fScaleY ); - } - rOutMtf.SetPrefSize( Size( FRound( aNewSize.Width() * fScaleX ), - FRound( aNewSize.Height() * fScaleY ) ) ); - } - - if( nNumBitmaps != 1 || bNonBitmapActionEncountered ) - { - if( rAttr.IsSpecialDrawMode() || rAttr.IsAdjusted() || rAttr.IsMirrored() || rAttr.IsRotated() || rAttr.IsTransparent() ) - ImplAdjust( rOutMtf, rAttr, GraphicAdjustmentFlags::ALL ); - - ImplDraw( pOut, rPt, rSz, rOutMtf, rAttr ); - rOutBmpEx = BitmapEx(); - } - - return true; -} - -void GraphicManager::ImplAdjust( BitmapEx& rBmpEx, const GraphicAttr& rAttr, GraphicAdjustmentFlags nAdjustmentFlags ) -{ - GraphicAttr aAttr( rAttr ); - - if( ( nAdjustmentFlags & GraphicAdjustmentFlags::DRAWMODE ) && aAttr.IsSpecialDrawMode() ) - { - switch( aAttr.GetDrawMode() ) - { - case GraphicDrawMode::Mono: - rBmpEx.Convert( BmpConversion::N1BitThreshold ); - break; - - case GraphicDrawMode::Greys: - rBmpEx.Convert( BmpConversion::N8BitGreys ); - break; - - case GraphicDrawMode::Watermark: - { - aAttr.SetLuminance( aAttr.GetLuminance() + WATERMARK_LUM_OFFSET ); - aAttr.SetContrast( aAttr.GetContrast() + WATERMARK_CON_OFFSET ); - } - break; - - default: - break; - } - } - - if( ( nAdjustmentFlags & GraphicAdjustmentFlags::COLORS ) && aAttr.IsAdjusted() ) - { - rBmpEx.Adjust( aAttr.GetLuminance(), aAttr.GetContrast(), - aAttr.GetChannelR(), aAttr.GetChannelG(), aAttr.GetChannelB(), ... etc. - the rest is truncated _______________________________________________ Libreoffice-commits mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits
