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(char3) << 8) | (static_cast(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 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,28 +534,192 @@ 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 + 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(true, aGraphic.isAvailable()); - CPPUNIT_ASSERT_EQUAL(sal_uInt32(223), aGraphic.GetGfxLink().GetDataSize()); - CPPUNIT_ASSERT_EQUAL(true, aGraphic.isAvailable()); + + CPPUNIT_ASSERT_EQUAL(false, aGraphic.IsGfxLink()); BitmapChecksum aBitmapChecksumBeforeSwapping = aGraphic.GetBitmapEx().GetChecksum(); @@ -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 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 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 xStream = createStream(rSwapFileURL); + CPPUNIT_ASSERT_EQUAL(true, bool(xStream)); + + // Check size of the stream + CPPUNIT_ASSERT_EQUAL(sal_uInt64(15183), xStream->remainingSize()); + + std::vector 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(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(meType) >= SYS_WINMETAFILE - && sal::static_int_cast(meType) <= SYS_MACMETAFILE ) - { - Graphic aSysGraphic; - ConvertDataFormat nCvtType; - - switch( sal::static_int_cast(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); - } + rStream.WriteUInt32(maVectorGraphicData->getVectorGraphicDataArrayLength()); + + rStream.WriteBytes( + maVectorGraphicData->getVectorGraphicDataArray().getConstArray(), + maVectorGraphicData->getVectorGraphicDataArrayLength()); + + rStream.WriteUniOrByteString(maVectorGraphicData->getPath(), rStream.GetStreamCharSet()); } - break; - - default: + 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(meType)); - // write new style header - { - VersionCompat aCompat(rOStm, StreamMode::WRITE, 2); - - rOStm.WriteInt32(static_cast(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 = rStream.Tell(); + + swapOutGraphic(rStream); + + if (!rStream.GetError()) { - const sal_uLong nDataStart = rOStm.Tell(); - - if (ImplIsSupportedGraphic()) - swapOutGraphic(rOStm); - - if( !rOStm.GetError() ) - { - const sal_uLong nStmPos2 = rOStm.Tell(); - rOStm.Seek( nDataFieldPos ); - rOStm.WriteInt32( nStmPos2 - nDataStart ); - rOStm.Seek( nStmPos2 ); - bRet = true; - } + // 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(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 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(); - mpSwapFile = std::move(pSwapFile); + // reset the swap file + mpSwapFile.reset(); + + // mark as swapped out mbSwapOut = true; // 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(aTempFileURL, getOriginURL()); + + // Open a stream to write the swap file to + { + std::unique_ptr 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(); + + mpSwapFile = std::move(pSwapFile); + mbSwapOut = true; + + // 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(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; } +void ImpGraphic::restoreFromSwapInfo() +{ + // 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(mpAnimation->GetBitmapEx()); + rAnimationBitmap.SetPrefMapMode(maSwapInfo.maPrefMapMode); + rAnimationBitmap.SetPrefSize(maSwapInfo.maPrefSize); + } + + if (maVectorGraphicData) + { + maExPrefSize = maSwapInfo.maPrefSize; + maVectorGraphicData->setPageIndex(maSwapInfo.mnPageIndex); + } +} + bool ImpGraphic::swapIn() { - bool bRet = false; - 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(*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 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 xSwapFile(std::move(mpSwapFile)); - assert(!mpSwapFile); - - std::shared_ptr 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) { + bool bReturn = false; + if (rStream.GetError()) - return; + return bReturn; - const sal_uLong nStmPos1 = rStream.Tell(); - sal_uInt32 nID; - - 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 (NATIVE_FORMAT_50 == nID) + if (meType == GraphicType::Bitmap) { - Graphic aGraphic; - GfxLink aLink; + sal_Int32 nContentType = -1; + rStream.ReadInt32(nContentType); + if (nContentType < 0) + return false; - // read compat info, destructor writes stuff into the header + auto eContentType = static_cast(nContentType); + + switch (eContentType) { - VersionCompat aCompat(rStream, StreamMode::READ); - } - - TypeSerializer aSerializer(rStream); - aSerializer.readGfxLink(aLink); - - // 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()); - - if (!rStream.GetError() && aLink.LoadNative(aGraphic)) - { - // set link only, if no other link was set - const bool bSetLink = !mpGfxLink; - - // assign graphic - *this = *aGraphic.ImplGetImpGraphic(); - - if (aLink.IsPrefMapModeValid()) - ImplSetPrefMapMode(aLink.GetPrefMapMode()); - - if (aLink.IsPrefSizeValid()) - ImplSetPrefSize(aLink.GetPrefSize()); - - if (bSetLink) - ImplSetLink(std::make_shared(aLink)); - } - else - { - rStream.Seek(nStmPos1); - rStream.SetError(ERRCODE_IO_WRONGFORMAT); - } - return; - } - - BitmapEx aBmpEx; - const SvStreamEndian nOldFormat = rStream.GetEndian(); - - rStream.SeekRel(-4); - rStream.SetEndian(SvStreamEndian::LITTLE); - ReadDIBBitmapEx(aBmpEx, rStream); - - if (!rStream.GetError()) - { - sal_uInt32 nMagic1(0); - sal_uInt32 nMagic2(0); - sal_uLong nActPos = rStream.Tell(); - - rStream.ReadUInt32(nMagic1); - rStream.ReadUInt32(nMagic2); - rStream.Seek(nActPos); - - *this = ImpGraphic(aBmpEx); - - if (!rStream.GetError() && (0x5344414e == nMagic1) && (0x494d4931 == nMagic2)) - { - mpAnimation = std::make_unique(); - ReadAnimation(rStream, *mpAnimation); - - // #108077# manually set loaded BmpEx to Animation - // (which skips loading its BmpEx if already done) - mpAnimation->SetBitmapEx(aBmpEx); - } - else - rStream.ResetError(); - } - else - { - 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) + case GraphicContentType::Bitmap: { - sal_uInt32 nVectorGraphicDataArrayLength(0); - rStream.ReadUInt32(nVectorGraphicDataArrayLength); - - if (nVectorGraphicDataArrayLength) + BitmapEx aBitmapEx; + ReadDIBBitmapEx(aBitmapEx, rStream); + if (!rStream.GetError()) { - VectorGraphicDataArray aNewData(nVectorGraphicDataArrayLength); + maBitmapEx = aBitmapEx; + bReturn = true; + } + } + break; - rStream.ReadBytes(aNewData.getArray(), nVectorGraphicDataArrayLength); - OUString aPath = rStream.ReadUniOrByteString(rStream.GetStreamCharSet()); + case GraphicContentType::Animation: + { + auto pAnimation = std::make_unique(); + ReadAnimation(rStream, *pAnimation); + if (!rStream.GetError()) + { + mpAnimation = std::move(pAnimation); + maBitmapEx = mpAnimation->GetBitmapEx(); + bReturn = true; + } + } + break; - if (!rStream.GetError()) + 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 (constSvgMagic == nMagic || constWmfMagic == nMagic || constEmfMagic == nMagic || constPdfMagic == nMagic) + { + sal_uInt32 nVectorGraphicDataArrayLength(0); + rStream.ReadUInt32(nVectorGraphicDataArrayLength); + + if (nVectorGraphicDataArrayLength) { - VectorGraphicDataType aDataType(VectorGraphicDataType::Svg); + VectorGraphicDataArray aNewData(nVectorGraphicDataArrayLength); - if (constWmfMagic == nMagic) + rStream.ReadBytes(aNewData.getArray(), nVectorGraphicDataArrayLength); + + OUString aPath = rStream.ReadUniOrByteString(rStream.GetStreamCharSet()); + + if (rStream.GetError()) + return false; + + VectorGraphicDataType aDataType; + + switch (nMagic) { - aDataType = VectorGraphicDataType::Wmf; - } - else if (constEmfMagic == nMagic) - { - aDataType = VectorGraphicDataType::Emf; - } - else if (constPdfMagic == nMagic) - { - aDataType = VectorGraphicDataType::Pdf; + 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; } auto aVectorGraphicDataPtr = std::make_shared(aNewData, aPath, aDataType); - *this = ImpGraphic(aVectorGraphicDataPtr); + + if (!rStream.GetError()) + { + maVectorGraphicData = aVectorGraphicDataPtr; + bReturn = true; + } } } } - else - { - rStream.SetError(nOrigError); - } - - rStream.Seek(nStmPos1); + break; } } - - rStream.SetEndian(nOldFormat); + else if (meType == GraphicType::GdiMetafile) + { + GDIMetaFile aMetaFile; + ReadGDIMetaFile(rStream, aMetaFile); + if (!rStream.GetError()) + { + maMetaFile = aMetaFile; + bReturn = true; + } + } + return bReturn; } void ImpGraphic::ImplSetLink(const std::shared_ptr& rGfxLink)