[Libreoffice-commits] core.git: vcl/inc vcl/qa vcl/source

Tomaž Vajngerl (via logerrit) logerrit at kemper.freedesktop.org
Tue Dec 15 08:04:11 UTC 2020


 vcl/inc/TypeSerializer.hxx        |    5 
 vcl/inc/impgraph.hxx              |   14 
 vcl/qa/cppunit/GraphicTest.cxx    |  630 +++++++++++++++++++++++++++++++--
 vcl/source/gdi/TypeSerializer.cxx |    5 
 vcl/source/gdi/impgraph.cxx       |  714 ++++++++++++++++----------------------
 5 files changed, 918 insertions(+), 450 deletions(-)

New commits:
commit def31e135e5e2c0adb1502cde8bc638588da485d
Author:     Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
AuthorDate: Sun Dec 6 21:14:07 2020 +0900
Commit:     Tomaž Vajngerl <quikee at gmail.com>
CommitDate: Tue Dec 15 09:03:40 2020 +0100

    graphic: Rework swapping algorithm to take GfxLink into account
    
    This reworks the Graphic swap algorithm to not swap to a file when
    GfxLink is available and leaves the compressed data in memory.
    With such a sheme, at swap-out we just remember the need specific
    properties of the Graphic, and delete the graphic content (Bitmap,
    Animation, VectorGraphic, Metafile). At swap-in use the GfxLink
    data to decompress and recreate the graphic content, then set
    the properties back as they were before (if needed).
    
    If a GfxLink is not available it swaps out to a file and back, but
    uses a simpler data format that is specific for swapping only. In
    the future this case can be removed, when we switch to automatic
    creation of GfxLink if that one is not present.
    
    For reworking of swapping it was also necessary to extensively add
    and extend the tests that check various swapping scenarios.
    
    Change-Id: I135a224f74aa48e6006f48dd2be74b8026614728
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/107287
    Tested-by: Jenkins
    Reviewed-by: Tomaž Vajngerl <quikee at gmail.com>

diff --git a/vcl/inc/TypeSerializer.hxx b/vcl/inc/TypeSerializer.hxx
index 060876593aa5..7be2f54198e7 100644
--- a/vcl/inc/TypeSerializer.hxx
+++ b/vcl/inc/TypeSerializer.hxx
@@ -32,6 +32,11 @@ constexpr sal_uInt32 createMagic(char char1, char char2, char char3, char char4)
            | (static_cast<sal_uInt32>(char3) << 8) | (static_cast<sal_uInt32>(char4) << 0);
 }
 
+constexpr sal_uInt32 constSvgMagic = createMagic('s', 'v', 'g', '0');
+constexpr sal_uInt32 constWmfMagic = createMagic('w', 'm', 'f', '0');
+constexpr sal_uInt32 constEmfMagic = createMagic('e', 'm', 'f', '0');
+constexpr sal_uInt32 constPdfMagic = createMagic('p', 'd', 'f', '0');
+
 class VCL_DLLPUBLIC TypeSerializer : public tools::GenericTypeSerializer
 {
 public:
diff --git a/vcl/inc/impgraph.hxx b/vcl/inc/impgraph.hxx
index de5df4a1ac57..6a312a76d58e 100644
--- a/vcl/inc/impgraph.hxx
+++ b/vcl/inc/impgraph.hxx
@@ -47,6 +47,13 @@ class ImpSwapFile;
 class GraphicConversionParameters;
 class ImpGraphic;
 
+enum class GraphicContentType : sal_Int32
+{
+    Bitmap,
+    Animation,
+    Vector
+};
+
 class VCL_DLLPUBLIC ImpGraphic final
 {
     friend class Graphic;
@@ -115,7 +122,9 @@ private:
         return mpGraphicID->getIDString();
     }
 
-    void                createSwapInfo();
+    void createSwapInfo();
+    void restoreFromSwapInfo();
+
     void                ImplClearGraphics();
     void                ImplClear();
 
@@ -170,7 +179,7 @@ private:
 private:
     // swapping methods
     bool swapInFromStream(SvStream& rStream);
-    void swapInGraphic(SvStream& rStream);
+    bool swapInGraphic(SvStream& rStream);
 
     bool swapInContent(SvStream& rStream);
     bool swapOutContent(SvStream& rStream);
@@ -205,6 +214,7 @@ private:
     sal_Int32 getPageNumber() const;
 
 public:
+    void resetChecksum() { mnChecksum = 0; }
     bool swapIn();
     bool swapOut();
     bool isSwappedOut() const { return mbSwapOut; }
diff --git a/vcl/qa/cppunit/GraphicTest.cxx b/vcl/qa/cppunit/GraphicTest.cxx
index d3671fe3c881..c58ca7d650b4 100644
--- a/vcl/qa/cppunit/GraphicTest.cxx
+++ b/vcl/qa/cppunit/GraphicTest.cxx
@@ -50,23 +50,50 @@ private:
     void testUnloadedGraphicWmf();
     void testUnloadedGraphicAlpha();
     void testUnloadedGraphicSizeUnit();
-    void testSwapping();
-    void testSwappingVectorGraphic();
-    void testSwappingPageNumber();
+
     void testWMFRoundtrip();
     void testEmfToWmfConversion();
 
+    void testSwappingGraphic_PNG_WithGfxLink();
+    void testSwappingGraphic_PNG_WithoutGfxLink();
+    void testSwappingGraphicProperties_PNG_WithGfxLink();
+    void testSwappingGraphicProperties_PNG_WithoutGfxLink();
+
+    void testSwappingVectorGraphic_SVG_WithGfxLink();
+    void testSwappingVectorGraphic_SVG_WithoutGfxLink();
+    void testSwappingGraphicProperties_SVG_WithGfxLink();
+    void testSwappingGraphicProperties_SVG_WithoutGfxLink();
+
+    void testSwappingVectorGraphic_PDF_WithGfxLink();
+    void testSwappingVectorGraphic_PDF_WithoutGfxLink();
+
+    void testSwappingAnimationGraphic_GIF_WithGfxLink();
+    void testSwappingAnimationGraphic_GIF_WithoutGfxLink();
+
     CPPUNIT_TEST_SUITE(GraphicTest);
     CPPUNIT_TEST(testUnloadedGraphic);
     CPPUNIT_TEST(testUnloadedGraphicLoading);
     CPPUNIT_TEST(testUnloadedGraphicWmf);
     CPPUNIT_TEST(testUnloadedGraphicAlpha);
     CPPUNIT_TEST(testUnloadedGraphicSizeUnit);
-    CPPUNIT_TEST(testSwapping);
-    CPPUNIT_TEST(testSwappingVectorGraphic);
-    CPPUNIT_TEST(testSwappingPageNumber);
     CPPUNIT_TEST(testWMFRoundtrip);
     CPPUNIT_TEST(testEmfToWmfConversion);
+
+    CPPUNIT_TEST(testSwappingGraphic_PNG_WithGfxLink);
+    CPPUNIT_TEST(testSwappingGraphic_PNG_WithoutGfxLink);
+    CPPUNIT_TEST(testSwappingGraphicProperties_PNG_WithGfxLink);
+    CPPUNIT_TEST(testSwappingGraphicProperties_PNG_WithoutGfxLink);
+
+    CPPUNIT_TEST(testSwappingVectorGraphic_SVG_WithGfxLink);
+    CPPUNIT_TEST(testSwappingVectorGraphic_SVG_WithoutGfxLink);
+    CPPUNIT_TEST(testSwappingGraphicProperties_SVG_WithGfxLink);
+    CPPUNIT_TEST(testSwappingGraphicProperties_SVG_WithoutGfxLink);
+
+    CPPUNIT_TEST(testSwappingVectorGraphic_PDF_WithGfxLink);
+    CPPUNIT_TEST(testSwappingVectorGraphic_PDF_WithoutGfxLink);
+
+    CPPUNIT_TEST(testSwappingAnimationGraphic_GIF_WithGfxLink);
+    CPPUNIT_TEST(testSwappingAnimationGraphic_GIF_WithoutGfxLink);
     CPPUNIT_TEST_SUITE_END();
 };
 
@@ -306,6 +333,33 @@ void GraphicTest::testUnloadedGraphicSizeUnit()
     CPPUNIT_ASSERT_EQUAL(Size(400, 363), aGraphic.GetPrefSize());
 }
 
+void GraphicTest::testWMFRoundtrip()
+{
+    // Load a WMF file.
+    test::Directories aDirectories;
+    OUString aURL = aDirectories.getURLFromSrc("vcl/qa/cppunit/data/roundtrip.wmf");
+    SvFileStream aStream(aURL, StreamMode::READ);
+    sal_uInt64 nExpectedSize = aStream.TellEnd();
+    GraphicFilter& rGraphicFilter = GraphicFilter::GetGraphicFilter();
+    Graphic aGraphic = rGraphicFilter.ImportUnloadedGraphic(aStream);
+
+    // Save as WMF.
+    utl::TempFile aTempFile;
+    aTempFile.EnableKillingFile();
+    sal_uInt16 nFormat = rGraphicFilter.GetExportFormatNumberForShortName(u"WMF");
+    SvStream& rOutStream = *aTempFile.GetStream(StreamMode::READWRITE);
+    rGraphicFilter.ExportGraphic(aGraphic, OUString(), rOutStream, nFormat);
+
+    // Check if we preserved the WMF data perfectly.
+    sal_uInt64 nActualSize = rOutStream.TellEnd();
+
+    // Without the accompanying fix in place, this test would have failed with:
+    // - Expected: 6475
+    // - Actual  : 2826
+    // i.e. we lost some of the WMF data on roundtrip.
+    CPPUNIT_ASSERT_EQUAL(nExpectedSize, nActualSize);
+}
+
 void GraphicTest::testEmfToWmfConversion()
 {
     // Load EMF data.
@@ -363,7 +417,7 @@ void GraphicTest::testEmfToWmfConversion()
     CPPUNIT_ASSERT_LESSEQUAL(4, nCommentCount);
 }
 
-void GraphicTest::testSwapping()
+void GraphicTest::testSwappingGraphic_PNG_WithGfxLink()
 {
     // Prepare Graphic from a PNG image first
     Graphic aGraphic = makeUnloadedGraphic(u"png");
@@ -377,10 +431,64 @@ void GraphicTest::testSwapping()
 
     BitmapChecksum aChecksumBeforeSwapping = aGraphic.GetChecksum();
 
+    CPPUNIT_ASSERT_EQUAL(true, aGraphic.IsGfxLink());
     CPPUNIT_ASSERT_EQUAL(sal_uInt32(319), aGraphic.GetGfxLink().GetDataSize());
 
     // We loaded the Graphic and made it available
     CPPUNIT_ASSERT_EQUAL(false, aGraphic.ImplGetImpGraphic()->isSwappedOut());
+    // Get the declared byte size of the graphic
+    sal_uLong rByteSize = aGraphic.GetSizeBytes();
+
+    // Check the swap file (shouldn't exist)
+    CPPUNIT_ASSERT_EQUAL(true, aGraphic.ImplGetImpGraphic()->getSwapFileURL().isEmpty());
+
+    // Swapping out
+    CPPUNIT_ASSERT_EQUAL(true, aGraphic.ImplGetImpGraphic()->swapOut());
+    CPPUNIT_ASSERT_EQUAL(true, aGraphic.ImplGetImpGraphic()->isSwappedOut());
+    CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable());
+
+    // Byte size doesn't change when we swapped out
+    CPPUNIT_ASSERT_EQUAL(rByteSize, aGraphic.GetSizeBytes());
+
+    // Check the swap file (still shouldn't exist)
+    CPPUNIT_ASSERT_EQUAL(true, aGraphic.ImplGetImpGraphic()->getSwapFileURL().isEmpty());
+
+    // Let's swap in
+    CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable());
+    CPPUNIT_ASSERT_EQUAL(true, aGraphic.makeAvailable());
+    CPPUNIT_ASSERT_EQUAL(true, aGraphic.isAvailable());
+    CPPUNIT_ASSERT_EQUAL(false, aGraphic.ImplGetImpGraphic()->isSwappedOut());
+
+    CPPUNIT_ASSERT_EQUAL(aChecksumBeforeSwapping, aGraphic.GetChecksum());
+
+    // Check the bitmap
+    CPPUNIT_ASSERT_EQUAL(tools::Long(120), aGraphic.GetSizePixel().Width());
+    CPPUNIT_ASSERT_EQUAL(tools::Long(100), aGraphic.GetSizePixel().Height());
+    CPPUNIT_ASSERT_EQUAL(true, checkBitmap(aGraphic));
+}
+
+void GraphicTest::testSwappingGraphic_PNG_WithoutGfxLink()
+{
+    // Prepare Graphic from a PNG image first
+
+    // Make sure to construct the Graphic from BitmapEx, so that we
+    // don't have the GfxLink present.
+    Graphic aGraphic(makeUnloadedGraphic(u"png").GetBitmapEx());
+
+    CPPUNIT_ASSERT_EQUAL(GraphicType::Bitmap, aGraphic.GetType());
+    CPPUNIT_ASSERT_EQUAL(true, aGraphic.makeAvailable());
+    CPPUNIT_ASSERT_EQUAL(true, aGraphic.isAvailable());
+
+    CPPUNIT_ASSERT_EQUAL(tools::Long(120), aGraphic.GetSizePixel().Width());
+    CPPUNIT_ASSERT_EQUAL(tools::Long(100), aGraphic.GetSizePixel().Height());
+
+    BitmapChecksum aChecksumBeforeSwapping = aGraphic.GetChecksum();
+
+    CPPUNIT_ASSERT_EQUAL(false, aGraphic.IsGfxLink());
+
+    // We loaded the Graphic and made it available
+    CPPUNIT_ASSERT_EQUAL(false, aGraphic.ImplGetImpGraphic()->isSwappedOut());
+
     // Get the declared byte size of the graphic
     sal_uLong rByteSize = aGraphic.GetSizeBytes();
     OUString rSwapFileURL = aGraphic.ImplGetImpGraphic()->getSwapFileURL();
@@ -403,19 +511,21 @@ void GraphicTest::testSwapping()
         CPPUNIT_ASSERT_EQUAL(true, bool(xStream));
 
         // Check size of the stream
-        CPPUNIT_ASSERT_EQUAL(sal_uInt64(449), xStream->remainingSize());
+        CPPUNIT_ASSERT_EQUAL(sal_uInt64(36079), xStream->remainingSize());
 
         std::vector<unsigned char> aHash = calculateHash(xStream);
-        CPPUNIT_ASSERT_EQUAL(std::string("878281e583487b29ae09078e8040c01791c7649a"),
+        CPPUNIT_ASSERT_EQUAL(std::string("9347511e3b80dfdfaadf91a3bdef55a8ae85552b"),
                              toHexString(aHash));
     }
 
-    // Let's swap in
+    // SWAP IN
     CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable());
     CPPUNIT_ASSERT_EQUAL(true, aGraphic.makeAvailable());
     CPPUNIT_ASSERT_EQUAL(true, aGraphic.isAvailable());
     CPPUNIT_ASSERT_EQUAL(false, aGraphic.ImplGetImpGraphic()->isSwappedOut());
 
+    // reset the checksum to make sure we don't get the cached value
+    aGraphic.ImplGetImpGraphic()->resetChecksum();
     CPPUNIT_ASSERT_EQUAL(aChecksumBeforeSwapping, aGraphic.GetChecksum());
 
     // File shouldn't be available anymore
@@ -424,29 +534,193 @@ void GraphicTest::testSwapping()
     // Check the bitmap
     CPPUNIT_ASSERT_EQUAL(tools::Long(120), aGraphic.GetSizePixel().Width());
     CPPUNIT_ASSERT_EQUAL(tools::Long(100), aGraphic.GetSizePixel().Height());
+
     CPPUNIT_ASSERT_EQUAL(true, checkBitmap(aGraphic));
-    CPPUNIT_ASSERT_EQUAL(true, checkBitmap(aGraphic));
 }
 
-void GraphicTest::testSwappingVectorGraphic()
+void GraphicTest::testSwappingGraphicProperties_PNG_WithGfxLink()
+{
+    // Prepare Graphic from a PNG image
+    Graphic aGraphic = makeUnloadedGraphic(u"png");
+
+    CPPUNIT_ASSERT_EQUAL(GraphicType::Bitmap, aGraphic.GetType());
+    CPPUNIT_ASSERT_EQUAL(true, aGraphic.makeAvailable());
+    CPPUNIT_ASSERT_EQUAL(true, aGraphic.isAvailable());
+
+    // Origin URL
+    aGraphic.setOriginURL("Origin URL");
+    CPPUNIT_ASSERT_EQUAL(OUString("Origin URL"), aGraphic.getOriginURL());
+
+    //Set PrefMapMode
+    CPPUNIT_ASSERT_EQUAL(MapUnit::Map100thMM, aGraphic.GetPrefMapMode().GetMapUnit());
+    aGraphic.SetPrefMapMode(MapMode(MapUnit::MapTwip));
+    CPPUNIT_ASSERT_EQUAL(MapUnit::MapTwip, aGraphic.GetPrefMapMode().GetMapUnit());
+
+    // Set the PrefSize
+    CPPUNIT_ASSERT_EQUAL(tools::Long(6000), aGraphic.GetPrefSize().Width());
+    CPPUNIT_ASSERT_EQUAL(tools::Long(5000), aGraphic.GetPrefSize().Height());
+    aGraphic.SetPrefSize(Size(200, 100));
+    CPPUNIT_ASSERT_EQUAL(tools::Long(200), aGraphic.GetPrefSize().Width());
+    CPPUNIT_ASSERT_EQUAL(tools::Long(100), aGraphic.GetPrefSize().Height());
+
+    // SWAP OUT
+    CPPUNIT_ASSERT_EQUAL(true, aGraphic.isAvailable());
+    CPPUNIT_ASSERT_EQUAL(true, aGraphic.ImplGetImpGraphic()->swapOut());
+    CPPUNIT_ASSERT_EQUAL(true, aGraphic.ImplGetImpGraphic()->isSwappedOut());
+    CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable());
+
+    // Check properties
+    CPPUNIT_ASSERT_EQUAL(OUString("Origin URL"), aGraphic.getOriginURL());
+    CPPUNIT_ASSERT_EQUAL(MapUnit::MapTwip, aGraphic.GetPrefMapMode().GetMapUnit());
+    CPPUNIT_ASSERT_EQUAL(tools::Long(200), aGraphic.GetPrefSize().Width());
+    CPPUNIT_ASSERT_EQUAL(tools::Long(100), aGraphic.GetPrefSize().Height());
+
+    // SWAP IN
+    CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable());
+    CPPUNIT_ASSERT_EQUAL(true, aGraphic.makeAvailable());
+    CPPUNIT_ASSERT_EQUAL(true, aGraphic.isAvailable());
+    CPPUNIT_ASSERT_EQUAL(false, aGraphic.ImplGetImpGraphic()->isSwappedOut());
+
+    // Check properties
+    CPPUNIT_ASSERT_EQUAL(OUString("Origin URL"), aGraphic.getOriginURL());
+    CPPUNIT_ASSERT_EQUAL(MapUnit::MapTwip, aGraphic.GetPrefMapMode().GetMapUnit());
+    CPPUNIT_ASSERT_EQUAL(tools::Long(200), aGraphic.GetPrefSize().Width());
+    CPPUNIT_ASSERT_EQUAL(tools::Long(100), aGraphic.GetPrefSize().Height());
+}
+
+void GraphicTest::testSwappingGraphicProperties_PNG_WithoutGfxLink()
+{
+    // Prepare Graphic from a PNG image
+    Graphic aGraphic(makeUnloadedGraphic(u"png").GetBitmapEx());
+
+    CPPUNIT_ASSERT_EQUAL(GraphicType::Bitmap, aGraphic.GetType());
+    CPPUNIT_ASSERT_EQUAL(true, aGraphic.makeAvailable());
+    CPPUNIT_ASSERT_EQUAL(true, aGraphic.isAvailable());
+
+    // Origin URL
+    aGraphic.setOriginURL("Origin URL");
+    CPPUNIT_ASSERT_EQUAL(OUString("Origin URL"), aGraphic.getOriginURL());
+
+    //Set PrefMapMode
+    CPPUNIT_ASSERT_EQUAL(MapUnit::Map100thMM, aGraphic.GetPrefMapMode().GetMapUnit());
+    aGraphic.SetPrefMapMode(MapMode(MapUnit::MapTwip));
+    CPPUNIT_ASSERT_EQUAL(MapUnit::MapTwip, aGraphic.GetPrefMapMode().GetMapUnit());
+
+    // Set the PrefSize
+    CPPUNIT_ASSERT_EQUAL(tools::Long(6000), aGraphic.GetPrefSize().Width());
+    CPPUNIT_ASSERT_EQUAL(tools::Long(5000), aGraphic.GetPrefSize().Height());
+    aGraphic.SetPrefSize(Size(200, 100));
+    CPPUNIT_ASSERT_EQUAL(tools::Long(200), aGraphic.GetPrefSize().Width());
+    CPPUNIT_ASSERT_EQUAL(tools::Long(100), aGraphic.GetPrefSize().Height());
+
+    // SWAP OUT
+    CPPUNIT_ASSERT_EQUAL(true, aGraphic.isAvailable());
+    CPPUNIT_ASSERT_EQUAL(true, aGraphic.ImplGetImpGraphic()->swapOut());
+    CPPUNIT_ASSERT_EQUAL(true, aGraphic.ImplGetImpGraphic()->isSwappedOut());
+    CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable());
+
+    // Check properties
+    CPPUNIT_ASSERT_EQUAL(OUString("Origin URL"), aGraphic.getOriginURL());
+    CPPUNIT_ASSERT_EQUAL(MapUnit::MapTwip, aGraphic.GetPrefMapMode().GetMapUnit());
+    CPPUNIT_ASSERT_EQUAL(tools::Long(200), aGraphic.GetPrefSize().Width());
+    CPPUNIT_ASSERT_EQUAL(tools::Long(100), aGraphic.GetPrefSize().Height());
+
+    // SWAP IN
+    CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable());
+    CPPUNIT_ASSERT_EQUAL(true, aGraphic.makeAvailable());
+    CPPUNIT_ASSERT_EQUAL(true, aGraphic.isAvailable());
+    CPPUNIT_ASSERT_EQUAL(false, aGraphic.ImplGetImpGraphic()->isSwappedOut());
+
+    // Check properties
+    CPPUNIT_ASSERT_EQUAL(OUString("Origin URL"), aGraphic.getOriginURL());
+    CPPUNIT_ASSERT_EQUAL(MapUnit::MapTwip, aGraphic.GetPrefMapMode().GetMapUnit());
+    CPPUNIT_ASSERT_EQUAL(tools::Long(200), aGraphic.GetPrefSize().Width());
+    CPPUNIT_ASSERT_EQUAL(tools::Long(100), aGraphic.GetPrefSize().Height());
+}
+
+void GraphicTest::testSwappingVectorGraphic_SVG_WithGfxLink()
 {
     test::Directories aDirectories;
     OUString aURL = aDirectories.getURLFromSrc(DATA_DIRECTORY) + "SimpleExample.svg";
     SvFileStream aStream(aURL, StreamMode::READ);
     GraphicFilter& rGraphicFilter = GraphicFilter::GetGraphicFilter();
     Graphic aGraphic = rGraphicFilter.ImportUnloadedGraphic(aStream);
+    // Loaded into "prepared" state
 
+    // Check that the state is as expected
     CPPUNIT_ASSERT_EQUAL(GraphicType::Bitmap, aGraphic.GetType());
     CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable());
 
     // Load the vector graphic
-    CPPUNIT_ASSERT_EQUAL(true, bool(aGraphic.getVectorGraphicData()));
-    CPPUNIT_ASSERT_EQUAL(sal_uInt32(223),
-                         aGraphic.getVectorGraphicData()->getVectorGraphicDataArrayLength());
+    auto pVectorData = aGraphic.getVectorGraphicData();
+    CPPUNIT_ASSERT_EQUAL(true, bool(pVectorData));
     CPPUNIT_ASSERT_EQUAL(true, aGraphic.isAvailable());
+
+    CPPUNIT_ASSERT_EQUAL(sal_uInt32(223), pVectorData->getVectorGraphicDataArrayLength());
+
+    CPPUNIT_ASSERT_EQUAL(true, aGraphic.IsGfxLink());
     CPPUNIT_ASSERT_EQUAL(sal_uInt32(223), aGraphic.GetGfxLink().GetDataSize());
+
+    // Remember checksum so we can compare after swapping back in again
+    BitmapChecksum aBitmapChecksumBeforeSwapping = aGraphic.GetBitmapEx().GetChecksum();
+
+    // Check we are not swapped out yet
+    CPPUNIT_ASSERT_EQUAL(false, aGraphic.ImplGetImpGraphic()->isSwappedOut());
+
+    // Get the declared byte size of the graphic
+    sal_uLong rByteSize = aGraphic.GetSizeBytes();
+    CPPUNIT_ASSERT_EQUAL(sal_uLong(223), rByteSize);
+
+    // Make sure we don't have a file
+    CPPUNIT_ASSERT_EQUAL(true, aGraphic.ImplGetImpGraphic()->getSwapFileURL().isEmpty());
+
+    // SWAP OUT the Graphic and make sure it's not available currently
+    CPPUNIT_ASSERT_EQUAL(true, aGraphic.ImplGetImpGraphic()->swapOut());
+    CPPUNIT_ASSERT_EQUAL(true, aGraphic.ImplGetImpGraphic()->isSwappedOut());
+    CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable());
+
+    // We use GfxLink so no swap file in this case
+    CPPUNIT_ASSERT_EQUAL(true, aGraphic.ImplGetImpGraphic()->getSwapFileURL().isEmpty());
+
+    // Byte size doesn't change when we swapped out
+    CPPUNIT_ASSERT_EQUAL(rByteSize, aGraphic.GetSizeBytes());
+
+    // SWAP IN
+    CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable());
+    CPPUNIT_ASSERT_EQUAL(true, aGraphic.makeAvailable());
+    CPPUNIT_ASSERT_EQUAL(true, aGraphic.isAvailable());
+    CPPUNIT_ASSERT_EQUAL(false, aGraphic.ImplGetImpGraphic()->isSwappedOut());
+
+    // Compare that the checksum of the bitmap is still the same
+    CPPUNIT_ASSERT_EQUAL(aBitmapChecksumBeforeSwapping, aGraphic.GetBitmapEx().GetChecksum());
+
+    // Byte size shouldn't change
+    CPPUNIT_ASSERT_EQUAL(rByteSize, aGraphic.GetSizeBytes());
+}
+
+void GraphicTest::testSwappingVectorGraphic_SVG_WithoutGfxLink()
+{
+    test::Directories aDirectories;
+    OUString aURL = aDirectories.getURLFromSrc(DATA_DIRECTORY) + "SimpleExample.svg";
+    SvFileStream aStream(aURL, StreamMode::READ);
+    GraphicFilter& rGraphicFilter = GraphicFilter::GetGraphicFilter();
+
+    Graphic aInputGraphic = rGraphicFilter.ImportUnloadedGraphic(aStream);
+    CPPUNIT_ASSERT_EQUAL(sal_uInt32(223),
+                         aInputGraphic.getVectorGraphicData()->getVectorGraphicDataArrayLength());
+
+    // Create graphic
+    Graphic aGraphic(aInputGraphic.getVectorGraphicData());
+
+    CPPUNIT_ASSERT_EQUAL(GraphicType::Bitmap, aGraphic.GetType());
+    CPPUNIT_ASSERT_EQUAL(true, bool(aGraphic.getVectorGraphicData()));
     CPPUNIT_ASSERT_EQUAL(true, aGraphic.isAvailable());
 
+    CPPUNIT_ASSERT_EQUAL(sal_uInt32(223),
+                         aGraphic.getVectorGraphicData()->getVectorGraphicDataArrayLength());
+
+    CPPUNIT_ASSERT_EQUAL(false, aGraphic.IsGfxLink());
+
     BitmapChecksum aBitmapChecksumBeforeSwapping = aGraphic.GetBitmapEx().GetChecksum();
 
     CPPUNIT_ASSERT_EQUAL(false, aGraphic.ImplGetImpGraphic()->isSwappedOut());
@@ -454,6 +728,7 @@ void GraphicTest::testSwappingVectorGraphic()
     // Get the declared byte size of the graphic
     sal_uLong rByteSize = aGraphic.GetSizeBytes();
     CPPUNIT_ASSERT_EQUAL(sal_uLong(223), rByteSize);
+
     OUString rSwapFileURL = aGraphic.ImplGetImpGraphic()->getSwapFileURL();
     CPPUNIT_ASSERT_EQUAL(true, rSwapFileURL.isEmpty());
 
@@ -468,17 +743,19 @@ void GraphicTest::testSwappingVectorGraphic()
 
     // Let's check the swap file
     rSwapFileURL = aGraphic.ImplGetImpGraphic()->getSwapFileURL();
+    CPPUNIT_ASSERT_EQUAL(false, rSwapFileURL.isEmpty());
     CPPUNIT_ASSERT_EQUAL(true, comphelper::DirectoryHelper::fileExists(rSwapFileURL));
 
-    { // Check the swap file content
+    {
+        // Check the swap file content
         std::unique_ptr<SvStream> xStream = createStream(rSwapFileURL);
         CPPUNIT_ASSERT_EQUAL(true, bool(xStream));
 
         // Check size of the stream
-        CPPUNIT_ASSERT_EQUAL(sal_uInt64(353), xStream->remainingSize());
+        CPPUNIT_ASSERT_EQUAL(sal_uInt64(249), xStream->remainingSize());
 
         std::vector<unsigned char> aHash = calculateHash(xStream);
-        CPPUNIT_ASSERT_EQUAL(std::string("6ae83fc9c06ca253ada0b156d6e4700a4a028c34"),
+        CPPUNIT_ASSERT_EQUAL(std::string("322da9ea0683f03ce35cf8a71e59b686b9be28e8"),
                              toHexString(aHash));
     }
 
@@ -486,15 +763,146 @@ void GraphicTest::testSwappingVectorGraphic()
     CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable());
     CPPUNIT_ASSERT_EQUAL(true, aGraphic.makeAvailable());
     CPPUNIT_ASSERT_EQUAL(true, aGraphic.isAvailable());
+
+    // Check the Graphic
     CPPUNIT_ASSERT_EQUAL(false, aGraphic.ImplGetImpGraphic()->isSwappedOut());
 
+    CPPUNIT_ASSERT_EQUAL(GraphicType::Bitmap, aGraphic.GetType());
+    CPPUNIT_ASSERT_EQUAL(true, bool(aGraphic.getVectorGraphicData()));
+
+    sal_uInt32 nVectorByteSize = aGraphic.getVectorGraphicData()->getVectorGraphicDataArrayLength();
+    CPPUNIT_ASSERT_EQUAL(sal_uInt32(223), nVectorByteSize);
+
+    CPPUNIT_ASSERT_EQUAL(false, aGraphic.IsGfxLink());
+
     CPPUNIT_ASSERT_EQUAL(aBitmapChecksumBeforeSwapping, aGraphic.GetBitmapEx().GetChecksum());
 
     // File shouldn't be available anymore
     CPPUNIT_ASSERT_EQUAL(false, comphelper::DirectoryHelper::fileExists(rSwapFileURL));
 }
 
-void GraphicTest::testSwappingPageNumber()
+void GraphicTest::testSwappingGraphicProperties_SVG_WithGfxLink()
+{
+    // We check that Graphic properties like MapMode, PrefSize are properly
+    // restored through a swap cycle
+
+    test::Directories aDirectories;
+    OUString aURL = aDirectories.getURLFromSrc(DATA_DIRECTORY) + "SimpleExample.svg";
+    SvFileStream aStream(aURL, StreamMode::READ);
+    GraphicFilter& rGraphicFilter = GraphicFilter::GetGraphicFilter();
+    Graphic aGraphic = rGraphicFilter.ImportUnloadedGraphic(aStream);
+    // Loaded into "prepared" state
+
+    // Load the vector graphic
+    auto pVectorData = aGraphic.getVectorGraphicData();
+    CPPUNIT_ASSERT_EQUAL(true, bool(pVectorData));
+    CPPUNIT_ASSERT_EQUAL(true, aGraphic.isAvailable());
+
+    // Origin URL
+    aGraphic.setOriginURL("Origin URL");
+    CPPUNIT_ASSERT_EQUAL(OUString("Origin URL"), aGraphic.getOriginURL());
+
+    // Check size in pixels
+    CPPUNIT_ASSERT_EQUAL(tools::Long(51), aGraphic.GetSizePixel().Width());
+    CPPUNIT_ASSERT_EQUAL(tools::Long(51), aGraphic.GetSizePixel().Height());
+
+    // Set and check the PrefSize
+    CPPUNIT_ASSERT_EQUAL(tools::Long(1349), aGraphic.GetPrefSize().Width());
+    CPPUNIT_ASSERT_EQUAL(tools::Long(1349), aGraphic.GetPrefSize().Height());
+    aGraphic.SetPrefSize(Size(200, 100));
+    CPPUNIT_ASSERT_EQUAL(tools::Long(200), aGraphic.GetPrefSize().Width());
+    CPPUNIT_ASSERT_EQUAL(tools::Long(100), aGraphic.GetPrefSize().Height());
+
+    // SWAP OUT the Graphic and make sure it's not available currently
+    CPPUNIT_ASSERT_EQUAL(true, aGraphic.isAvailable());
+    CPPUNIT_ASSERT_EQUAL(true, aGraphic.ImplGetImpGraphic()->swapOut());
+    CPPUNIT_ASSERT_EQUAL(true, aGraphic.ImplGetImpGraphic()->isSwappedOut());
+    CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable());
+
+    // Check properties
+    CPPUNIT_ASSERT_EQUAL(OUString("Origin URL"), aGraphic.getOriginURL());
+    CPPUNIT_ASSERT_EQUAL(tools::Long(200), aGraphic.GetPrefSize().Width());
+    CPPUNIT_ASSERT_EQUAL(tools::Long(100), aGraphic.GetPrefSize().Height());
+    CPPUNIT_ASSERT_EQUAL(tools::Long(51), aGraphic.GetSizePixel().Width());
+    CPPUNIT_ASSERT_EQUAL(tools::Long(51), aGraphic.GetSizePixel().Height());
+
+    // SWAP IN
+    CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable());
+    CPPUNIT_ASSERT_EQUAL(true, aGraphic.makeAvailable());
+    CPPUNIT_ASSERT_EQUAL(true, aGraphic.isAvailable());
+    CPPUNIT_ASSERT_EQUAL(false, aGraphic.ImplGetImpGraphic()->isSwappedOut());
+
+    // Check properties
+    CPPUNIT_ASSERT_EQUAL(OUString("Origin URL"), aGraphic.getOriginURL());
+    CPPUNIT_ASSERT_EQUAL(tools::Long(200), aGraphic.GetPrefSize().Width());
+    CPPUNIT_ASSERT_EQUAL(tools::Long(100), aGraphic.GetPrefSize().Height());
+    CPPUNIT_ASSERT_EQUAL(tools::Long(51), aGraphic.GetSizePixel().Width());
+    CPPUNIT_ASSERT_EQUAL(tools::Long(51), aGraphic.GetSizePixel().Height());
+}
+
+void GraphicTest::testSwappingGraphicProperties_SVG_WithoutGfxLink()
+{
+    test::Directories aDirectories;
+    OUString aURL = aDirectories.getURLFromSrc(DATA_DIRECTORY) + "SimpleExample.svg";
+    SvFileStream aStream(aURL, StreamMode::READ);
+    GraphicFilter& rGraphicFilter = GraphicFilter::GetGraphicFilter();
+
+    Graphic aInputGraphic = rGraphicFilter.ImportUnloadedGraphic(aStream);
+    CPPUNIT_ASSERT_EQUAL(sal_uInt32(223),
+                         aInputGraphic.getVectorGraphicData()->getVectorGraphicDataArrayLength());
+
+    // Create graphic
+    Graphic aGraphic(aInputGraphic.getVectorGraphicData());
+
+    CPPUNIT_ASSERT_EQUAL(GraphicType::Bitmap, aGraphic.GetType());
+    CPPUNIT_ASSERT_EQUAL(true, bool(aGraphic.getVectorGraphicData()));
+    CPPUNIT_ASSERT_EQUAL(true, aGraphic.isAvailable());
+    CPPUNIT_ASSERT_EQUAL(false, aGraphic.IsGfxLink());
+    CPPUNIT_ASSERT_EQUAL(false, aGraphic.ImplGetImpGraphic()->isSwappedOut());
+
+    // Origin URL
+    aGraphic.setOriginURL("Origin URL");
+    CPPUNIT_ASSERT_EQUAL(OUString("Origin URL"), aGraphic.getOriginURL());
+
+    // Check size in pixels
+    CPPUNIT_ASSERT_EQUAL(tools::Long(51), aGraphic.GetSizePixel().Width());
+    CPPUNIT_ASSERT_EQUAL(tools::Long(51), aGraphic.GetSizePixel().Height());
+
+    // Set and check the PrefSize
+    CPPUNIT_ASSERT_EQUAL(tools::Long(1349), aGraphic.GetPrefSize().Width());
+    CPPUNIT_ASSERT_EQUAL(tools::Long(1349), aGraphic.GetPrefSize().Height());
+    aGraphic.SetPrefSize(Size(200, 100));
+    CPPUNIT_ASSERT_EQUAL(tools::Long(200), aGraphic.GetPrefSize().Width());
+    CPPUNIT_ASSERT_EQUAL(tools::Long(100), aGraphic.GetPrefSize().Height());
+
+    // SWAP OUT the Graphic and make sure it's not available currently
+    CPPUNIT_ASSERT_EQUAL(true, aGraphic.isAvailable());
+    CPPUNIT_ASSERT_EQUAL(true, aGraphic.ImplGetImpGraphic()->swapOut());
+    CPPUNIT_ASSERT_EQUAL(true, aGraphic.ImplGetImpGraphic()->isSwappedOut());
+    CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable());
+
+    CPPUNIT_ASSERT_EQUAL(OUString("Origin URL"), aGraphic.getOriginURL());
+
+    CPPUNIT_ASSERT_EQUAL(tools::Long(200), aGraphic.GetPrefSize().Width());
+    CPPUNIT_ASSERT_EQUAL(tools::Long(100), aGraphic.GetPrefSize().Height());
+    CPPUNIT_ASSERT_EQUAL(tools::Long(51), aGraphic.GetSizePixel().Width());
+    CPPUNIT_ASSERT_EQUAL(tools::Long(51), aGraphic.GetSizePixel().Height());
+
+    // SWAP IN
+    CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable());
+    CPPUNIT_ASSERT_EQUAL(true, aGraphic.makeAvailable());
+    CPPUNIT_ASSERT_EQUAL(true, aGraphic.isAvailable());
+    CPPUNIT_ASSERT_EQUAL(false, aGraphic.ImplGetImpGraphic()->isSwappedOut());
+
+    CPPUNIT_ASSERT_EQUAL(OUString("Origin URL"), aGraphic.getOriginURL());
+
+    CPPUNIT_ASSERT_EQUAL(tools::Long(200), aGraphic.GetPrefSize().Width());
+    CPPUNIT_ASSERT_EQUAL(tools::Long(100), aGraphic.GetPrefSize().Height());
+    CPPUNIT_ASSERT_EQUAL(tools::Long(51), aGraphic.GetSizePixel().Width());
+    CPPUNIT_ASSERT_EQUAL(tools::Long(51), aGraphic.GetSizePixel().Height());
+}
+
+void GraphicTest::testSwappingVectorGraphic_PDF_WithGfxLink()
 {
     test::Directories aDirectories;
     OUString aURL = aDirectories.getURLFromSrc(PDFEXPORT_DATA_DIRECTORY) + "SimpleMultiPagePDF.pdf";
@@ -507,6 +915,7 @@ void GraphicTest::testSwappingPageNumber()
 
     // Load the vector graphic
     CPPUNIT_ASSERT_EQUAL(true, bool(aGraphic.getVectorGraphicData()));
+
     // Set the page index
     aGraphic.getVectorGraphicData()->setPageIndex(1);
 
@@ -519,12 +928,12 @@ void GraphicTest::testSwappingPageNumber()
 
     CPPUNIT_ASSERT_EQUAL(false, aGraphic.ImplGetImpGraphic()->isSwappedOut());
 
-    // Swapping out
+    // SWAP OUT
     CPPUNIT_ASSERT_EQUAL(true, aGraphic.ImplGetImpGraphic()->swapOut());
     CPPUNIT_ASSERT_EQUAL(true, aGraphic.ImplGetImpGraphic()->isSwappedOut());
     CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable());
 
-    // Let's swap in
+    // SWAP IN
     CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable());
     CPPUNIT_ASSERT_EQUAL(true, aGraphic.makeAvailable());
     CPPUNIT_ASSERT_EQUAL(true, aGraphic.isAvailable());
@@ -533,31 +942,176 @@ void GraphicTest::testSwappingPageNumber()
     CPPUNIT_ASSERT_EQUAL(sal_Int32(1), aGraphic.getVectorGraphicData()->getPageIndex());
 }
 
-void GraphicTest::testWMFRoundtrip()
+void GraphicTest::testSwappingVectorGraphic_PDF_WithoutGfxLink()
 {
-    // Load a WMF file.
     test::Directories aDirectories;
-    OUString aURL = aDirectories.getURLFromSrc("vcl/qa/cppunit/data/roundtrip.wmf");
+    OUString aURL = aDirectories.getURLFromSrc(PDFEXPORT_DATA_DIRECTORY) + "SimpleMultiPagePDF.pdf";
+    SvFileStream aStream(aURL, StreamMode::READ);
+    GraphicFilter& rGraphicFilter = GraphicFilter::GetGraphicFilter();
+    Graphic aInputGraphic = rGraphicFilter.ImportUnloadedGraphic(aStream);
+
+    // Create graphic
+    Graphic aGraphic(aInputGraphic.getVectorGraphicData());
+
+    CPPUNIT_ASSERT_EQUAL(GraphicType::Bitmap, aGraphic.GetType());
+    CPPUNIT_ASSERT_EQUAL(true, aGraphic.isAvailable());
+    CPPUNIT_ASSERT_EQUAL(true, bool(aGraphic.getVectorGraphicData()));
+
+    // Set the page index
+    aGraphic.getVectorGraphicData()->setPageIndex(1);
+
+    CPPUNIT_ASSERT_EQUAL(VectorGraphicDataType::Pdf,
+                         aGraphic.getVectorGraphicData()->getVectorGraphicDataType());
+    CPPUNIT_ASSERT_EQUAL(sal_uInt32(17693),
+                         aGraphic.getVectorGraphicData()->getVectorGraphicDataArrayLength());
+    CPPUNIT_ASSERT_EQUAL(true, aGraphic.isAvailable());
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), aGraphic.getVectorGraphicData()->getPageIndex());
+
+    CPPUNIT_ASSERT_EQUAL(false, aGraphic.ImplGetImpGraphic()->isSwappedOut());
+
+    // SWAP OUT
+    CPPUNIT_ASSERT_EQUAL(true, aGraphic.ImplGetImpGraphic()->swapOut());
+    CPPUNIT_ASSERT_EQUAL(true, aGraphic.ImplGetImpGraphic()->isSwappedOut());
+    CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable());
+
+    // SWAP IN
+    CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable());
+    CPPUNIT_ASSERT_EQUAL(true, aGraphic.makeAvailable());
+    CPPUNIT_ASSERT_EQUAL(true, aGraphic.isAvailable());
+    CPPUNIT_ASSERT_EQUAL(false, aGraphic.ImplGetImpGraphic()->isSwappedOut());
+
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), aGraphic.getVectorGraphicData()->getPageIndex());
+}
+
+void GraphicTest::testSwappingAnimationGraphic_GIF_WithGfxLink()
+{
+    test::Directories aDirectories;
+    OUString aURL = aDirectories.getURLFromSrc(DATA_DIRECTORY) + "123_Numbers.gif";
     SvFileStream aStream(aURL, StreamMode::READ);
-    sal_uInt64 nExpectedSize = aStream.TellEnd();
     GraphicFilter& rGraphicFilter = GraphicFilter::GetGraphicFilter();
     Graphic aGraphic = rGraphicFilter.ImportUnloadedGraphic(aStream);
+    // Loaded into "prepared" state
 
-    // Save as WMF.
-    utl::TempFile aTempFile;
-    aTempFile.EnableKillingFile();
-    sal_uInt16 nFormat = rGraphicFilter.GetExportFormatNumberForShortName(u"WMF");
-    SvStream& rOutStream = *aTempFile.GetStream(StreamMode::READWRITE);
-    rGraphicFilter.ExportGraphic(aGraphic, OUString(), rOutStream, nFormat);
+    // Check that the state is as expected
+    CPPUNIT_ASSERT_EQUAL(GraphicType::Bitmap, aGraphic.GetType());
+    CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable());
 
-    // Check if we preserved the WMF data perfectly.
-    sal_uInt64 nActualSize = rOutStream.TellEnd();
+    CPPUNIT_ASSERT_EQUAL(true, aGraphic.makeAvailable());
+    CPPUNIT_ASSERT_EQUAL(true, aGraphic.isAvailable());
 
-    // Without the accompanying fix in place, this test would have failed with:
-    // - Expected: 6475
-    // - Actual  : 2826
-    // i.e. we lost some of the WMF data on roundtrip.
-    CPPUNIT_ASSERT_EQUAL(nExpectedSize, nActualSize);
+    CPPUNIT_ASSERT_EQUAL(true, aGraphic.IsGfxLink());
+
+    CPPUNIT_ASSERT_EQUAL(tools::Long(124), aGraphic.GetSizePixel().Width());
+    CPPUNIT_ASSERT_EQUAL(tools::Long(146), aGraphic.GetSizePixel().Height());
+
+    CPPUNIT_ASSERT_EQUAL(sal_uInt32(1515), aGraphic.GetGfxLink().GetDataSize());
+
+    // Remember checksum so we can compare after swapping back in again
+    BitmapChecksum aBitmapChecksumBeforeSwapping = aGraphic.GetBitmapEx().GetChecksum();
+
+    // Check we are not swapped out yet
+    CPPUNIT_ASSERT_EQUAL(false, aGraphic.ImplGetImpGraphic()->isSwappedOut());
+
+    // Get the declared byte size of the graphic
+    sal_uLong rByteSize = aGraphic.GetSizeBytes();
+    CPPUNIT_ASSERT_EQUAL(sal_uLong(50373), rByteSize);
+
+    // Make sure we don't have a file
+    CPPUNIT_ASSERT_EQUAL(true, aGraphic.ImplGetImpGraphic()->getSwapFileURL().isEmpty());
+
+    // SWAP OUT the Graphic and make sure it's not available currently
+    CPPUNIT_ASSERT_EQUAL(true, aGraphic.ImplGetImpGraphic()->swapOut());
+    CPPUNIT_ASSERT_EQUAL(true, aGraphic.ImplGetImpGraphic()->isSwappedOut());
+    CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable());
+
+    // We use GfxLink so no swap file in this case
+    CPPUNIT_ASSERT_EQUAL(true, aGraphic.ImplGetImpGraphic()->getSwapFileURL().isEmpty());
+
+    // Byte size doesn't change when we swapped out
+    CPPUNIT_ASSERT_EQUAL(rByteSize, aGraphic.GetSizeBytes());
+
+    // SWAP IN
+    CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable());
+    CPPUNIT_ASSERT_EQUAL(true, aGraphic.makeAvailable());
+    CPPUNIT_ASSERT_EQUAL(true, aGraphic.isAvailable());
+    CPPUNIT_ASSERT_EQUAL(false, aGraphic.ImplGetImpGraphic()->isSwappedOut());
+
+    // Compare that the checksum of the bitmap is still the same
+    CPPUNIT_ASSERT_EQUAL(aBitmapChecksumBeforeSwapping, aGraphic.GetBitmapEx().GetChecksum());
+
+    // Byte size shouldn't change
+    CPPUNIT_ASSERT_EQUAL(rByteSize, aGraphic.GetSizeBytes());
+}
+
+void GraphicTest::testSwappingAnimationGraphic_GIF_WithoutGfxLink()
+{
+    test::Directories aDirectories;
+    OUString aURL = aDirectories.getURLFromSrc(DATA_DIRECTORY) + "123_Numbers.gif";
+    SvFileStream aStream(aURL, StreamMode::READ);
+    GraphicFilter& rGraphicFilter = GraphicFilter::GetGraphicFilter();
+    Graphic aInputGraphic = rGraphicFilter.ImportUnloadedGraphic(aStream);
+    Graphic aGraphic(aInputGraphic.GetAnimation());
+
+    // Check animation graphic
+    CPPUNIT_ASSERT_EQUAL(GraphicType::Bitmap, aGraphic.GetType());
+    CPPUNIT_ASSERT_EQUAL(true, aGraphic.makeAvailable());
+    CPPUNIT_ASSERT_EQUAL(true, aGraphic.isAvailable());
+    CPPUNIT_ASSERT_EQUAL(true, aGraphic.IsAnimated());
+
+    CPPUNIT_ASSERT_EQUAL(tools::Long(124), aGraphic.GetSizePixel().Width());
+    CPPUNIT_ASSERT_EQUAL(tools::Long(146), aGraphic.GetSizePixel().Height());
+
+    CPPUNIT_ASSERT_EQUAL(false, aGraphic.IsGfxLink());
+
+    // We loaded the Graphic and made it available
+    CPPUNIT_ASSERT_EQUAL(false, aGraphic.ImplGetImpGraphic()->isSwappedOut());
+
+    // Get the declared byte size of the graphic
+    sal_uLong rByteSize = aGraphic.GetSizeBytes();
+    OUString rSwapFileURL = aGraphic.ImplGetImpGraphic()->getSwapFileURL();
+    CPPUNIT_ASSERT_EQUAL(true, rSwapFileURL.isEmpty());
+
+    // SWAP OUT
+    CPPUNIT_ASSERT_EQUAL(true, aGraphic.isAvailable());
+    CPPUNIT_ASSERT_EQUAL(true, aGraphic.ImplGetImpGraphic()->swapOut());
+    CPPUNIT_ASSERT_EQUAL(true, aGraphic.ImplGetImpGraphic()->isSwappedOut());
+    CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable());
+
+    // Byte size doesn't change when we swapped out
+    CPPUNIT_ASSERT_EQUAL(rByteSize, aGraphic.GetSizeBytes());
+
+    // Let's check the swap file
+    rSwapFileURL = aGraphic.ImplGetImpGraphic()->getSwapFileURL();
+    CPPUNIT_ASSERT_EQUAL(true, comphelper::DirectoryHelper::fileExists(rSwapFileURL));
+
+    {
+        // Check the swap file content
+        std::unique_ptr<SvStream> xStream = createStream(rSwapFileURL);
+        CPPUNIT_ASSERT_EQUAL(true, bool(xStream));
+
+        // Check size of the stream
+        CPPUNIT_ASSERT_EQUAL(sal_uInt64(15183), xStream->remainingSize());
+
+        std::vector<unsigned char> aHash = calculateHash(xStream);
+        CPPUNIT_ASSERT_EQUAL(std::string("deb13fdf0ffa0b58ce92fff0a6ca9e98c5d26ed9"),
+                             toHexString(aHash));
+    }
+
+    // SWAP IN
+    CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable());
+    CPPUNIT_ASSERT_EQUAL(true, aGraphic.makeAvailable());
+    CPPUNIT_ASSERT_EQUAL(true, aGraphic.isAvailable());
+    CPPUNIT_ASSERT_EQUAL(false, aGraphic.ImplGetImpGraphic()->isSwappedOut());
+
+    // File shouldn't be available anymore
+    CPPUNIT_ASSERT_EQUAL(false, comphelper::DirectoryHelper::fileExists(rSwapFileURL));
+
+    // Check the bitmap
+    CPPUNIT_ASSERT_EQUAL(tools::Long(124), aGraphic.GetSizePixel().Width());
+    CPPUNIT_ASSERT_EQUAL(tools::Long(146), aGraphic.GetSizePixel().Height());
+
+    // Byte size is still the same
+    CPPUNIT_ASSERT_EQUAL(rByteSize, aGraphic.GetSizeBytes());
 }
 
 } // namespace
diff --git a/vcl/source/gdi/TypeSerializer.cxx b/vcl/source/gdi/TypeSerializer.cxx
index c86498485d4f..f02edcb38b25 100644
--- a/vcl/source/gdi/TypeSerializer.cxx
+++ b/vcl/source/gdi/TypeSerializer.cxx
@@ -160,11 +160,6 @@ namespace
 {
 #define NATIVE_FORMAT_50 COMPAT_FORMAT('N', 'A', 'T', '5')
 
-constexpr sal_uInt32 constSvgMagic = createMagic('s', 'v', 'g', '0');
-constexpr sal_uInt32 constWmfMagic = createMagic('w', 'm', 'f', '0');
-constexpr sal_uInt32 constEmfMagic = createMagic('e', 'm', 'f', '0');
-constexpr sal_uInt32 constPdfMagic = createMagic('p', 'd', 'f', '0');
-
 } // end anonymous namespace
 
 void TypeSerializer::readGraphic(Graphic& rGraphic)
diff --git a/vcl/source/gdi/impgraph.cxx b/vcl/source/gdi/impgraph.cxx
index aed7f2e86772..fec7c9654f4c 100644
--- a/vcl/source/gdi/impgraph.cxx
+++ b/vcl/source/gdi/impgraph.cxx
@@ -50,23 +50,9 @@
 #define GRAPHIC_MTFTOBMP_MAXEXT     2048
 #define GRAPHIC_STREAMBUFSIZE       8192UL
 
-#define SYS_WINMETAFILE             0x00000003L
-#define SYS_WNTMETAFILE             0x00000004L
-#define SYS_OS2METAFILE             0x00000005L
-#define SYS_MACMETAFILE             0x00000006L
-
-#define GRAPHIC_FORMAT_50           COMPAT_FORMAT( 'G', 'R', 'F', '5' )
+#define SWAP_FORMAT_ID COMPAT_FORMAT( 'S', 'W', 'A', 'P' )
 #define NATIVE_FORMAT_50            COMPAT_FORMAT( 'N', 'A', 'T', '5' )
 
-namespace {
-
-constexpr sal_uInt32 constSvgMagic((sal_uInt32('s') << 24) | (sal_uInt32('v') << 16) | (sal_uInt32('g') << 8) | sal_uInt32('0'));
-constexpr sal_uInt32 constWmfMagic((sal_uInt32('w') << 24) | (sal_uInt32('m') << 16) | (sal_uInt32('f') << 8) | sal_uInt32('0'));
-constexpr sal_uInt32 constEmfMagic((sal_uInt32('e') << 24) | (sal_uInt32('m') << 16) | (sal_uInt32('f') << 8) | sal_uInt32('0'));
-constexpr sal_uInt32 constPdfMagic((sal_uInt32('s') << 24) | (sal_uInt32('v') << 16) | (sal_uInt32('g') << 8) | sal_uInt32('0'));
-
-}
-
 using namespace com::sun::star;
 
 class ImpSwapFile : public vcl::SwapFile
@@ -348,6 +334,7 @@ void ImpGraphic::createSwapInfo()
     if (isSwappedOut())
         return;
 
+    maSwapInfo.maSizePixel = ImplGetSizePixel();
     maSwapInfo.maPrefMapMode = ImplGetPrefMapMode();
     maSwapInfo.maPrefSize = ImplGetPrefSize();
     maSwapInfo.mbIsAnimated = ImplIsAnimated();
@@ -363,7 +350,6 @@ void ImpGraphic::ImplClearGraphics()
     maBitmapEx.Clear();
     maMetaFile.Clear();
     mpAnimation.reset();
-    mpGfxLink.reset();
     maVectorGraphicData.reset();
 }
 
@@ -1121,107 +1107,32 @@ bool ImpGraphic::swapInContent(SvStream& rStream)
 {
     bool bRet = false;
 
-    ensureAvailable();
-
-    MapMode aMapMode;
-    Size aSize;
     sal_uInt32 nId;
     sal_Int32 nType;
-    sal_Int32 nPageIndex = -1;
-    const SvStreamEndian nOldFormat = rStream.GetEndian();
+    sal_Int32 nLength;
 
-    rStream.SetEndian(SvStreamEndian::LITTLE);
     rStream.ReadUInt32(nId);
 
     // check version
-    if (GRAPHIC_FORMAT_50 != nId)
+    if (SWAP_FORMAT_ID != nId)
+    {
+        SAL_WARN("vcl", "Incompatible swap file!");
         return false;
-
-    // read new style header
-    VersionCompat aCompat(rStream, StreamMode::READ);
+    }
 
     rStream.ReadInt32(nType);
-    sal_Int32 nLen;
-    rStream.ReadInt32(nLen);
-    TypeSerializer aSerializer(rStream);
-    aSerializer.readSize(aSize);
-    ReadMapMode(rStream, aMapMode);
-
-    if (aCompat.GetVersion() >= 2)
-    {
-        rStream.ReadInt32(nPageIndex);
-    }
+    rStream.ReadInt32(nLength);
 
     meType = static_cast<GraphicType>(nType);
 
-    if( meType != GraphicType::NONE )
+    if (meType == GraphicType::NONE  || meType == GraphicType::Default)
     {
-        if( meType == GraphicType::Bitmap )
-        {
-            if(maVectorGraphicData && maBitmapEx.IsEmpty())
-            {
-                // use maBitmapEx as local buffer for rendered svg
-                maBitmapEx = getVectorGraphicReplacement();
-            }
-
-            maBitmapEx.SetSizePixel(aSize);
-
-            if( aMapMode != MapMode() )
-            {
-                maBitmapEx.SetPrefMapMode( aMapMode );
-                maBitmapEx.SetPrefSize( aSize );
-            }
-        }
-        else
-        {
-            maMetaFile.SetPrefMapMode( aMapMode );
-            maMetaFile.SetPrefSize( aSize );
-        }
-
-        if( meType == GraphicType::Bitmap || meType == GraphicType::GdiMetafile )
-        {
-            swapInGraphic(rStream);
-            bRet = rStream.GetError() == ERRCODE_NONE;
-        }
-        else if( sal::static_int_cast<sal_uLong>(meType) >= SYS_WINMETAFILE
-                 && sal::static_int_cast<sal_uLong>(meType) <= SYS_MACMETAFILE )
-        {
-            Graphic           aSysGraphic;
-            ConvertDataFormat nCvtType;
-
-            switch( sal::static_int_cast<sal_uLong>(meType) )
-            {
-                case SYS_WINMETAFILE:
-                case SYS_WNTMETAFILE: nCvtType = ConvertDataFormat::WMF; break;
-                case SYS_OS2METAFILE: nCvtType = ConvertDataFormat::MET; break;
-                case SYS_MACMETAFILE: nCvtType = ConvertDataFormat::PCT; break;
-
-                default:
-                    nCvtType = ConvertDataFormat::Unknown;
-                break;
-            }
-
-            if( nType && GraphicConverter::Import(rStream, aSysGraphic, nCvtType) == ERRCODE_NONE )
-            {
-                *this = ImpGraphic( aSysGraphic.GetGDIMetaFile() );
-                bRet = rStream.GetError() == ERRCODE_NONE;
-            }
-            else
-                meType = GraphicType::Default;
-        }
-
-        if (bRet)
-        {
-            ImplSetPrefMapMode( aMapMode );
-            ImplSetPrefSize( aSize );
-            if (maVectorGraphicData)
-                maVectorGraphicData->setPageIndex(nPageIndex);
-        }
+        return true;
     }
     else
-        bRet = true;
-
-    rStream.SetEndian(nOldFormat);
+    {
+        bRet = swapInGraphic(rStream);
+    }
 
     return bRet;
 }
@@ -1239,149 +1150,111 @@ bool ImpGraphic::swapOutGraphic(SvStream& rStream)
         return false;
     }
 
-    if (rStream.GetVersion() >= SOFFICE_FILEFORMAT_50 &&
-        rStream.GetCompressMode() & SvStreamCompressFlags::NATIVE &&
-        mpGfxLink && mpGfxLink->IsNative())
+    switch (meType)
     {
-        // native format
-        rStream.WriteUInt32(NATIVE_FORMAT_50);
-
-        // write compat info, destructor writes stuff into the header
+        case GraphicType::GdiMetafile:
         {
-            VersionCompat aCompat(rStream, StreamMode::WRITE, 1);
+            WriteGDIMetaFile(rStream, maMetaFile);
         }
-        mpGfxLink->SetPrefMapMode(ImplGetPrefMapMode());
-        mpGfxLink->SetPrefSize(ImplGetPrefSize());
-        TypeSerializer aSerializer(rStream);
-        aSerializer.writeGfxLink(*mpGfxLink);
-    }
-    else
-    {
-        switch (ImplGetType())
-        {
-            case GraphicType::NONE:
-            case GraphicType::Default:
-            break;
+        break;
 
-            case GraphicType::Bitmap:
+        case GraphicType::Bitmap:
+        {
+            if (maVectorGraphicData)
             {
-                if (getVectorGraphicData())
+                rStream.WriteInt32(sal_Int32(GraphicContentType::Vector));
+                // stream out Vector Graphic defining data (length, byte array and evtl. path)
+                // this is used e.g. in swapping out graphic data and in transporting it over UNO API
+                // as sequence of bytes, but AFAIK not written anywhere to any kind of file, so it should be
+                // no problem to extend it; only used at runtime
+                switch (maVectorGraphicData->getVectorGraphicDataType())
                 {
-                    // stream out Vector Graphic defining data (length, byte array and evtl. path)
-                    // this is used e.g. in swapping out graphic data and in transporting it over UNO API
-                    // as sequence of bytes, but AFAIK not written anywhere to any kind of file, so it should be
-                    // no problem to extend it; only used at runtime
-                    switch (getVectorGraphicData()->getVectorGraphicDataType())
+                    case VectorGraphicDataType::Wmf:
                     {
-                        case VectorGraphicDataType::Wmf:
-                        {
-                            rStream.WriteUInt32(constWmfMagic);
-                            break;
-                        }
-                        case VectorGraphicDataType::Emf:
-                        {
-                            rStream.WriteUInt32(constEmfMagic);
-                            break;
-                        }
-                        case VectorGraphicDataType::Svg:
-                        {
-                            rStream.WriteUInt32(constSvgMagic);
-                            break;
-                        }
-                        case VectorGraphicDataType::Pdf:
-                        {
-                            rStream.WriteUInt32(constPdfMagic);
-                            break;
-                        }
+                        rStream.WriteUInt32(constWmfMagic);
+                        break;
+                    }
+                    case VectorGraphicDataType::Emf:
+                    {
+                        rStream.WriteUInt32(constEmfMagic);
+                        break;
+                    }
+                    case VectorGraphicDataType::Svg:
+                    {
+                        rStream.WriteUInt32(constSvgMagic);
+                        break;
+                    }
+                    case VectorGraphicDataType::Pdf:
+                    {
+                        rStream.WriteUInt32(constPdfMagic);
+                        break;
                     }
-
-                    rStream.WriteUInt32(getVectorGraphicData()->getVectorGraphicDataArrayLength());
-                    rStream.WriteBytes(
-                        getVectorGraphicData()->getVectorGraphicDataArray().getConstArray(),
-                        getVectorGraphicData()->getVectorGraphicDataArrayLength());
-                    rStream.WriteUniOrByteString(getVectorGraphicData()->getPath(), rStream.GetStreamCharSet());
-                }
-                else if (ImplIsAnimated())
-                {
-                    WriteAnimation(rStream, *mpAnimation);
-                }
-                else
-                {
-                    WriteDIBBitmapEx(maBitmapEx, rStream);
                 }
-            }
-            break;
 
-            default:
+                rStream.WriteUInt32(maVectorGraphicData->getVectorGraphicDataArrayLength());
+
+                rStream.WriteBytes(
+                    maVectorGraphicData->getVectorGraphicDataArray().getConstArray(),
+                    maVectorGraphicData->getVectorGraphicDataArrayLength());
+
+                rStream.WriteUniOrByteString(maVectorGraphicData->getPath(), rStream.GetStreamCharSet());
+            }
+            else if (ImplIsAnimated())
             {
-                if (ImplIsSupportedGraphic())
-                    WriteGDIMetaFile(rStream, maMetaFile);
+                rStream.WriteInt32(sal_Int32(GraphicContentType::Animation));
+                WriteAnimation(rStream, *mpAnimation);
+            }
+            else
+            {
+                rStream.WriteInt32(sal_Int32(GraphicContentType::Bitmap));
+                WriteDIBBitmapEx(maBitmapEx, rStream);
             }
-            break;
         }
+        break;
+
+        case GraphicType::NONE:
+        case GraphicType::Default:
+            break;
     }
+
     return true;
 }
 
-bool ImpGraphic::swapOutContent(SvStream& rOStm)
+bool ImpGraphic::swapOutContent(SvStream& rStream)
 {
     ensureAvailable();
 
+    bool bRet = false;
+
     if (meType == GraphicType::NONE || meType == GraphicType::Default || isSwappedOut())
         return false;
 
-    const SvStreamEndian nOldFormat = rOStm.GetEndian();
-
-    const MapMode aMapMode = ImplGetPrefMapMode();
-    const Size aSize = ImplGetPrefSize();
     sal_uLong nDataFieldPos;
 
-    rOStm.SetEndian(SvStreamEndian::LITTLE);
+    // Write te SWAP ID
+    rStream.WriteUInt32(SWAP_FORMAT_ID);
 
-    // write ID for new format (5.0)
-    rOStm.WriteUInt32(GRAPHIC_FORMAT_50);
+    rStream.WriteInt32(static_cast<sal_Int32>(meType));
 
-    // write new style header
-    {
-        VersionCompat aCompat(rOStm, StreamMode::WRITE, 2);
-
-        rOStm.WriteInt32(static_cast<sal_Int32>(meType));
-
-        // data size is updated later
-        nDataFieldPos = rOStm.Tell();
-        rOStm.WriteInt32(0);
-
-        TypeSerializer aSerializer(rOStm);
-        aSerializer.writeSize(aSize);
-
-        WriteMapMode(rOStm, aMapMode);
-
-        // Version 2
-        rOStm.WriteInt32(getPageNumber());
-    }
-
-    bool bRet = false;
+    // data size is updated later
+    nDataFieldPos = rStream.Tell();
+    rStream.WriteInt32(0);
 
     // write data block
-    if (!rOStm.GetError())
-    {
-        const sal_uLong nDataStart = rOStm.Tell();
+    const sal_uLong nDataStart = rStream.Tell();
 
-        if (ImplIsSupportedGraphic())
-            swapOutGraphic(rOStm);
+    swapOutGraphic(rStream);
 
-        if( !rOStm.GetError() )
-        {
-            const sal_uLong nStmPos2 = rOStm.Tell();
-            rOStm.Seek( nDataFieldPos );
-            rOStm.WriteInt32( nStmPos2 - nDataStart );
-            rOStm.Seek( nStmPos2 );
-            bRet = true;
-        }
+    if (!rStream.GetError())
+    {
+        // Write the written length th the header
+        const sal_uLong nCurrentPosition = rStream.Tell();
+        rStream.Seek(nDataFieldPos);
+        rStream.WriteInt32(nCurrentPosition - nDataStart);
+        rStream.Seek(nCurrentPosition);
+        bRet = true;
     }
 
-    rOStm.SetEndian(nOldFormat);
-
     return bRet;
 }
 
@@ -1390,46 +1263,67 @@ bool ImpGraphic::swapOut()
     if (isSwappedOut())
         return false;
 
-    // Create a temp filename for the swap file
-    utl::TempFile aTempFile;
-    const INetURLObject aTempFileURL(aTempFile.GetURL());
-
-    // Create a swap file
-    auto pSwapFile = o3tl::make_shared<ImpSwapFile>(aTempFileURL, getOriginURL());
-
     bool bResult = false;
 
-    // Open a stream to write the swap file to
+    // We have GfxLink so we have the source available
+    if (mpGfxLink && mpGfxLink->IsNative())
     {
-        std::unique_ptr<SvStream> xOutputStream = pSwapFile->openOutputStream();
+        createSwapInfo();
 
-        if (!xOutputStream)
-            return false;
+        ImplClearGraphics();
+
+        // reset the swap file
+        mpSwapFile.reset();
+
+        // mark as swapped out
+        mbSwapOut = true;
 
-        // Write to stream
-        xOutputStream->SetVersion(SOFFICE_FILEFORMAT_50);
-        xOutputStream->SetCompressMode(SvStreamCompressFlags::NATIVE);
-        xOutputStream->SetBufferSize(GRAPHIC_STREAMBUFSIZE);
+        // Signal to manager that we have swapped out
+        vcl::graphic::Manager::get().swappedOut(this);
+
+        bResult = true;
+    }
+    else
+    {
+        // Create a temp filename for the swap file
+        utl::TempFile aTempFile;
+        const INetURLObject aTempFileURL(aTempFile.GetURL());
+
+        // Create a swap file
+        auto pSwapFile = o3tl::make_shared<ImpSwapFile>(aTempFileURL, getOriginURL());
 
-        if (!xOutputStream->GetError() && swapOutContent(*xOutputStream))
+        // Open a stream to write the swap file to
         {
-            xOutputStream->Flush();
-            bResult = !xOutputStream->GetError();
+            std::unique_ptr<SvStream> xOutputStream = pSwapFile->openOutputStream();
+
+            if (!xOutputStream)
+                return false;
+
+            // Write to stream
+            xOutputStream->SetVersion(SOFFICE_FILEFORMAT_50);
+            xOutputStream->SetCompressMode(SvStreamCompressFlags::NATIVE);
+            xOutputStream->SetBufferSize(GRAPHIC_STREAMBUFSIZE);
+
+            if (!xOutputStream->GetError() && swapOutContent(*xOutputStream))
+            {
+                xOutputStream->Flush();
+                bResult = !xOutputStream->GetError();
+            }
         }
-    }
 
-    // Check if writing was successful
-    if (bResult)
-    {
-        // We have swapped out, so can clean memory and prepare swap info
-        createSwapInfo();
-        ImplClearGraphics();
+        // Check if writing was successful
+        if (bResult)
+        {
+            // We have swapped out, so can clean memory and prepare swap info
+            createSwapInfo();
+            ImplClearGraphics();
 
-        mpSwapFile = std::move(pSwapFile);
-        mbSwapOut = true;
+            mpSwapFile = std::move(pSwapFile);
+            mbSwapOut = true;
 
-        // Signal to manager that we have swapped out
-        vcl::graphic::Manager::get().swappedOut(this);
+            // Signal to manager that we have swapped out
+            vcl::graphic::Manager::get().swappedOut(this);
+        }
     }
 
     return bResult;
@@ -1439,11 +1333,13 @@ bool ImpGraphic::ensureAvailable() const
 {
     auto pThis = const_cast<ImpGraphic*>(this);
 
+    bool bResult = true;
+
     if (isSwappedOut())
-        return pThis->swapIn();
+        bResult = pThis->swapIn();
 
     pThis->maLastUsed = std::chrono::high_resolution_clock::now();
-    return true;
+    return bResult;
 }
 
 bool ImpGraphic::loadPrepared()
@@ -1470,30 +1366,95 @@ void ImpGraphic::updateFromLoadedGraphic(ImpGraphic* graphic)
     maGraphicExternalLink = aLink;
 }
 
-bool ImpGraphic::swapIn()
+void ImpGraphic::restoreFromSwapInfo()
 {
-    bool bRet = false;
+    // Reset the parameters
+    if (!maBitmapEx.IsEmpty())
+    {
+        maBitmapEx.SetPrefMapMode(maSwapInfo.maPrefMapMode);
+        maBitmapEx.SetPrefSize(maSwapInfo.maPrefSize);
+    }
+
+    if (meType == GraphicType::GdiMetafile)
+    {
+         maMetaFile.SetPrefMapMode(maSwapInfo.maPrefMapMode);
+         maMetaFile.SetPrefSize(maSwapInfo.maPrefSize);
+    }
 
+    if (ImplIsAnimated())
+    {
+        auto & rAnimationBitmap = const_cast<BitmapEx&>(mpAnimation->GetBitmapEx());
+        rAnimationBitmap.SetPrefMapMode(maSwapInfo.maPrefMapMode);
+        rAnimationBitmap.SetPrefSize(maSwapInfo.maPrefSize);
+    }
+
+    if (maVectorGraphicData)
+    {
+        maExPrefSize = maSwapInfo.maPrefSize;
+        maVectorGraphicData->setPageIndex(maSwapInfo.mnPageIndex);
+    }
+}
+
+bool ImpGraphic::swapIn()
+{
     if (!isSwappedOut())
-        return bRet;
+        return false;
+
+    bool bReturn = false;
 
     if (mbPrepared)
     {
-        bRet = loadPrepared();
+        bReturn = loadPrepared();
+    }
+    else if (mpGfxLink && mpGfxLink->IsNative())
+    {
+        Graphic aGraphic;
+        if (!mpGfxLink->LoadNative(aGraphic))
+            return false;
+
+        auto & rImpGraphic = *aGraphic.ImplGetImpGraphic();
+
+        if (meType != rImpGraphic.meType)
+            return false;
+
+        // Move over only graphic content
+        mpAnimation.reset();
+        if (rImpGraphic.mpAnimation)
+        {
+            mpAnimation = std::make_unique<Animation>(*rImpGraphic.mpAnimation);
+            maBitmapEx = mpAnimation->GetBitmapEx();
+        }
+        else
+        {
+            maBitmapEx = rImpGraphic.maBitmapEx;
+        }
+
+        maMetaFile = rImpGraphic.maMetaFile;
+        maVectorGraphicData = rImpGraphic.maVectorGraphicData;
+
+        // Set to 0, to force recalculation
+        mnSizeBytes = 0;
+        mnChecksum = 0;
+
+        restoreFromSwapInfo();
+
+        maLastUsed = std::chrono::high_resolution_clock::now();
+        mbSwapOut = false;
+        bReturn = true;
     }
     else
     {
         OUString aSwapURL;
 
-        if( mpSwapFile )
-            aSwapURL = mpSwapFile->getSwapURL().GetMainURL( INetURLObject::DecodeMechanism::NONE );
+        if (mpSwapFile)
+            aSwapURL = mpSwapFile->getSwapURL().GetMainURL(INetURLObject::DecodeMechanism::NONE);
 
-        if( !aSwapURL.isEmpty() )
+        if (!aSwapURL.isEmpty())
         {
             std::unique_ptr<SvStream> xStream;
             try
             {
-                xStream = ::utl::UcbStreamHelper::CreateStream( aSwapURL, StreamMode::READWRITE | StreamMode::SHARE_DENYWRITE );
+                xStream = ::utl::UcbStreamHelper::CreateStream(aSwapURL, StreamMode::READWRITE | StreamMode::SHARE_DENYWRITE);
             }
             catch( const css::uno::Exception& )
             {
@@ -1501,51 +1462,43 @@ bool ImpGraphic::swapIn()
 
             if (xStream)
             {
-                xStream->SetVersion( SOFFICE_FILEFORMAT_50 );
-                xStream->SetCompressMode( SvStreamCompressFlags::NATIVE );
+                xStream->SetVersion(SOFFICE_FILEFORMAT_50);
+                xStream->SetCompressMode(SvStreamCompressFlags::NATIVE);
+                xStream->SetBufferSize(GRAPHIC_STREAMBUFSIZE);
+
+                bReturn = swapInFromStream(*xStream);
 
-                bRet = swapInFromStream(*xStream);
                 xStream.reset();
+
+                restoreFromSwapInfo();
+
                 if (mpSwapFile)
                     setOriginURL(mpSwapFile->getOriginURL());
+
                 mpSwapFile.reset();
             }
         }
     }
 
-    if (bRet)
+    if (bReturn)
         vcl::graphic::Manager::get().swappedIn(this);
 
-    return bRet;
+    return bReturn;
 }
 
 bool ImpGraphic::swapInFromStream(SvStream& rStream)
 {
     bool bRet = false;
 
-    rStream.SetBufferSize(GRAPHIC_STREAMBUFSIZE);
-
     if (rStream.GetError())
         return false;
 
-    //keep the swap file alive, because its quite possibly the backing storage
-    //for xIStm
-    std::shared_ptr<ImpSwapFile> xSwapFile(std::move(mpSwapFile));
-    assert(!mpSwapFile);
-
-    std::shared_ptr<GraphicReader> xContext(std::move(mpContext));
-    assert(!mpContext);
-
-    bool bDummyContext = mbDummyContext;
-    mbDummyContext = false;
+    ImplClearGraphics();
+    mnSizeBytes = 0;
+    mnChecksum = 0;
 
     bRet = swapInContent(rStream);
 
-    //restore ownership of the swap file and context
-    mpSwapFile = std::move(xSwapFile);
-    mpContext = std::move(xContext);
-    mbDummyContext = bDummyContext;
-
     if (!bRet)
     {
         //throw away swapfile, etc.
@@ -1557,165 +1510,116 @@ bool ImpGraphic::swapInFromStream(SvStream& rStream)
     return bRet;
 }
 
-void ImpGraphic::swapInGraphic(SvStream& rStream)
+bool ImpGraphic::swapInGraphic(SvStream& rStream)
 {
-    if (rStream.GetError())
-        return;
-
-    const sal_uLong nStmPos1 = rStream.Tell();
-    sal_uInt32 nID;
+    bool bReturn = false;
 
-    ImplClear();
-
-    // read Id
-    rStream.ReadUInt32(nID);
-
-    // if there is no more data, avoid further expensive
-    // reading which will create VDevs and other stuff, just to
-    // read nothing. CAUTION: Eof is only true AFTER reading another
-    // byte, a speciality of SvMemoryStream (!)
-    if (!rStream.good())
-        return;
+    if (rStream.GetError())
+        return bReturn;
 
-    if (NATIVE_FORMAT_50 == nID)
+    if (meType == GraphicType::Bitmap)
     {
-        Graphic aGraphic;
-        GfxLink aLink;
-
-        // read compat info, destructor writes stuff into the header
-        {
-            VersionCompat aCompat(rStream, StreamMode::READ);
-        }
-
-        TypeSerializer aSerializer(rStream);
-        aSerializer.readGfxLink(aLink);
+        sal_Int32 nContentType = -1;
+        rStream.ReadInt32(nContentType);
+        if (nContentType < 0)
+            return false;
 
-        // set dummy link to avoid creation of additional link after filtering;
-        // we set a default link to avoid unnecessary swapping of native data
-        aGraphic.SetGfxLink(std::make_shared<GfxLink>());
+        auto eContentType = static_cast<GraphicContentType>(nContentType);
 
-        if (!rStream.GetError() && aLink.LoadNative(aGraphic))
+        switch (eContentType)
         {
-            // set link only, if no other link was set
-            const bool bSetLink = !mpGfxLink;
+            case GraphicContentType::Bitmap:
+            {
+                BitmapEx aBitmapEx;
+                ReadDIBBitmapEx(aBitmapEx, rStream);
+                if (!rStream.GetError())
+                {
+                    maBitmapEx = aBitmapEx;
+                    bReturn = true;
+                }
+            }
+            break;
 
-            // assign graphic
-            *this = *aGraphic.ImplGetImpGraphic();
+            case GraphicContentType::Animation:
+            {
+                auto pAnimation = std::make_unique<Animation>();
+                ReadAnimation(rStream, *pAnimation);
+                if (!rStream.GetError())
+                {
+                    mpAnimation = std::move(pAnimation);
+                    maBitmapEx = mpAnimation->GetBitmapEx();
+                    bReturn = true;
+                }
+            }
+            break;
 
-            if (aLink.IsPrefMapModeValid())
-                ImplSetPrefMapMode(aLink.GetPrefMapMode());
+            case GraphicContentType::Vector:
+            {
+                // try to stream in Svg defining data (length, byte array and evtl. path)
+                // See below (operator<<) for more information
+                sal_uInt32 nMagic;
+                rStream.ReadUInt32(nMagic);
 
-            if (aLink.IsPrefSizeValid())
-                ImplSetPrefSize(aLink.GetPrefSize());
+                if (constSvgMagic == nMagic || constWmfMagic == nMagic || constEmfMagic == nMagic || constPdfMagic == nMagic)
+                {
+                    sal_uInt32 nVectorGraphicDataArrayLength(0);
+                    rStream.ReadUInt32(nVectorGraphicDataArrayLength);
 
-            if (bSetLink)
-                ImplSetLink(std::make_shared<GfxLink>(aLink));
-        }
-        else
-        {
-            rStream.Seek(nStmPos1);
-            rStream.SetError(ERRCODE_IO_WRONGFORMAT);
-        }
-        return;
-    }
+                    if (nVectorGraphicDataArrayLength)
+                    {
+                        VectorGraphicDataArray aNewData(nVectorGraphicDataArrayLength);
 
-    BitmapEx aBmpEx;
-    const SvStreamEndian nOldFormat = rStream.GetEndian();
+                        rStream.ReadBytes(aNewData.getArray(), nVectorGraphicDataArrayLength);
 
-    rStream.SeekRel(-4);
-    rStream.SetEndian(SvStreamEndian::LITTLE);
-    ReadDIBBitmapEx(aBmpEx, rStream);
+                        OUString aPath = rStream.ReadUniOrByteString(rStream.GetStreamCharSet());
 
-    if (!rStream.GetError())
-    {
-        sal_uInt32 nMagic1(0);
-        sal_uInt32 nMagic2(0);
-        sal_uLong nActPos = rStream.Tell();
+                        if (rStream.GetError())
+                            return false;
 
-        rStream.ReadUInt32(nMagic1);
-        rStream.ReadUInt32(nMagic2);
-        rStream.Seek(nActPos);
+                        VectorGraphicDataType aDataType;
 
-        *this = ImpGraphic(aBmpEx);
+                        switch (nMagic)
+                        {
+                            case constSvgMagic:
+                                aDataType = VectorGraphicDataType::Svg;
+                                break;
+                            case constWmfMagic:
+                                aDataType = VectorGraphicDataType::Wmf;
+                                break;
+                            case constEmfMagic:
+                                aDataType = VectorGraphicDataType::Emf;
+                                break;
+                            case constPdfMagic:
+                                aDataType = VectorGraphicDataType::Pdf;
+                                break;
+                            default:
+                                return false;
+                        }
 
-        if (!rStream.GetError() && (0x5344414e == nMagic1) && (0x494d4931 == nMagic2))
-        {
-            mpAnimation = std::make_unique<Animation>();
-            ReadAnimation(rStream, *mpAnimation);
+                        auto aVectorGraphicDataPtr = std::make_shared<VectorGraphicData>(aNewData, aPath, aDataType);
 
-            // #108077# manually set loaded BmpEx to Animation
-            // (which skips loading its BmpEx if already done)
-            mpAnimation->SetBitmapEx(aBmpEx);
+                        if (!rStream.GetError())
+                        {
+                            maVectorGraphicData = aVectorGraphicDataPtr;
+                            bReturn = true;
+                        }
+                    }
+                }
+            }
+            break;
         }
-        else
-            rStream.ResetError();
     }
-    else
+    else if (meType == GraphicType::GdiMetafile)
     {
         GDIMetaFile aMetaFile;
-
-        rStream.Seek(nStmPos1);
-        rStream.ResetError();
         ReadGDIMetaFile(rStream, aMetaFile);
-
         if (!rStream.GetError())
         {
-            *this = aMetaFile;
-        }
-        else
-        {
-            ErrCode nOrigError = rStream.GetErrorCode();
-            // try to stream in Svg defining data (length, byte array and evtl. path)
-            // See below (operator<<) for more information
-            sal_uInt32 nMagic;
-            rStream.Seek(nStmPos1);
-            rStream.ResetError();
-            rStream.ReadUInt32( nMagic );
-
-            if (constSvgMagic == nMagic || constWmfMagic == nMagic || constEmfMagic == nMagic || constPdfMagic == nMagic)
-            {
-                sal_uInt32 nVectorGraphicDataArrayLength(0);
-                rStream.ReadUInt32(nVectorGraphicDataArrayLength);
-
-                if (nVectorGraphicDataArrayLength)
-                {
-                    VectorGraphicDataArray aNewData(nVectorGraphicDataArrayLength);
-
-                    rStream.ReadBytes(aNewData.getArray(), nVectorGraphicDataArrayLength);
-                    OUString aPath = rStream.ReadUniOrByteString(rStream.GetStreamCharSet());
-
-                    if (!rStream.GetError())
-                    {
-                        VectorGraphicDataType aDataType(VectorGraphicDataType::Svg);
-
-                        if (constWmfMagic == nMagic)
-                        {
-                            aDataType = VectorGraphicDataType::Wmf;
-                        }
-                        else if (constEmfMagic == nMagic)
-                        {
-                            aDataType = VectorGraphicDataType::Emf;
-                        }
-                        else if (constPdfMagic == nMagic)
-                        {
-                            aDataType = VectorGraphicDataType::Pdf;
-                        }
-
-                        auto aVectorGraphicDataPtr = std::make_shared<VectorGraphicData>(aNewData, aPath, aDataType);
-                        *this = ImpGraphic(aVectorGraphicDataPtr);
-                    }
-                }
-            }
-            else
-            {
-                rStream.SetError(nOrigError);
-            }
-
-            rStream.Seek(nStmPos1);
+            maMetaFile = aMetaFile;
+            bReturn = true;
         }
     }
-
-    rStream.SetEndian(nOldFormat);
+    return bReturn;
 }
 
 void ImpGraphic::ImplSetLink(const std::shared_ptr<GfxLink>& rGfxLink)


More information about the Libreoffice-commits mailing list