Function to load graphic swapped out (loaded on demand)

When a document is loaded it takes a lot of time and memory to
load the graphic that are in the documet, so avoid that and just
store the compressed graphic into a temporary file (handeled by
GfxLink) and load when we really need to show the graphic.

GraphicObject cached some attributes from Graphic, but this
attributes now aren't available immediately so this attributes
are removed form GraphicObject and now delegate to the Graphic
itself. GetSizeBytes attribute however was removed as it is
only used in some tests.

GfxLink initial values were moved to the constructor and are
not set in the header file anymore (as it is the recommended
way to do it).

The SdImportTest::testDocumentLayout failed as it looks like the
dump sometimes didn't include the width and height of the null
bitmap (which is set to 32x32) of the FillBitmap in some
situations, but then in other situations it did include this
attributes. With this change the width and height are always
included for the FillBitmap which looks like it is more correct.

Change-Id: Ia1218f93b1735402b7828404f65660e2d4acf32f
Reviewed-on: https://gerrit.libreoffice.org/53016
Tested-by: Jenkins <ci@libreoffice.org>
Reviewed-by: Tomaž Vajngerl <quikee@gmail.com>
diff --git a/include/svx/svdograf.hxx b/include/svx/svdograf.hxx
index f3b0b19..9b1a463 100644
--- a/include/svx/svdograf.hxx
+++ b/include/svx/svdograf.hxx
@@ -156,8 +156,8 @@ public:
    bool IsEPS() const;
    bool IsSwappedOut() const;

    const MapMode&          GetGrafPrefMapMode() const;
    const Size&             GetGrafPrefSize() const;
    MapMode          GetGrafPrefMapMode() const;
    Size             GetGrafPrefSize() const;

    void                    SetGrafStreamURL( const OUString& rGraphicStreamURL );
    OUString const &        GetGrafStreamURL() const;
diff --git a/include/vcl/GraphicObject.hxx b/include/vcl/GraphicObject.hxx
index 140ea74..d9f60e4 100644
--- a/include/vcl/GraphicObject.hxx
+++ b/include/vcl/GraphicObject.hxx
@@ -172,19 +172,9 @@ class VCL_DLLPUBLIC GraphicObject
private:
    Graphic                 maGraphic;
    GraphicAttr             maAttr;
    Size                    maPrefSize;
    MapMode                 maPrefMapMode;
    sal_uLong               mnSizeBytes;
    GraphicType             meType;
    OUString                maUserData;
    std::unique_ptr<GrfSimpleCacheObj> mxSimpleCache;
    sal_uInt32              mnAnimationLoopCount;

    bool                    mbTransparent   : 1;
    bool                    mbAnimated      : 1;
    bool                    mbEPS           : 1;

    void                    VCL_DLLPRIVATE ImplAssignGraphicData();
    bool                    VCL_DLLPRIVATE ImplGetCropParams(
                                OutputDevice const * pOut,
                                Point& rPt,
@@ -342,13 +332,12 @@ public:

    OString                 GetUniqueID() const;

    GraphicType             GetType() const { return meType; }
    const Size&             GetPrefSize() const { return maPrefSize; }
    const MapMode&          GetPrefMapMode() const { return maPrefMapMode; }
    sal_uLong               GetSizeBytes() const { return mnSizeBytes; }
    bool                    IsTransparent() const { return mbTransparent; }
    bool                    IsAnimated() const { return mbAnimated; }
    bool                    IsEPS() const { return mbEPS; }
    GraphicType             GetType() const;
    Size                    GetPrefSize() const;
    MapMode                 GetPrefMapMode() const;
    bool                    IsTransparent() const;
    bool                    IsAnimated() const;
    bool                    IsEPS() const;

    bool                    Draw(
                                OutputDevice* pOut,
diff --git a/include/vcl/gfxlink.hxx b/include/vcl/gfxlink.hxx
index 2d84fd29..054ab2c 100644
--- a/include/vcl/gfxlink.hxx
+++ b/include/vcl/gfxlink.hxx
@@ -64,17 +64,17 @@ private:

    };

    GfxLinkType     meType = GfxLinkType::NONE;
    sal_uInt32      mnUserId = 0;
    GfxLinkType     meType;
    sal_uInt32      mnUserId;

    std::shared_ptr<sal_uInt8> mpSwapInData;
    std::shared_ptr<SwapOutData> mpSwapOutData;

    sal_uInt32      mnSwapInDataSize = 0;
    sal_uInt32      mnSwapInDataSize;
    MapMode         maPrefMapMode;
    Size            maPrefSize;
    bool            mbPrefMapModeValid = false;
    bool            mbPrefSizeValid = false;
    bool            mbPrefMapModeValid;
    bool            mbPrefSizeValid;

    SAL_DLLPRIVATE std::shared_ptr<sal_uInt8> GetSwapInData() const;
public:
diff --git a/include/vcl/graph.hxx b/include/vcl/graph.hxx
index d69b9e8..8406686 100644
--- a/include/vcl/graph.hxx
+++ b/include/vcl/graph.hxx
@@ -144,6 +144,9 @@ public:
    bool            IsAnimated() const;
    bool            IsEPS() const;

    bool isAvailable() const;
    bool makeAvailable();

    // #i102089# Access of Bitmap potentially will have to rasterconvert the Graphic
    // if it is a MetaFile. To be able to control this conversion it is necessary to
    // allow giving parameters which control AntiAliasing and LineSnapping of the
diff --git a/include/vcl/graphicfilter.hxx b/include/vcl/graphicfilter.hxx
index bc21885..adf3089 100644
--- a/include/vcl/graphicfilter.hxx
+++ b/include/vcl/graphicfilter.hxx
@@ -98,6 +98,7 @@ namespace o3tl
#define WMF_SHORTNAME           "WMF"
#define EMF_SHORTNAME           "EMF"
#define SVG_SHORTNAME           "SVG"
#define PDF_SHORTNAME           "PDF"

//  Info class for all supported file formats

@@ -289,6 +290,8 @@ public:
                                   css::uno::Sequence< css::beans::PropertyValue >* pFilterData,
                                   WmfExternal const *pExtHeader = nullptr );

    Graphic ImportUnloadedGraphic(SvStream& rIStream);

    const FilterErrorEx&    GetLastError() const { return *pErrorEx;}
    void                    ResetLastError();

diff --git a/include/vcl/salctype.hxx b/include/vcl/salctype.hxx
index 409fc5a..893adb4 100644
--- a/include/vcl/salctype.hxx
+++ b/include/vcl/salctype.hxx
@@ -37,7 +37,8 @@ enum class ConvertDataFormat
    TIF,
    WMF,
    EMF,
    SVG
    SVG,
    PDF
};

class SvStream;
diff --git a/sc/qa/extras/anchor.cxx b/sc/qa/extras/anchor.cxx
index 1407b78..133b1bd 100644
--- a/sc/qa/extras/anchor.cxx
+++ b/sc/qa/extras/anchor.cxx
@@ -87,7 +87,7 @@ void ScAnchorTest::testUndoAnchor()

    const GraphicObject& rGraphicObj = pObject->GetGraphicObject(true);
    CPPUNIT_ASSERT_EQUAL(int(GraphicType::Bitmap), int(rGraphicObj.GetGraphic().GetType()));
    CPPUNIT_ASSERT_EQUAL(sal_uLong(864900), rGraphicObj.GetSizeBytes());
    CPPUNIT_ASSERT_EQUAL(sal_uLong(864900), rGraphicObj.GetGraphic().GetSizeBytes());

    // Get the document controller
    ScTabViewShell* pViewShell = pDocSh->GetBestViewShell(false);
@@ -121,14 +121,14 @@ void ScAnchorTest::testUndoAnchor()
    // Check anchor type
    CPPUNIT_ASSERT_EQUAL(oldType, ScDrawLayer::GetAnchorType(*pObject));
    CPPUNIT_ASSERT_EQUAL(int(GraphicType::Bitmap), int(rGraphicObj.GetGraphic().GetType()));
    CPPUNIT_ASSERT_EQUAL(sal_uLong(864900), rGraphicObj.GetSizeBytes());
    CPPUNIT_ASSERT_EQUAL(sal_uLong(864900), rGraphicObj.GetGraphic().GetSizeBytes());

    pUndoMgr->Redo();

    // Check anchor type
    CPPUNIT_ASSERT_EQUAL(newType, ScDrawLayer::GetAnchorType(*pObject));
    CPPUNIT_ASSERT_EQUAL(int(GraphicType::Bitmap), int(rGraphicObj.GetGraphic().GetType()));
    CPPUNIT_ASSERT_EQUAL(sal_uLong(864900), rGraphicObj.GetSizeBytes());
    CPPUNIT_ASSERT_EQUAL(sal_uLong(864900), rGraphicObj.GetGraphic().GetSizeBytes());

    ScDrawLayer::SetPageAnchored(*pObject);
    // Check state
@@ -146,14 +146,14 @@ void ScAnchorTest::testUndoAnchor()
    // Check anchor type
    CPPUNIT_ASSERT_EQUAL(oldType, ScDrawLayer::GetAnchorType(*pObject));
    CPPUNIT_ASSERT_EQUAL(int(GraphicType::Bitmap), int(rGraphicObj.GetGraphic().GetType()));
    CPPUNIT_ASSERT_EQUAL(sal_uLong(864900), rGraphicObj.GetSizeBytes());
    CPPUNIT_ASSERT_EQUAL(sal_uLong(864900), rGraphicObj.GetGraphic().GetSizeBytes());

    pUndoMgr->Redo();

    // Check anchor type
    CPPUNIT_ASSERT_EQUAL(newType, ScDrawLayer::GetAnchorType(*pObject));
    CPPUNIT_ASSERT_EQUAL(int(GraphicType::Bitmap), int(rGraphicObj.GetGraphic().GetType()));
    CPPUNIT_ASSERT_EQUAL(sal_uLong(864900), rGraphicObj.GetSizeBytes());
    CPPUNIT_ASSERT_EQUAL(sal_uLong(864900), rGraphicObj.GetGraphic().GetSizeBytes());

    xComponent->dispose();
}
diff --git a/sc/qa/unit/subsequent_export-test.cxx b/sc/qa/unit/subsequent_export-test.cxx
index 1339274..2a7a76e 100644
--- a/sc/qa/unit/subsequent_export-test.cxx
+++ b/sc/qa/unit/subsequent_export-test.cxx
@@ -3253,7 +3253,7 @@ void ScExportTest::testLinkedGraphicRT()

        const GraphicObject& rGraphicObj = pObject->GetGraphicObject(true);
        CPPUNIT_ASSERT_EQUAL_MESSAGE( sFailedMessage.getStr(), int(GraphicType::Bitmap), int(rGraphicObj.GetGraphic().GetType()));
        CPPUNIT_ASSERT_EQUAL_MESSAGE( sFailedMessage.getStr(), sal_uLong(864900), rGraphicObj.GetSizeBytes());
        CPPUNIT_ASSERT_EQUAL_MESSAGE( sFailedMessage.getStr(), sal_uLong(864900), rGraphicObj.GetGraphic().GetSizeBytes());

        xDocSh2->DoClose();
    }
diff --git a/sd/qa/unit/data/xml/fdo64586_0.xml b/sd/qa/unit/data/xml/fdo64586_0.xml
index a248783..4ba0afe 100644
--- a/sd/qa/unit/data/xml/fdo64586_0.xml
+++ b/sd/qa/unit/data/xml/fdo64586_0.xml
@@ -4,7 +4,7 @@
  <FillTransparenceGradient style="LINEAR" startColor="000000" endColor="ffffff" angle="0" border="0" xOffset="50" yOffset="50" startIntensity="100" endIntensity="100" stepCount="0"/>
  <FillGradient style="LINEAR" startColor="000000" endColor="ffffff" angle="0" border="0" xOffset="50" yOffset="50" startIntensity="100" endIntensity="100" stepCount="0"/>
  <FillHatch style="SINGLE" color="3465a4" distance="20" angle="0"/>
  <FillBitmap/>
  <FillBitmap width="32" height="32"/>
  <LineDash style="RECT" dots="1" dotLen="20" dashes="1" dashLen="20" distance="20"/>
  <LineStart/>
  <LineEnd/>
@@ -18,7 +18,7 @@
  <FillTransparenceGradient style="LINEAR" startColor="000000" endColor="ffffff" angle="0" border="0" xOffset="50" yOffset="50" startIntensity="100" endIntensity="100" stepCount="0"/>
  <FillGradient style="LINEAR" startColor="000000" endColor="ffffff" angle="0" border="0" xOffset="50" yOffset="50" startIntensity="100" endIntensity="100" stepCount="0"/>
  <FillHatch style="SINGLE" color="3465a4" distance="20" angle="0"/>
  <FillBitmap/>
  <FillBitmap width="32" height="32"/>
  <LineDash style="RECT" dots="1" dotLen="20" dashes="1" dashLen="20" distance="20"/>
  <LineStart/>
  <LineEnd/>
diff --git a/sd/qa/unit/data/xml/n758621_0.xml b/sd/qa/unit/data/xml/n758621_0.xml
index 754be1d..dc3e093 100644
--- a/sd/qa/unit/data/xml/n758621_0.xml
+++ b/sd/qa/unit/data/xml/n758621_0.xml
@@ -4,7 +4,7 @@
  <FillTransparenceGradient style="LINEAR" startColor="000000" endColor="ffffff" angle="0" border="0" xOffset="50" yOffset="50" startIntensity="100" endIntensity="100" stepCount="0"/>
  <FillGradient style="LINEAR" startColor="000000" endColor="ffffff" angle="0" border="0" xOffset="50" yOffset="50" startIntensity="100" endIntensity="100" stepCount="0"/>
  <FillHatch style="SINGLE" color="3465a4" distance="20" angle="0"/>
  <FillBitmap/>
  <FillBitmap width="32" height="32"/>
  <LineDash style="RECT" dots="1" dotLen="20" dashes="1" dashLen="20" distance="20"/>
  <LineStart/>
  <LineEnd/>
@@ -18,7 +18,7 @@
  <FillTransparenceGradient style="LINEAR" startColor="000000" endColor="ffffff" angle="0" border="0" xOffset="50" yOffset="50" startIntensity="100" endIntensity="100" stepCount="0"/>
  <FillGradient style="LINEAR" startColor="000000" endColor="ffffff" angle="0" border="0" xOffset="50" yOffset="50" startIntensity="100" endIntensity="100" stepCount="0"/>
  <FillHatch style="SINGLE" color="3465a4" distance="20" angle="0"/>
  <FillBitmap/>
  <FillBitmap width="32" height="32"/>
  <LineDash style="RECT" dots="1" dotLen="20" dashes="1" dashLen="20" distance="20"/>
  <LineStart/>
  <LineEnd/>
diff --git a/sd/qa/unit/data/xml/n758621_1.xml b/sd/qa/unit/data/xml/n758621_1.xml
index 0f71931..0b82624 100644
--- a/sd/qa/unit/data/xml/n758621_1.xml
+++ b/sd/qa/unit/data/xml/n758621_1.xml
@@ -4,7 +4,7 @@
  <FillTransparenceGradient style="LINEAR" startColor="000000" endColor="ffffff" angle="0" border="0" xOffset="50" yOffset="50" startIntensity="100" endIntensity="100" stepCount="0"/>
  <FillGradient style="LINEAR" startColor="000000" endColor="ffffff" angle="0" border="0" xOffset="50" yOffset="50" startIntensity="100" endIntensity="100" stepCount="0"/>
  <FillHatch style="SINGLE" color="3465a4" distance="20" angle="0"/>
  <FillBitmap/>
  <FillBitmap width="32" height="32"/>
  <LineDash style="RECT" dots="1" dotLen="20" dashes="1" dashLen="20" distance="20"/>
  <LineStart/>
  <LineEnd/>
@@ -18,7 +18,7 @@
  <FillTransparenceGradient style="LINEAR" startColor="000000" endColor="ffffff" angle="0" border="0" xOffset="50" yOffset="50" startIntensity="100" endIntensity="100" stepCount="0"/>
  <FillGradient style="LINEAR" startColor="000000" endColor="ffffff" angle="0" border="0" xOffset="50" yOffset="50" startIntensity="100" endIntensity="100" stepCount="0"/>
  <FillHatch style="SINGLE" color="3465a4" distance="20" angle="0"/>
  <FillBitmap/>
  <FillBitmap width="32" height="32"/>
  <LineDash style="RECT" dots="1" dotLen="20" dashes="1" dashLen="20" distance="20"/>
  <LineStart/>
  <LineEnd/>
diff --git a/sd/qa/unit/data/xml/n819614_0.xml b/sd/qa/unit/data/xml/n819614_0.xml
index 368a2fa..e51b520 100644
--- a/sd/qa/unit/data/xml/n819614_0.xml
+++ b/sd/qa/unit/data/xml/n819614_0.xml
@@ -4,7 +4,7 @@
  <FillTransparenceGradient style="LINEAR" startColor="000000" endColor="ffffff" angle="0" border="0" xOffset="50" yOffset="50" startIntensity="100" endIntensity="100" stepCount="0"/>
  <FillGradient style="LINEAR" startColor="000000" endColor="ffffff" angle="0" border="0" xOffset="50" yOffset="50" startIntensity="100" endIntensity="100" stepCount="0"/>
  <FillHatch style="SINGLE" color="3465a4" distance="20" angle="0"/>
  <FillBitmap/>
  <FillBitmap width="32" height="32"/>
  <LineDash style="RECT" dots="1" dotLen="20" dashes="1" dashLen="20" distance="20"/>
  <LineStart/>
  <LineEnd/>
diff --git a/sd/qa/unit/export-tests.cxx b/sd/qa/unit/export-tests.cxx
index fca7018..f5c7c4e 100644
--- a/sd/qa/unit/export-tests.cxx
+++ b/sd/qa/unit/export-tests.cxx
@@ -590,7 +590,7 @@ void SdExportTest::testLinkedGraphicRT()

            const GraphicObject& rGraphicObj = pObject->GetGraphicObject(true);
            CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedImportMessage.getStr(), int(GraphicType::Bitmap), int(rGraphicObj.GetGraphic().GetType()));
            CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedImportMessage.getStr(), sal_uLong(864900), rGraphicObj.GetSizeBytes());
            CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedImportMessage.getStr(), sal_uLong(864900), rGraphicObj.GetGraphic().GetSizeBytes());
        }

        // Save and reload
@@ -615,7 +615,7 @@ void SdExportTest::testLinkedGraphicRT()

            const GraphicObject& rGraphicObj = pObject->GetGraphicObject(true);
            CPPUNIT_ASSERT_EQUAL_MESSAGE( sFailedMessage.getStr(), int(GraphicType::Bitmap), int(rGraphicObj.GetGraphic().GetType()));
            CPPUNIT_ASSERT_EQUAL_MESSAGE( sFailedMessage.getStr(), sal_uLong(864900), rGraphicObj.GetSizeBytes());
            CPPUNIT_ASSERT_EQUAL_MESSAGE( sFailedMessage.getStr(), sal_uLong(864900), rGraphicObj.GetGraphic().GetSizeBytes());
        }

        xDocShRef->DoClose();
diff --git a/svx/source/svdraw/svdograf.cxx b/svx/source/svdraw/svdograf.cxx
index 018aef7..4894964 100644
--- a/svx/source/svdraw/svdograf.cxx
+++ b/svx/source/svdraw/svdograf.cxx
@@ -282,7 +282,7 @@ sdr::contact::ViewContact* SdrGrafObj::CreateObjectSpecificViewContact()

void SdrGrafObj::onGraphicChanged()
{
    if (!mpGraphicObject) // don't force swap-in for this
    if (!mpGraphicObject || !mpGraphicObject->GetGraphic().isAvailable())
        return;

    const VectorGraphicDataPtr& rVectorGraphicDataPtr = mpGraphicObject->GetGraphic().getVectorGraphicData();
@@ -551,12 +551,12 @@ bool SdrGrafObj::IsSwappedOut() const
    return false;
}

const MapMode& SdrGrafObj::GetGrafPrefMapMode() const
MapMode SdrGrafObj::GetGrafPrefMapMode() const
{
    return mpGraphicObject->GetPrefMapMode();
}

const Size& SdrGrafObj::GetGrafPrefSize() const
Size SdrGrafObj::GetGrafPrefSize() const
{
    return mpGraphicObject->GetPrefSize();
}
diff --git a/svx/source/xml/xmlgrhlp.cxx b/svx/source/xml/xmlgrhlp.cxx
index e420cc1..971402a 100644
--- a/svx/source/xml/xmlgrhlp.cxx
+++ b/svx/source/xml/xmlgrhlp.cxx
@@ -493,15 +493,20 @@ OUString SvXMLGraphicHelper::ImplGetGraphicMimeType( const OUString& rFileName )
Graphic SvXMLGraphicHelper::ImplReadGraphic( const OUString& rPictureStorageName,
                                             const OUString& rPictureStreamName )
{
    Graphic             aGraphic;
    Graphic aReturnGraphic;
    SvxGraphicHelperStream_Impl aStream( ImplGetGraphicStream( rPictureStorageName, rPictureStreamName ) );
    if( aStream.xStream.is() )
    if (aStream.xStream.is())
    {
        std::unique_ptr<SvStream> pStream(utl::UcbStreamHelper::CreateStream( aStream.xStream ));
        GraphicFilter::GetGraphicFilter().ImportGraphic( aGraphic, "", *pStream );
        GraphicFilter& rGraphicFilter = GraphicFilter::GetGraphicFilter();
        std::unique_ptr<SvStream> pStream(utl::UcbStreamHelper::CreateStream(aStream.xStream));
        Graphic aGraphic = rGraphicFilter.ImportUnloadedGraphic(*pStream);
        if (aGraphic)
            aReturnGraphic = aGraphic;
        else
            rGraphicFilter.ImportGraphic(aReturnGraphic, "", *pStream);
    }

    return aGraphic;
    return aReturnGraphic;
}

void SvXMLGraphicHelper::Init( const uno::Reference < embed::XStorage >& rXMLStorage,
diff --git a/sw/qa/extras/globalfilter/globalfilter.cxx b/sw/qa/extras/globalfilter/globalfilter.cxx
index 66b0d72..2145eb9 100644
--- a/sw/qa/extras/globalfilter/globalfilter.cxx
+++ b/sw/qa/extras/globalfilter/globalfilter.cxx
@@ -184,8 +184,9 @@ void Test::testLinkedGraphicRT()
                CPPUNIT_ASSERT(pGrfNode);

                const GraphicObject& rGraphicObj = pGrfNode->GetGrfObj(true);
                CPPUNIT_ASSERT_EQUAL_MESSAGE( sFailedMessage.getStr(), int(GraphicType::Bitmap), int(rGraphicObj.GetType()));
                CPPUNIT_ASSERT_EQUAL_MESSAGE( sFailedMessage.getStr(), static_cast<sal_uLong>(864900), rGraphicObj.GetSizeBytes());
                const Graphic& rGraphic = rGraphicObj.GetGraphic();
                CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), int(GraphicType::Bitmap), int(rGraphic.GetType()));
                CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), sal_uLong(864900), rGraphic.GetSizeBytes());
                bImageFound = true;
            }
        }
diff --git a/vcl/inc/graphic/Manager.hxx b/vcl/inc/graphic/Manager.hxx
index 4b45852..6dd88a5 100644
--- a/vcl/inc/graphic/Manager.hxx
+++ b/vcl/inc/graphic/Manager.hxx
@@ -46,6 +46,8 @@ private:

    DECL_LINK(SwapOutTimerHandler, Timer*, void);

    static sal_Int64 getGraphicSizeBytes(const ImpGraphic* pImpGraphic);

public:
    static Manager& get();

diff --git a/vcl/inc/impgraph.hxx b/vcl/inc/impgraph.hxx
index 814f9fe..660fdfc 100644
--- a/vcl/inc/impgraph.hxx
+++ b/vcl/inc/impgraph.hxx
@@ -27,6 +27,13 @@ struct ImpSwapInfo
{
    MapMode     maPrefMapMode;
    Size        maPrefSize;

    bool mbIsAnimated;
    bool mbIsEPS;
    bool mbIsTransparent;
    bool mbIsAlpha;

    sal_uInt32 mnAnimationLoopCount;
};

class OutputDevice;
@@ -85,6 +92,7 @@ private:
    GraphicExternalLink          maGraphicExternalLink;

    std::chrono::high_resolution_clock::time_point maLastUsed;
    bool mbPrepared;

public:
    ImpGraphic();
@@ -98,6 +106,8 @@ public:
    ImpGraphic( const GDIMetaFile& rMtf );
    ~ImpGraphic();

    void ImplSetPrepared();

private:

    ImpGraphic&         operator=( const ImpGraphic& rImpGraphic );
@@ -135,6 +145,9 @@ private:
    bool                ImplIsAnimated() const;
    bool                ImplIsEPS() const;

    bool isAvailable() const;
    bool makeAvailable();

    Bitmap              ImplGetBitmap(const GraphicConversionParameters& rParameters) const;
    BitmapEx            ImplGetBitmapEx(const GraphicConversionParameters& rParameters) const;
    /// Gives direct access to the contained BitmapEx.
@@ -203,6 +216,8 @@ private:
    void setPdfData(const css::uno::Sequence<sal_Int8>& rPdfData);

    bool ensureAvailable () const;

    bool loadPrepared();
};

#endif // INCLUDED_VCL_INC_IMPGRAPH_HXX
diff --git a/vcl/source/filter/graphicfilter.cxx b/vcl/source/filter/graphicfilter.cxx
index 79c6e48..023c07e 100644
--- a/vcl/source/filter/graphicfilter.cxx
+++ b/vcl/source/filter/graphicfilter.cxx
@@ -37,6 +37,7 @@
#include <vcl/pngwrite.hxx>
#include <vcl/vectorgraphicdata.hxx>
#include <vcl/virdev.hxx>
#include <impgraph.hxx>
#include <vcl/svapp.hxx>
#include <osl/file.hxx>
#include <vcl/graphicfilter.hxx>
@@ -1441,6 +1442,231 @@ void GraphicFilter::ImportGraphics(std::vector< std::shared_ptr<Graphic> >& rGra
    }
}

Graphic GraphicFilter::ImportUnloadedGraphic(SvStream& rIStream)
{
    Graphic aGraphic;
    sal_uInt16 nFormat = GRFILTER_FORMAT_DONTKNOW;
    GfxLinkType eLinkType = GfxLinkType::NONE;

    ResetLastError();

    const sal_uLong nStreamBegin = rIStream.Tell();

    rIStream.Seek(nStreamBegin);

    ErrCode nStatus = ImpTestOrFindFormat("", rIStream, nFormat);

    rIStream.Seek(nStreamBegin);
    const sal_uInt32 nStreamLength(rIStream.Seek(STREAM_SEEK_TO_END) - nStreamBegin);

    OUString aFilterName = pConfig->GetImportFilterName(nFormat);
    OUString aExternalFilterName = pConfig->GetExternalFilterName(nFormat, false);

    std::unique_ptr<sal_uInt8[]> pGraphicContent;
    sal_Int32 nGraphicContentSize = 0;

    // read graphic
    if (pConfig->IsImportInternalFilter(nFormat))
    {
        if (aFilterName.equalsIgnoreAsciiCase(IMP_GIF))
        {
            eLinkType = GfxLinkType::NativeGif;
        }
        else if (aFilterName.equalsIgnoreAsciiCase(IMP_PNG))
        {
            vcl::PNGReader aPNGReader(rIStream);

            // check if this PNG contains a GIF chunk!
            const std::vector<vcl::PNGReader::ChunkData>& rChunkData = aPNGReader.GetChunks();
            for (auto const& chunk : rChunkData)
            {
                // Microsoft Office is storing Animated GIFs in following chunk
                if (chunk.nType == PMGCHUNG_msOG)
                {
                    sal_uInt32 nChunkSize = chunk.aData.size();

                    if (nChunkSize > 11)
                    {
                        const std::vector<sal_uInt8>& rData = chunk.aData;
                        nGraphicContentSize = nChunkSize - 11;
                        SvMemoryStream aIStrm(const_cast<sal_uInt8*>(&rData[11]), nGraphicContentSize, StreamMode::READ);
                        pGraphicContent.reset(new sal_uInt8[nGraphicContentSize]);
                        sal_uInt64 aCurrentPosition = aIStrm.Tell();
                        aIStrm.ReadBytes(pGraphicContent.get(), nGraphicContentSize);
                        aIStrm.Seek(aCurrentPosition);
                        eLinkType = GfxLinkType::NativeGif;
                        break;
                    }
                }
            }
            if (eLinkType == GfxLinkType::NONE)
            {
                eLinkType = GfxLinkType::NativePng;
            }
        }
        else if (aFilterName.equalsIgnoreAsciiCase(IMP_JPEG))
        {
            eLinkType = GfxLinkType::NativeJpg;
        }
        else if (aFilterName.equalsIgnoreAsciiCase(IMP_SVG))
        {
            bool bOkay(false);

            if (nStreamLength > 0)
            {
                std::vector<sal_uInt8> aTwoBytes(2);
                rIStream.ReadBytes(aTwoBytes.data(), 2);
                rIStream.Seek(nStreamBegin);

                if (aTwoBytes[0] == 0x1F && aTwoBytes[1] == 0x8B)
                {
                    SvMemoryStream aMemStream;
                    ZCodec aCodec;
                    long nMemoryLength;

                    aCodec.BeginCompression(ZCODEC_DEFAULT_COMPRESSION, false, true);
                    nMemoryLength = aCodec.Decompress(rIStream, aMemStream);
                    aCodec.EndCompression();

                    if (!rIStream.GetError() && nMemoryLength >= 0)
                    {
                        nGraphicContentSize = nMemoryLength;
                        pGraphicContent.reset(new sal_uInt8[nGraphicContentSize]);

                        aMemStream.Seek(STREAM_SEEK_TO_BEGIN);
                        aMemStream.ReadBytes(pGraphicContent.get(), nGraphicContentSize);

                        bOkay = true;
                    }
                }
                else
                {
                    nGraphicContentSize = nStreamLength;
                    pGraphicContent.reset(new sal_uInt8[nGraphicContentSize]);
                    rIStream.ReadBytes(pGraphicContent.get(), nStreamLength);

                    bOkay = true;
                }
            }

            if (bOkay)
            {
                eLinkType = GfxLinkType::NativeSvg;
            }
            else
            {
                nStatus = ERRCODE_GRFILTER_FILTERERROR;
            }
        }
        else if (aFilterName.equalsIgnoreAsciiCase(IMP_BMP))
        {
            eLinkType = GfxLinkType::NativeBmp;
        }
        else if (aFilterName.equalsIgnoreAsciiCase(IMP_MOV))
        {
            eLinkType = GfxLinkType::NativeMov;
        }
        else if (aFilterName.equalsIgnoreAsciiCase(IMP_WMF) ||
                 aFilterName.equalsIgnoreAsciiCase(IMP_EMF))
        {
            nGraphicContentSize = nStreamLength;
            pGraphicContent.reset(new sal_uInt8[nGraphicContentSize]);

            rIStream.ReadBytes(pGraphicContent.get(), nStreamLength);

            if (!rIStream.GetError())
            {
                eLinkType = GfxLinkType::NativeWmf;
            }
            else
            {
                nStatus = ERRCODE_GRFILTER_FILTERERROR;
            }
        }
        else if (aFilterName == IMP_PDF)
        {
            eLinkType = GfxLinkType::NativePdf;
        }
        else
        {
            nStatus = ERRCODE_GRFILTER_FILTERERROR;
        }
    }
    else
    {
        ImpFilterLibCacheEntry* pFilter = nullptr;

        // find first filter in filter paths
        sal_Int32 i, nTokenCount = getTokenCount(aFilterPath, ';');
        ImpFilterLibCache &rCache = Cache::get();
        for( i = 0; ( i < nTokenCount ) && ( pFilter == nullptr ); i++ )
            pFilter = rCache.GetFilter(aFilterPath.getToken(i, ';'), aFilterName, aExternalFilterName);
        if( !pFilter )
            nStatus = ERRCODE_GRFILTER_FILTERERROR;
        else
        {
            PFilterCall pFunc = pFilter->GetImportFunction();

            if (!pFunc)
                nStatus = ERRCODE_GRFILTER_FILTERERROR;
            else
            {
                OUString aShortName;
                if (nFormat != GRFILTER_FORMAT_DONTKNOW)
                    aShortName = GetImportFormatShortName(nFormat).toAsciiUpperCase();

                if (aShortName.startsWith(TIF_SHORTNAME))
                    eLinkType = GfxLinkType::NativeTif;
                else if( aShortName.startsWith(MET_SHORTNAME))
                    eLinkType = GfxLinkType::NativeMet;
                else if( aShortName.startsWith(PCT_SHORTNAME))
                    eLinkType = GfxLinkType::NativePct;
            }
        }
    }

    if (nStatus == ERRCODE_NONE && eLinkType != GfxLinkType::NONE)
    {
        if (!pGraphicContent)
        {
            nGraphicContentSize = nStreamLength;

            if (nGraphicContentSize > 0)
            {
                try
                {
                    pGraphicContent.reset(new sal_uInt8[nGraphicContentSize]);
                }
                catch (const std::bad_alloc&)
                {
                    nStatus = ERRCODE_GRFILTER_TOOBIG;
                }

                if (nStatus == ERRCODE_NONE)
                {
                    rIStream.Seek(nStreamBegin);
                    rIStream.ReadBytes(pGraphicContent.get(), nGraphicContentSize);
                }
            }
        }

        if( nStatus == ERRCODE_NONE )
        {
            aGraphic.SetGfxLink(GfxLink(std::move(pGraphicContent), nGraphicContentSize, eLinkType));
            aGraphic.ImplGetImpGraphic()->ImplSetPrepared();
        }
    }

    // Set error code or try to set native buffer
    if(nStatus != ERRCODE_NONE)
    {
        ImplSetError(nStatus, &rIStream);
        rIStream.Seek(nStreamBegin);
    }

    return aGraphic;
}

ErrCode GraphicFilter::ImportGraphic( Graphic& rGraphic, const OUString& rPath, SvStream& rIStream,
                                     sal_uInt16 nFormat, sal_uInt16* pDeterminedFormat, GraphicFilterImportFlags nImportFlags,
                                     css::uno::Sequence< css::beans::PropertyValue >* pFilterData,
@@ -2272,6 +2498,7 @@ IMPL_LINK( GraphicFilter, FilterCallback, ConvertData&, rData, bool )
        case ConvertDataFormat::WMF: aShortName = WMF_SHORTNAME; break;
        case ConvertDataFormat::EMF: aShortName = EMF_SHORTNAME; break;
        case ConvertDataFormat::SVG: aShortName = SVG_SHORTNAME; break;
        case ConvertDataFormat::PDF: aShortName = PDF_SHORTNAME; break;

        default:
        break;
diff --git a/vcl/source/gdi/gfxlink.cxx b/vcl/source/gdi/gfxlink.cxx
index c1b0cd4..885385c 100644
--- a/vcl/source/gdi/gfxlink.cxx
+++ b/vcl/source/gdi/gfxlink.cxx
@@ -24,21 +24,28 @@
#include <vcl/graph.hxx>
#include <vcl/gfxlink.hxx>
#include <vcl/cvtgrf.hxx>
#include <vcl/graphicfilter.hxx>
#include <memory>
#include <o3tl/make_shared.hxx>

GfxLink::GfxLink()
    : meType(GfxLinkType::NONE)
    , mnUserId(0)
    , mnSwapInDataSize(0)
    , mbPrefMapModeValid(false)
    , mbPrefSizeValid(false)
{
}

GfxLink::GfxLink( std::unique_ptr<sal_uInt8[]> pBuf, sal_uInt32 nSize, GfxLinkType nType )
GfxLink::GfxLink(std::unique_ptr<sal_uInt8[]> pBuf, sal_uInt32 nSize, GfxLinkType nType)
    : meType(nType)
    , mnUserId(0)
    , mpSwapInData(std::shared_ptr<sal_uInt8>(pBuf.release(), pBuf.get_deleter())) // std::move(pBuf) does not compile on Jenkins MacOSX (24 May 2016)
    , mnSwapInDataSize(nSize)
    , mbPrefMapModeValid(false)
    , mbPrefSizeValid(false)
{
    SAL_WARN_IF( pBuf == nullptr || !nSize, "vcl",
                "GfxLink::GfxLink(): empty/NULL buffer given" );

    meType = nType;
    mnSwapInDataSize = nSize;
    mpSwapInData = std::shared_ptr<sal_uInt8>(pBuf.release(), pBuf.get_deleter());  // std::move(pBuf) does not compile on Jenkins MacOSX (24 May 2016)
    SAL_WARN_IF(mpSwapInData.get() == nullptr || mnSwapInDataSize <= 0, "vcl", "GfxLink::GfxLink(): empty/NULL buffer given");
}

bool GfxLink::operator==( const GfxLink& rGfxLink ) const
@@ -98,31 +105,33 @@ bool GfxLink::LoadNative( Graphic& rGraphic )
    if( IsNative() && mnSwapInDataSize )
    {
        const sal_uInt8* pData = GetData();

        if( pData )
        if (pData)
        {
            SvMemoryStream    aMemStm;
            ConvertDataFormat nCvtType;
            SvMemoryStream aMemoryStream(const_cast<sal_uInt8*>(pData), mnSwapInDataSize, StreamMode::READ | StreamMode::WRITE);
            OUString aShortName;

            aMemStm.SetBuffer( const_cast<sal_uInt8*>(pData), mnSwapInDataSize, mnSwapInDataSize );

            switch( meType )
            switch (meType)
            {
                case GfxLinkType::NativeGif: nCvtType = ConvertDataFormat::GIF; break;
                case GfxLinkType::NativeBmp: nCvtType = ConvertDataFormat::BMP; break;
                case GfxLinkType::NativeJpg: nCvtType = ConvertDataFormat::JPG; break;
                case GfxLinkType::NativePng: nCvtType = ConvertDataFormat::PNG; break;
                case GfxLinkType::NativeTif: nCvtType = ConvertDataFormat::TIF; break;
                case GfxLinkType::NativeWmf: nCvtType = ConvertDataFormat::WMF; break;
                case GfxLinkType::NativeMet: nCvtType = ConvertDataFormat::MET; break;
                case GfxLinkType::NativePct: nCvtType = ConvertDataFormat::PCT; break;
                case GfxLinkType::NativeSvg: nCvtType = ConvertDataFormat::SVG; break;

                default: nCvtType = ConvertDataFormat::Unknown; break;
                case GfxLinkType::NativeGif: aShortName = GIF_SHORTNAME; break;
                case GfxLinkType::NativeJpg: aShortName = JPG_SHORTNAME; break;
                case GfxLinkType::NativePng: aShortName = PNG_SHORTNAME; break;
                case GfxLinkType::NativeTif: aShortName = TIF_SHORTNAME; break;
                case GfxLinkType::NativeWmf: aShortName = WMF_SHORTNAME; break;
                case GfxLinkType::NativeMet: aShortName = MET_SHORTNAME; break;
                case GfxLinkType::NativePct: aShortName = PCT_SHORTNAME; break;
                case GfxLinkType::NativeSvg: aShortName = SVG_SHORTNAME; break;
                case GfxLinkType::NativeBmp: aShortName = BMP_SHORTNAME; break;
                case GfxLinkType::NativePdf: aShortName = PDF_SHORTNAME; break;
                default: break;
            }

            if( nCvtType != ConvertDataFormat::Unknown && ( GraphicConverter::Import( aMemStm, rGraphic, nCvtType ) == ERRCODE_NONE ) )
                bRet = true;
            if (!aShortName.isEmpty())
            {
                GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter();
                sal_uInt16 nFormat = rFilter.GetImportFormatNumberForShortName(aShortName);
                ErrCode nResult = rFilter.ImportGraphic(rGraphic, OUString(), aMemoryStream, nFormat);
                if (nResult == ERRCODE_NONE)
                    bRet = true;
            }
        }
    }

diff --git a/vcl/source/gdi/graph.cxx b/vcl/source/gdi/graph.cxx
index 91dcad7..9ba35dd 100644
--- a/vcl/source/gdi/graph.cxx
+++ b/vcl/source/gdi/graph.cxx
@@ -257,6 +257,16 @@ void Graphic::ImplTestRefCount()
    }
}

bool Graphic::isAvailable() const
{
    return mxImpGraphic->isAvailable();
}

bool Graphic::makeAvailable()
{
    return mxImpGraphic->makeAvailable();
}

Graphic& Graphic::operator=( const Graphic& rGraphic )
{
    if( &rGraphic != this )
diff --git a/vcl/source/gdi/impgraph.cxx b/vcl/source/gdi/impgraph.cxx
index c4ef749..9cd9bbb 100644
--- a/vcl/source/gdi/impgraph.cxx
+++ b/vcl/source/gdi/impgraph.cxx
@@ -30,6 +30,7 @@
#include <unotools/ucbstreamhelper.hxx>
#include <unotools/tempfile.hxx>
#include <vcl/outdev.hxx>
#include <vcl/graphicfilter.hxx>
#include <vcl/virdev.hxx>
#include <vcl/gfxlink.hxx>
#include <vcl/cvtgrf.hxx>
@@ -103,6 +104,8 @@ Size GraphicReader::GetPreviewSize() const

GraphicID::GraphicID(ImpGraphic const & rGraphic)
{
    rGraphic.ensureAvailable();

    mnID1 = static_cast<sal_uLong>(rGraphic.ImplGetType()) << 28;
    mnID2 = mnID3 = mnID4 = 0;

@@ -176,7 +179,8 @@ ImpGraphic::ImpGraphic() :
        mnSizeBytes     ( 0 ),
        mbSwapOut       ( false ),
        mbDummyContext  ( false ),
        maLastUsed (std::chrono::high_resolution_clock::now())
        maLastUsed (std::chrono::high_resolution_clock::now()),
        mbPrepared      ( false )
{
}

@@ -194,6 +198,7 @@ ImpGraphic::ImpGraphic(const ImpGraphic& rImpGraphic)
    , maPdfData(rImpGraphic.maPdfData)
    , maGraphicExternalLink(rImpGraphic.maGraphicExternalLink)
    , maLastUsed (std::chrono::high_resolution_clock::now())
    , mbPrepared (rImpGraphic.mbPrepared)
{
    if( rImpGraphic.mpGfxLink )
        mpGfxLink = o3tl::make_unique<GfxLink>( *rImpGraphic.mpGfxLink );
@@ -221,6 +226,7 @@ ImpGraphic::ImpGraphic(ImpGraphic&& rImpGraphic)
    , maPdfData(std::move(rImpGraphic.maPdfData))
    , maGraphicExternalLink(rImpGraphic.maGraphicExternalLink)
    , maLastUsed (std::chrono::high_resolution_clock::now())
    , mbPrepared (rImpGraphic.mbPrepared)
{
    rImpGraphic.ImplClear();
    rImpGraphic.mbDummyContext = false;
@@ -232,7 +238,8 @@ ImpGraphic::ImpGraphic(GraphicExternalLink const & rGraphicExternalLink) :
        mbSwapOut       ( false ),
        mbDummyContext  ( false ),
        maGraphicExternalLink(rGraphicExternalLink),
        maLastUsed (std::chrono::high_resolution_clock::now())
        maLastUsed (std::chrono::high_resolution_clock::now()),
        mbPrepared (false)
{
}

@@ -242,7 +249,8 @@ ImpGraphic::ImpGraphic( const Bitmap& rBitmap ) :
        mnSizeBytes     ( 0 ),
        mbSwapOut       ( false ),
        mbDummyContext  ( false ),
        maLastUsed (std::chrono::high_resolution_clock::now())
        maLastUsed (std::chrono::high_resolution_clock::now()),
        mbPrepared (false)
{
}

@@ -252,7 +260,8 @@ ImpGraphic::ImpGraphic( const BitmapEx& rBitmapEx ) :
        mnSizeBytes     ( 0 ),
        mbSwapOut       ( false ),
        mbDummyContext  ( false ),
        maLastUsed (std::chrono::high_resolution_clock::now())
        maLastUsed (std::chrono::high_resolution_clock::now()),
        mbPrepared (false)
{
}

@@ -262,7 +271,8 @@ ImpGraphic::ImpGraphic(const VectorGraphicDataPtr& rVectorGraphicDataPtr)
    mbSwapOut( false ),
    mbDummyContext  ( false ),
    maVectorGraphicData(rVectorGraphicDataPtr),
    maLastUsed (std::chrono::high_resolution_clock::now())
    maLastUsed (std::chrono::high_resolution_clock::now()),
    mbPrepared (false)
{
}

@@ -273,7 +283,8 @@ ImpGraphic::ImpGraphic( const Animation& rAnimation ) :
        mnSizeBytes     ( 0 ),
        mbSwapOut       ( false ),
        mbDummyContext  ( false ),
        maLastUsed (std::chrono::high_resolution_clock::now())
        maLastUsed (std::chrono::high_resolution_clock::now()),
        mbPrepared (false)
{
}

@@ -283,7 +294,8 @@ ImpGraphic::ImpGraphic( const GDIMetaFile& rMtf ) :
        mnSizeBytes     ( 0 ),
        mbSwapOut       ( false ),
        mbDummyContext  ( false ),
        maLastUsed (std::chrono::high_resolution_clock::now())
        maLastUsed (std::chrono::high_resolution_clock::now()),
        mbPrepared (false)
{
}

@@ -321,6 +333,7 @@ ImpGraphic& ImpGraphic::operator=( const ImpGraphic& rImpGraphic )

        mbSwapOut = rImpGraphic.mbSwapOut;
        mpSwapFile = rImpGraphic.mpSwapFile;
        mbPrepared = rImpGraphic.mbPrepared;

        mpGfxLink.reset();

@@ -355,6 +368,7 @@ ImpGraphic& ImpGraphic::operator=(ImpGraphic&& rImpGraphic)
    maVectorGraphicData = std::move(rImpGraphic.maVectorGraphicData);
    maPdfData = std::move(rImpGraphic.maPdfData);
    maGraphicExternalLink = rImpGraphic.maGraphicExternalLink;
    mbPrepared = rImpGraphic.mbPrepared;

    rImpGraphic.ImplClear();
    rImpGraphic.mbDummyContext = false;
@@ -371,7 +385,11 @@ bool ImpGraphic::operator==( const ImpGraphic& rImpGraphic ) const

    if( this == &rImpGraphic )
        bRet = true;
    else if( !ImplIsSwapOut() && ( rImpGraphic.meType == meType ) )
    else if (mbPrepared && rImpGraphic.mbPrepared)
    {
        bRet = (*mpGfxLink == *rImpGraphic.mpGfxLink);
    }
    else if (isAvailable() && rImpGraphic.isAvailable())
    {
        switch( meType )
        {
@@ -427,16 +445,22 @@ bool ImpGraphic::operator==( const ImpGraphic& rImpGraphic ) const

const VectorGraphicDataPtr& ImpGraphic::getVectorGraphicData() const
{
    ensureAvailable();

    return maVectorGraphicData;
}

void ImpGraphic::setPdfData(const uno::Sequence<sal_Int8>& rPdfData)
{
    ensureAvailable();

    maPdfData = rPdfData;
}

const uno::Sequence<sal_Int8>& ImpGraphic::getPdfData() const
{
    ensureAvailable();

    return maPdfData;
}

@@ -446,6 +470,11 @@ void ImpGraphic::ImplCreateSwapInfo()
    {
        maSwapInfo.maPrefMapMode = ImplGetPrefMapMode();
        maSwapInfo.maPrefSize = ImplGetPrefSize();
        maSwapInfo.mbIsAnimated = ImplIsAnimated();
        maSwapInfo.mbIsEPS = ImplIsEPS();
        maSwapInfo.mbIsTransparent = ImplIsTransparent();
        maSwapInfo.mbIsAlpha = ImplIsAlpha();
        maSwapInfo.mnAnimationLoopCount = ImplGetAnimationLoopCount();
    }
}

@@ -483,10 +512,37 @@ ImpSwapFile::~ImpSwapFile()
    }
}

void ImpGraphic::ImplSetPrepared()
{
    mbPrepared = true;
    mbSwapOut = true;
    meType = GraphicType::Bitmap;

    SvMemoryStream aMemoryStream(const_cast<sal_uInt8*>(mpGfxLink->GetData()), mpGfxLink->GetDataSize(), StreamMode::READ | StreamMode::WRITE);

    GraphicDescriptor aDescriptor(aMemoryStream, nullptr);
    if (aDescriptor.Detect(true))
    {
        maSwapInfo.maPrefSize = aDescriptor.GetSizePixel();
        maSwapInfo.maPrefMapMode = MapMode(MapUnit::MapPixel);
    }
    maSwapInfo.mnAnimationLoopCount = 0;
    maSwapInfo.mbIsAnimated = false;
    maSwapInfo.mbIsEPS = false;
    maSwapInfo.mbIsTransparent = false;
    maSwapInfo.mbIsAlpha = false;

    if (mpGfxLink->GetType() == GfxLinkType::NativeGif)
    {
        maSwapInfo.mbIsAnimated = true;
    }
}

void ImpGraphic::ImplClear()
{
    mpSwapFile.reset();
    mbSwapOut = false;
    mbPrepared = false;

    // cleanup
    ImplClearGraphics();
@@ -512,11 +568,13 @@ bool ImpGraphic::ImplIsTransparent() const
{
    bool bRet(true);

    ensureAvailable();

    if( meType == GraphicType::Bitmap && !maVectorGraphicData.get())
    if (mbSwapOut)
    {
        bRet = ( mpAnimation ? mpAnimation->IsTransparent() : maEx.IsTransparent() );
        bRet = maSwapInfo.mbIsTransparent;
    }
    else if (meType == GraphicType::Bitmap && !maVectorGraphicData.get())
    {
        bRet = mpAnimation ? mpAnimation->IsTransparent() : maEx.IsTransparent();
    }

    return bRet;
@@ -526,15 +584,17 @@ bool ImpGraphic::ImplIsAlpha() const
{
    bool bRet(false);

    ensureAvailable();

    if(maVectorGraphicData.get())
    if (mbSwapOut)
    {
        bRet = maSwapInfo.mbIsAlpha;
    }
    else if (maVectorGraphicData.get())
    {
        bRet = true;
    }
    else if( meType == GraphicType::Bitmap )
    else if (meType == GraphicType::Bitmap)
    {
        bRet = ( nullptr == mpAnimation ) && maEx.IsAlpha();
        bRet = (nullptr == mpAnimation && maEx.IsAlpha());
    }

    return bRet;
@@ -542,19 +602,29 @@ bool ImpGraphic::ImplIsAlpha() const

bool ImpGraphic::ImplIsAnimated() const
{
    ensureAvailable();
    return( mpAnimation != nullptr );
    return mbSwapOut ? maSwapInfo.mbIsAnimated : mpAnimation != nullptr;
}

bool ImpGraphic::ImplIsEPS() const
{
    ensureAvailable();
    if (mbSwapOut)
        return maSwapInfo.mbIsEPS;

    return( ( meType == GraphicType::GdiMetafile ) &&
            ( maMetaFile.GetActionSize() > 0 ) &&
            ( maMetaFile.GetAction( 0 )->GetType() == MetaActionType::EPS ) );
}

bool ImpGraphic::isAvailable() const
{
    return !mbPrepared && !mbSwapOut;
}

bool ImpGraphic::makeAvailable()
{
    return ensureAvailable();
}

Bitmap ImpGraphic::ImplGetBitmap(const GraphicConversionParameters& rParameters) const
{
    Bitmap aRetBmp;
@@ -790,8 +860,10 @@ Size ImpGraphic::ImplGetPrefSize() const
{
    Size aSize;

    if( ImplIsSwapOut() )
    if (ImplIsSwapOut())
    {
        aSize = maSwapInfo.maPrefSize;
    }
    else
    {
        switch( meType )
@@ -835,6 +907,8 @@ Size ImpGraphic::ImplGetPrefSize() const

void ImpGraphic::ImplSetPrefSize( const Size& rPrefSize )
{
    ensureAvailable();

    switch( meType )
    {
        case GraphicType::NONE:
@@ -875,8 +949,10 @@ MapMode ImpGraphic::ImplGetPrefMapMode() const
{
    MapMode aMapMode;

    if( ImplIsSwapOut() )
    if (ImplIsSwapOut())
    {
        aMapMode = maSwapInfo.maPrefMapMode;
    }
    else
    {
        switch( meType )
@@ -916,6 +992,8 @@ MapMode ImpGraphic::ImplGetPrefMapMode() const

void ImpGraphic::ImplSetPrefMapMode( const MapMode& rPrefMapMode )
{
    ensureAvailable();

    switch( meType )
    {
        case GraphicType::NONE:
@@ -956,6 +1034,9 @@ sal_uLong ImpGraphic::ImplGetSizeBytes() const
{
    if( 0 == mnSizeBytes )
    {
        if (mbPrepared)
            ensureAvailable();

        if( meType == GraphicType::Bitmap )
        {
            if(maVectorGraphicData.get())
@@ -1070,12 +1151,16 @@ void ImpGraphic::ImplStartAnimation( OutputDevice* pOutDev, const Point& rDestPt

void ImpGraphic::ImplStopAnimation( OutputDevice* pOutDev, long nExtraData )
{
    ensureAvailable();

    if( ImplIsSupportedGraphic() && !ImplIsSwapOut() && mpAnimation )
        mpAnimation->Stop( pOutDev, nExtraData );
}

void ImpGraphic::ImplSetAnimationNotifyHdl( const Link<Animation*,void>& rLink )
{
    ensureAvailable();

    if( mpAnimation )
        mpAnimation->SetNotifyHdl( rLink );
}
@@ -1084,6 +1169,8 @@ Link<Animation*,void> ImpGraphic::ImplGetAnimationNotifyHdl() const
{
    Link<Animation*,void> aLink;

    ensureAvailable();

    if( mpAnimation )
        aLink = mpAnimation->GetNotifyHdl();

@@ -1092,8 +1179,10 @@ Link<Animation*,void> ImpGraphic::ImplGetAnimationNotifyHdl() const

sal_uInt32 ImpGraphic::ImplGetAnimationLoopCount() const
{
    ensureAvailable();
    return( mpAnimation ? mpAnimation->GetLoopCount() : 0 );
    if (mbSwapOut)
        return maSwapInfo.mnAnimationLoopCount;

    return mpAnimation ? mpAnimation->GetLoopCount() : 0;
}

void ImpGraphic::ImplSetContext( const std::shared_ptr<GraphicReader>& pReader )
@@ -1104,6 +1193,8 @@ void ImpGraphic::ImplSetContext( const std::shared_ptr<GraphicReader>& pReader )

bool ImpGraphic::ImplReadEmbedded( SvStream& rIStm )
{
    ensureAvailable();

    MapMode         aMapMode;
    Size            aSize;
    sal_uInt32      nId;
@@ -1405,17 +1496,37 @@ bool ImpGraphic::ImplSwapOut( SvStream* xOStm )
bool ImpGraphic::ensureAvailable() const
{
    auto pThis = const_cast<ImpGraphic*>(this);
    pThis->maLastUsed = std::chrono::high_resolution_clock::now();

    if (ImplIsSwapOut())
        return pThis->ImplSwapIn();

    pThis->maLastUsed = std::chrono::high_resolution_clock::now();
    return true;
}

bool ImpGraphic::loadPrepared()
{
    Graphic aGraphic;
    if (mpGfxLink->LoadNative(aGraphic))
    {
        *this = *aGraphic.ImplGetImpGraphic();
        return true;
    }
    return false;
}

bool ImpGraphic::ImplSwapIn()
{
    bool bRet = false;

    if( ImplIsSwapOut() )
    if (!ImplIsSwapOut())
        return bRet;

    if (mbPrepared)
    {
        bRet = loadPrepared();
    }
    else
    {
        OUString aSwapURL;

@@ -1763,6 +1874,8 @@ void WriteImpGraphic(SvStream& rOStm, const ImpGraphic& rImpGraphic)
    if (rOStm.GetError())
        return;

    rImpGraphic.ensureAvailable();

    if (rImpGraphic.ImplIsSwapOut())
    {
        rOStm.SetError( SVSTREAM_GENERALERROR );
diff --git a/vcl/source/graphic/GraphicObject.cxx b/vcl/source/graphic/GraphicObject.cxx
index b3f6a52..c855c90 100644
--- a/vcl/source/graphic/GraphicObject.cxx
+++ b/vcl/source/graphic/GraphicObject.cxx
@@ -303,27 +303,17 @@ struct GrfSimpleCacheObj

GraphicObject::GraphicObject()
{
    ImplAssignGraphicData();
}

GraphicObject::GraphicObject(const Graphic& rGraphic)
    : maGraphic(rGraphic)
{
    ImplAssignGraphicData();
}

GraphicObject::GraphicObject(const GraphicObject& rGraphicObj)
    : maGraphic(rGraphicObj.GetGraphic())
    , maAttr(rGraphicObj.maAttr)
    , maPrefSize(rGraphicObj.maPrefSize)
    , maPrefMapMode(rGraphicObj.maPrefMapMode)
    , mnSizeBytes(rGraphicObj.mnSizeBytes)
    , meType(rGraphicObj.meType)
    , maUserData(rGraphicObj.maUserData)
    , mnAnimationLoopCount(rGraphicObj.mnAnimationLoopCount)
    , mbTransparent(rGraphicObj.mbTransparent)
    , mbAnimated(rGraphicObj.mbAnimated)
    , mbEPS(rGraphicObj.mbEPS)
{
}

@@ -331,16 +321,34 @@ GraphicObject::~GraphicObject()
{
}

void GraphicObject::ImplAssignGraphicData()
GraphicType GraphicObject::GetType() const
{
    maPrefSize = maGraphic.GetPrefSize();
    maPrefMapMode = maGraphic.GetPrefMapMode();
    mnSizeBytes = maGraphic.GetSizeBytes();
    meType = maGraphic.GetType();
    mbTransparent = maGraphic.IsTransparent();
    mbAnimated = maGraphic.IsAnimated();
    mbEPS = maGraphic.IsEPS();
    mnAnimationLoopCount = ( mbAnimated ? maGraphic.GetAnimationLoopCount() : 0 );
    return maGraphic.GetType();
}

Size GraphicObject::GetPrefSize() const
{
    return maGraphic.GetPrefSize();
}

MapMode GraphicObject::GetPrefMapMode() const
{
    return maGraphic.GetPrefMapMode();
}

bool GraphicObject::IsTransparent() const
{
    return maGraphic.IsTransparent();
}

bool GraphicObject::IsAnimated() const
{
    return maGraphic.IsAnimated();
}

bool GraphicObject::IsEPS() const
{
    return maGraphic.IsEPS();
}

bool GraphicObject::ImplGetCropParams( OutputDevice const * pOut, Point& rPt, Size& rSz, const GraphicAttr* pAttr,
@@ -420,7 +428,6 @@ GraphicObject& GraphicObject::operator=( const GraphicObject& rGraphicObj )
        maGraphic = rGraphicObj.GetGraphic();
        maAttr = rGraphicObj.maAttr;
        maUserData = rGraphicObj.maUserData;
        ImplAssignGraphicData();
    }

    return *this;
@@ -551,10 +558,9 @@ bool GraphicObject::StartAnimation( OutputDevice* pOut, const Point& rPt, const 

    GetGraphic();


    const GraphicAttr aAttr( GetAttr() );

    if( mbAnimated )
    if (IsAnimated())
    {
        Point   aPt( rPt );
        Size    aSz( rSz );
@@ -610,7 +616,6 @@ const Graphic& GraphicObject::GetGraphic() const
void GraphicObject::SetGraphic( const Graphic& rGraphic, const GraphicObject* /*pCopyObj*/)
{
    maGraphic = rGraphic;
    ImplAssignGraphicData();
}

void GraphicObject::SetGraphic( const Graphic& rGraphic, const OUString& /*rLink*/ )
@@ -862,7 +867,7 @@ Graphic GraphicObject::GetTransformedGraphic( const GraphicAttr* pAttr ) const
                {
                    Animation aAnimation( maGraphic.GetAnimation() );
                    lclImplAdjust( aAnimation, aAttr, GraphicAdjustmentFlags::ALL );
                    aAnimation.SetLoopCount( mnAnimationLoopCount );
                    aAnimation.SetLoopCount(maGraphic.GetAnimationLoopCount());
                    aGraphic = aAnimation;
                }
                else
@@ -884,7 +889,7 @@ Graphic GraphicObject::GetTransformedGraphic( const GraphicAttr* pAttr ) const
            if( ( GetType() == GraphicType::Bitmap ) && IsAnimated() )
            {
                Animation aAnimation( maGraphic.GetAnimation() );
                aAnimation.SetLoopCount( mnAnimationLoopCount );
                aAnimation.SetLoopCount(maGraphic.GetAnimationLoopCount());
                aGraphic = aAnimation;
            }
            else
diff --git a/vcl/source/graphic/Manager.cxx b/vcl/source/graphic/Manager.cxx
index 549b9c6..106677c 100644
--- a/vcl/source/graphic/Manager.cxx
+++ b/vcl/source/graphic/Manager.cxx
@@ -71,7 +71,7 @@ void Manager::reduceGraphicMemory()
        if (mnUsedSize < mnTotalCacheSize * 0.7)
            return;

        sal_Int64 nCurrentGraphicSize = pEachImpGraphic->ImplGetSizeBytes();
        sal_Int64 nCurrentGraphicSize = getGraphicSizeBytes(pEachImpGraphic);
        if (!pEachImpGraphic->ImplIsSwapOut() && nCurrentGraphicSize > 1000000)
        {
            if (!pEachImpGraphic->mpContext)
@@ -87,6 +87,13 @@ void Manager::reduceGraphicMemory()
    }
}

sal_Int64 Manager::getGraphicSizeBytes(const ImpGraphic* pImpGraphic)
{
    if (!pImpGraphic->isAvailable())
        return 0;
    return pImpGraphic->ImplGetSizeBytes();
}

IMPL_LINK(Manager, SwapOutTimerHandler, Timer*, pTimer, void)
{
    pTimer->Stop();
@@ -102,7 +109,7 @@ void Manager::registerGraphic(std::shared_ptr<ImpGraphic>& pImpGraphic,
        reduceGraphicMemory();

    // Insert and update the used size (bytes)
    mnUsedSize += pImpGraphic->ImplGetSizeBytes();
    mnUsedSize += getGraphicSizeBytes(pImpGraphic.get());
    m_pImpGraphicList.insert(pImpGraphic.get());

    // calculate size of the graphic set
@@ -111,7 +118,7 @@ void Manager::registerGraphic(std::shared_ptr<ImpGraphic>& pImpGraphic,
    {
        if (!pEachImpGraphic->ImplIsSwapOut())
        {
            calculatedSize += pEachImpGraphic->ImplGetSizeBytes();
            calculatedSize += getGraphicSizeBytes(pEachImpGraphic);
        }
    }

@@ -126,7 +133,7 @@ void Manager::registerGraphic(std::shared_ptr<ImpGraphic>& pImpGraphic,

void Manager::unregisterGraphic(ImpGraphic* pImpGraphic)
{
    mnUsedSize -= pImpGraphic->ImplGetSizeBytes();
    mnUsedSize -= getGraphicSizeBytes(pImpGraphic);
    m_pImpGraphicList.erase(pImpGraphic);
}

@@ -188,18 +195,18 @@ std::shared_ptr<ImpGraphic> Manager::newInstance(const GraphicExternalLink& rGra

void Manager::swappedIn(const ImpGraphic* pImpGraphic)
{
    mnUsedSize += pImpGraphic->ImplGetSizeBytes();
    mnUsedSize += getGraphicSizeBytes(pImpGraphic);
}

void Manager::swappedOut(const ImpGraphic* pImpGraphic)
{
    mnUsedSize -= pImpGraphic->ImplGetSizeBytes();
    mnUsedSize -= getGraphicSizeBytes(pImpGraphic);
}

void Manager::changeExisting(const ImpGraphic* pImpGraphic, sal_Int64 nOldSizeBytes)
{
    mnUsedSize -= nOldSizeBytes;
    mnUsedSize += pImpGraphic->ImplGetSizeBytes();
    mnUsedSize += getGraphicSizeBytes(pImpGraphic);
}
}
} // end vcl::graphic