From ed5640d8b587fbcfed7dd7967f3de04b37a76f26 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 11:06:44 +0200 Subject: Adding upstream version 4:7.4.7. Signed-off-by: Daniel Baumann --- vcl/qa/cppunit/GraphicTest.cxx | 1385 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1385 insertions(+) create mode 100644 vcl/qa/cppunit/GraphicTest.cxx (limited to 'vcl/qa/cppunit/GraphicTest.cxx') diff --git a/vcl/qa/cppunit/GraphicTest.cxx b/vcl/qa/cppunit/GraphicTest.cxx new file mode 100644 index 000000000..1d6d49891 --- /dev/null +++ b/vcl/qa/cppunit/GraphicTest.cxx @@ -0,0 +1,1385 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#if USE_TLS_NSS +#include +#endif + +using namespace css; + +namespace +{ +class GraphicTest : public test::BootstrapFixture +{ +public: + ~GraphicTest(); + +private: + void testUnloadedGraphic(); + void testUnloadedGraphicLoading(); + void testUnloadedGraphicWmf(); + void testUnloadedGraphicAlpha(); + void testUnloadedGraphicSizeUnit(); + + void testWMFRoundtrip(); + void testWMFWithEmfPlusRoundtrip(); + 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(); + + void testLoadMET(); + void testLoadBMP(); + void testLoadPSD(); + void testLoadTGA(); + void testLoadXBM(); + void testLoadXPM(); + void testLoadPCX(); + void testLoadEPS(); + void testLoadWEBP(); + + void testAvailableThreaded(); + void testColorChangeToTransparent(); + + CPPUNIT_TEST_SUITE(GraphicTest); + CPPUNIT_TEST(testUnloadedGraphic); + CPPUNIT_TEST(testUnloadedGraphicLoading); + CPPUNIT_TEST(testUnloadedGraphicWmf); + CPPUNIT_TEST(testUnloadedGraphicAlpha); + CPPUNIT_TEST(testUnloadedGraphicSizeUnit); + CPPUNIT_TEST(testWMFRoundtrip); + CPPUNIT_TEST(testWMFWithEmfPlusRoundtrip); + 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(testLoadMET); + CPPUNIT_TEST(testLoadBMP); + CPPUNIT_TEST(testLoadPSD); + CPPUNIT_TEST(testLoadTGA); + CPPUNIT_TEST(testLoadXBM); + CPPUNIT_TEST(testLoadXPM); + CPPUNIT_TEST(testLoadPCX); + CPPUNIT_TEST(testLoadEPS); + CPPUNIT_TEST(testLoadWEBP); + + CPPUNIT_TEST(testAvailableThreaded); + CPPUNIT_TEST(testColorChangeToTransparent); + + CPPUNIT_TEST_SUITE_END(); +}; + +GraphicTest::~GraphicTest() +{ +#if USE_TLS_NSS + NSS_Shutdown(); +#endif +} + +BitmapEx createBitmap(bool alpha = false) +{ + Bitmap aBitmap(Size(120, 100), vcl::PixelFormat::N24_BPP); + aBitmap.Erase(COL_LIGHTRED); + + aBitmap.SetPrefSize(Size(6000, 5000)); + aBitmap.SetPrefMapMode(MapMode(MapUnit::Map100thMM)); + + if (alpha) + { + sal_uInt8 uAlphaValue = 0x80; + AlphaMask aAlphaMask(Size(120, 100), &uAlphaValue); + + return BitmapEx(aBitmap, aAlphaMask); + } + else + { + return BitmapEx(aBitmap); + } +} + +void createBitmapAndExportForType(SvStream& rStream, std::u16string_view sType, bool alpha) +{ + BitmapEx aBitmapEx = createBitmap(alpha); + + uno::Sequence aFilterData; + GraphicFilter& rGraphicFilter = GraphicFilter::GetGraphicFilter(); + sal_uInt16 nFilterFormat = rGraphicFilter.GetExportFormatNumberForShortName(sType); + rGraphicFilter.ExportGraphic(aBitmapEx, u"none", rStream, nFilterFormat, &aFilterData); + + rStream.Seek(STREAM_SEEK_TO_BEGIN); +} + +Graphic makeUnloadedGraphic(std::u16string_view sType, bool alpha = false) +{ + SvMemoryStream aStream; + GraphicFilter& rGraphicFilter = GraphicFilter::GetGraphicFilter(); + createBitmapAndExportForType(aStream, sType, alpha); + return rGraphicFilter.ImportUnloadedGraphic(aStream); +} + +std::string toHexString(const std::vector& a) +{ + std::stringstream aStrm; + for (auto& i : a) + { + aStrm << std::setw(2) << std::setfill('0') << std::hex << static_cast(i); + } + + return aStrm.str(); +} + +std::unique_ptr createStream(OUString const& rSwapFileURL) +{ + std::unique_ptr xStream; + + try + { + xStream = ::utl::UcbStreamHelper::CreateStream( + rSwapFileURL, StreamMode::READWRITE | StreamMode::SHARE_DENYWRITE); + } + catch (const css::uno::Exception&) + { + } + + return xStream; +} + +std::vector calculateHash(std::unique_ptr& rStream) +{ + comphelper::Hash aHashEngine(comphelper::HashType::SHA1); + const sal_uInt32 nSize(rStream->remainingSize()); + std::vector aData(nSize); + aHashEngine.update(aData.data(), nSize); + return aHashEngine.finalize(); +} + +bool checkBitmap(Graphic& rGraphic) +{ + bool bResult = true; + + Bitmap aBitmap(rGraphic.GetBitmapEx().GetBitmap()); + { + Bitmap::ScopedReadAccess pReadAccess(aBitmap); + for (tools::Long y = 0; y < rGraphic.GetSizePixel().Height(); y++) + { + for (tools::Long x = 0; x < rGraphic.GetSizePixel().Width(); x++) + { + if (pReadAccess->HasPalette()) + { + sal_uInt32 nIndex = pReadAccess->GetPixelIndex(y, x); + Color aColor = pReadAccess->GetPaletteColor(nIndex); + bResult &= (aColor == Color(0xff, 0x00, 0x00)); + } + else + { + Color aColor = pReadAccess->GetPixel(y, x); + bResult &= (aColor == Color(0xff, 0x00, 0x00)); + } + } + } + } + + return bResult; +} + +constexpr OUStringLiteral DATA_DIRECTORY = u"/vcl/qa/cppunit/data/"; +constexpr OUStringLiteral PDFEXPORT_DATA_DIRECTORY = u"/vcl/qa/cppunit/pdfexport/data/"; + +Graphic loadGraphic(std::u16string_view const& rFilename) +{ + test::Directories aDirectories; + OUString aFilename = aDirectories.getURLFromSrc(DATA_DIRECTORY) + rFilename; + SvFileStream aFileStream(aFilename, StreamMode::READ); + GraphicFilter& rGraphicFilter = GraphicFilter::GetGraphicFilter(); + + Graphic aGraphic; + CPPUNIT_ASSERT_EQUAL(ERRCODE_NONE, rGraphicFilter.ImportGraphic(aGraphic, u"", aFileStream, + GRFILTER_FORMAT_DONTKNOW)); + return aGraphic; +} + +Graphic importUnloadedGraphic(std::u16string_view const& rFilename) +{ + test::Directories aDirectories; + OUString aFilename = aDirectories.getURLFromSrc(DATA_DIRECTORY) + rFilename; + SvFileStream aFileStream(aFilename, StreamMode::READ); + GraphicFilter& rGraphicFilter = GraphicFilter::GetGraphicFilter(); + return rGraphicFilter.ImportUnloadedGraphic(aFileStream); +} + +void GraphicTest::testUnloadedGraphic() +{ + // make unloaded test graphic + Graphic aGraphic = makeUnloadedGraphic(u"png"); + Graphic aGraphic2 = aGraphic; + + // check available + CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable()); + CPPUNIT_ASSERT_EQUAL(false, aGraphic2.isAvailable()); + + CPPUNIT_ASSERT_EQUAL(true, aGraphic2.makeAvailable()); + CPPUNIT_ASSERT_EQUAL(true, aGraphic.isAvailable()); + CPPUNIT_ASSERT_EQUAL(true, aGraphic2.isAvailable()); + + // check GetSizePixel doesn't load graphic + aGraphic = makeUnloadedGraphic(u"png"); + CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable()); + CPPUNIT_ASSERT_EQUAL(tools::Long(120), aGraphic.GetSizePixel().Width()); + CPPUNIT_ASSERT_EQUAL(tools::Long(100), aGraphic.GetSizePixel().Height()); + CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable()); + + // check GetPrefSize doesn't load graphic + CPPUNIT_ASSERT_EQUAL(tools::Long(6000), aGraphic.GetPrefSize().Width()); + CPPUNIT_ASSERT_EQUAL(tools::Long(5000), aGraphic.GetPrefSize().Height()); + CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable()); + + // check GetSizeBytes loads graphic + CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable()); + CPPUNIT_ASSERT(aGraphic.GetSizeBytes() > 0); + CPPUNIT_ASSERT_EQUAL(true, aGraphic.isAvailable()); + + //check Type + aGraphic = makeUnloadedGraphic(u"png"); + CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable()); + CPPUNIT_ASSERT_EQUAL(GraphicType::Bitmap, aGraphic.GetType()); + CPPUNIT_ASSERT_EQUAL(true, aGraphic.makeAvailable()); + CPPUNIT_ASSERT_EQUAL(true, aGraphic.isAvailable()); + CPPUNIT_ASSERT_EQUAL(GraphicType::Bitmap, aGraphic.GetType()); +} + +void GraphicTest::testUnloadedGraphicLoading() +{ + const OUString aFormats[] = { "png", "gif", "jpg", "tif", "webp" }; + + for (OUString const& sFormat : aFormats) + { + Graphic aGraphic = makeUnloadedGraphic(sFormat); + + // check available + CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable()); + CPPUNIT_ASSERT_EQUAL(tools::Long(120), aGraphic.GetSizePixel().Width()); + CPPUNIT_ASSERT_EQUAL(tools::Long(100), aGraphic.GetSizePixel().Height()); + CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable()); + CPPUNIT_ASSERT(aGraphic.GetSizeBytes() > 0); + CPPUNIT_ASSERT_EQUAL(true, aGraphic.isAvailable()); + + if (sFormat != "jpg") + CPPUNIT_ASSERT_EQUAL(true, checkBitmap(aGraphic)); + } +} + +void GraphicTest::testUnloadedGraphicWmf() +{ + // Create some in-memory WMF data, set its own preferred size to 99x99. + BitmapEx aBitmapEx = createBitmap(); + SvMemoryStream aStream; + GraphicFilter& rGraphicFilter = GraphicFilter::GetGraphicFilter(); + sal_uInt16 nFilterFormat = rGraphicFilter.GetExportFormatNumberForShortName(u"wmf"); + Graphic aGraphic(aBitmapEx); + aGraphic.SetPrefSize(Size(99, 99)); + aGraphic.SetPrefMapMode(MapMode(MapUnit::Map100thMM)); + rGraphicFilter.ExportGraphic(aGraphic, u"none", aStream, nFilterFormat); + aStream.Seek(STREAM_SEEK_TO_BEGIN); + + // Now lazy-load this WMF data, with a custom preferred size of 42x42. + Size aMtfSize100(42, 42); + aGraphic = rGraphicFilter.ImportUnloadedGraphic(aStream, 0, &aMtfSize100); + aGraphic.makeAvailable(); + + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 42x42 + // - Actual : 99x99 + // i.e. the custom preferred size was lost after lazy-load. + CPPUNIT_ASSERT_EQUAL(Size(42, 42), aGraphic.GetPrefSize()); +} + +void GraphicTest::testUnloadedGraphicAlpha() +{ + // make unloaded test graphic with alpha + Graphic aGraphic = makeUnloadedGraphic(u"png", true); + + CPPUNIT_ASSERT_EQUAL(true, aGraphic.IsAlpha()); + CPPUNIT_ASSERT_EQUAL(true, aGraphic.IsTransparent()); + CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable()); + + // make unloaded test graphic without alpha + aGraphic = makeUnloadedGraphic(u"png", false); + + CPPUNIT_ASSERT_EQUAL(false, aGraphic.IsAlpha()); + CPPUNIT_ASSERT_EQUAL(false, aGraphic.IsTransparent()); + CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable()); +} + +void GraphicTest::testUnloadedGraphicSizeUnit() +{ + GraphicFilter& rGraphicFilter = GraphicFilter::GetGraphicFilter(); + test::Directories aDirectories; + OUString aURL = aDirectories.getURLFromSrc(DATA_DIRECTORY) + "inch-size.emf"; + Size aMtfSize100(42, 42); + SvFileStream aStream(aURL, StreamMode::READ); + Graphic aGraphic = rGraphicFilter.ImportUnloadedGraphic(aStream, 0, &aMtfSize100); + + CPPUNIT_ASSERT_EQUAL(Size(42, 42), aGraphic.GetPrefSize()); + + // Force it to swap in + aGraphic.makeAvailable(); + + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 400x363 + // - Actual : 42x42 + // i.e. a mm100 size was used as a hint and the inch size was set for a non-matching unit. + CPPUNIT_ASSERT_EQUAL(Size(400, 363), aGraphic.GetPrefSize()); +} + +void GraphicTest::testWMFRoundtrip() +{ + // Load a WMF file. + test::Directories aDirectories; + OUString aURL = aDirectories.getURLFromSrc(u"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, u"", 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); +} + +int getEmfPlusActionsCount(const Graphic& graphic) +{ + const GDIMetaFile& metafile = graphic.GetGDIMetaFile(); + int emfPlusCount = 0; + for (size_t i = 0; i < metafile.GetActionSize(); ++i) + { + MetaAction* action = metafile.GetAction(i); + if (action->GetType() == MetaActionType::COMMENT) + { + const MetaCommentAction* commentAction = static_cast(action); + if (commentAction->GetComment() == "EMF_PLUS") + ++emfPlusCount; + } + } + return emfPlusCount; +} + +int getPolygonActionsCount(const Graphic& graphic) +{ + const GDIMetaFile& metafile = graphic.GetGDIMetaFile(); + int polygonCount = 0; + for (size_t i = 0; i < metafile.GetActionSize(); ++i) + { + MetaAction* action = metafile.GetAction(i); + if (action->GetType() == MetaActionType::POLYGON) + ++polygonCount; + } + return polygonCount; +} + +void GraphicTest::testWMFWithEmfPlusRoundtrip() +{ + // Load a WMF file. + test::Directories aDirectories; + OUString aURL = aDirectories.getURLFromSrc(u"vcl/qa/cppunit/data/wmf-embedded-emfplus.wmf"); + SvFileStream aStream(aURL, StreamMode::READ); + sal_uInt64 nExpectedSize = aStream.TellEnd(); + GraphicFilter& rGraphicFilter = GraphicFilter::GetGraphicFilter(); + Graphic aGraphic = rGraphicFilter.ImportUnloadedGraphic(aStream); + + CPPUNIT_ASSERT_GREATER(0, getEmfPlusActionsCount(aGraphic)); + CPPUNIT_ASSERT_EQUAL(0, getPolygonActionsCount(aGraphic)); + + for (bool useConvertMetafile : { false, true }) + { + // Save as WMF. + utl::TempFile aTempFile; + aTempFile.EnableKillingFile(); + SvStream& rOutStream = *aTempFile.GetStream(StreamMode::READWRITE); + if (useConvertMetafile) + ConvertGraphicToWMF(aGraphic, rOutStream, nullptr); + else + { + sal_uInt16 nFormat = rGraphicFilter.GetExportFormatNumberForShortName(u"WMF"); + rGraphicFilter.ExportGraphic(aGraphic, u"", rOutStream, nFormat); + } + CPPUNIT_ASSERT_EQUAL(nExpectedSize, rOutStream.TellEnd()); + + rOutStream.Seek(0); + Graphic aNewGraphic = rGraphicFilter.ImportUnloadedGraphic(rOutStream); + // Check that reading the WMF back preserves the EMF+ actions in it. + CPPUNIT_ASSERT_GREATER(0, getEmfPlusActionsCount(aNewGraphic)); + // EmfReader::ReadEnhWMF() drops non-EMF+ drawing actions if EMF+ is found. + CPPUNIT_ASSERT_EQUAL(0, getPolygonActionsCount(aNewGraphic)); + + // With EMF+ disabled there should be no EMF+ actions. + auto aVectorGraphicData = std::make_shared( + aNewGraphic.GetGfxLink().getDataContainer(), VectorGraphicDataType::Wmf); + aVectorGraphicData->setEnableEMFPlus(false); + Graphic aNoEmfPlusGraphic(aVectorGraphicData); + CPPUNIT_ASSERT_EQUAL(0, getEmfPlusActionsCount(aNoEmfPlusGraphic)); + CPPUNIT_ASSERT_GREATER(0, getPolygonActionsCount(aNoEmfPlusGraphic)); + } +} + +void GraphicTest::testEmfToWmfConversion() +{ + // Load EMF data. + GraphicFilter aGraphicFilter; + test::Directories aDirectories; + OUString aURL = aDirectories.getURLFromSrc(DATA_DIRECTORY) + "to-wmf.emf"; + SvFileStream aStream(aURL, StreamMode::READ); + Graphic aGraphic; + // This similar to an application/x-openoffice-wmf mime type in manifest.xml in the ODF case. + sal_uInt16 nFormat = aGraphicFilter.GetImportFormatNumberForShortName(u"WMF"); + CPPUNIT_ASSERT_EQUAL(ERRCODE_NONE, + aGraphicFilter.ImportGraphic(aGraphic, u"", aStream, nFormat)); + CPPUNIT_ASSERT_EQUAL(VectorGraphicDataType::Wmf, aGraphic.getVectorGraphicData()->getType()); + + // Save as WMF. + sal_uInt16 nFilterType = aGraphicFilter.GetExportFormatNumberForShortName(u"WMF"); + SvMemoryStream aGraphicStream; + CPPUNIT_ASSERT_EQUAL(ERRCODE_NONE, + aGraphicFilter.ExportGraphic(aGraphic, u"", aGraphicStream, nFilterType)); + aGraphicStream.Seek(0); + vcl::GraphicFormatDetector aDetector(aGraphicStream, OUString()); + CPPUNIT_ASSERT(aDetector.detect()); + CPPUNIT_ASSERT(aDetector.checkWMForEMF()); + + // Without the accompanying fix in place, this test would have failed with: + // - Expected: WMF + // - Actual : EMF + // i.e. EMF data was requested to be converted to WMF, but the output was still EMF. + CPPUNIT_ASSERT_EQUAL(OUString("WMF"), aDetector.msDetectedFormat); + + // Import the WMF result and check for traces of EMF+ in it. + Graphic aWmfGraphic; + aGraphicStream.Seek(0); + CPPUNIT_ASSERT_EQUAL(ERRCODE_NONE, + aGraphicFilter.ImportGraphic(aWmfGraphic, u"", aGraphicStream, nFormat)); + int nCommentCount = 0; + for (size_t i = 0; i < aWmfGraphic.GetGDIMetaFile().GetActionSize(); ++i) + { + MetaAction* pAction = aWmfGraphic.GetGDIMetaFile().GetAction(i); + if (pAction->GetType() == MetaActionType::COMMENT) + { + auto pComment = static_cast(pAction); + if (pComment->GetComment().startsWith("EMF_PLUS")) + { + ++nCommentCount; + } + } + } + // Without the accompanying fix in place, this test would have failed with: + // - Expected less or equal than: 4 + // - Actual : 8 + // i.e. even more EMF+ comments were left in the WMF output. The ideal would be to get this down + // to 0, though. + CPPUNIT_ASSERT_LESSEQUAL(4, nCommentCount); +} + +void GraphicTest::testSwappingGraphic_PNG_WithGfxLink() +{ + // Prepare Graphic from a PNG image first + Graphic aGraphic = makeUnloadedGraphic(u"png"); + + 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(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(); + CPPUNIT_ASSERT_EQUAL(true, rSwapFileURL.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()); + + // 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(36079), xStream->remainingSize()); + + std::vector aHash = calculateHash(xStream); + CPPUNIT_ASSERT_EQUAL(std::string("9347511e3b80dfdfaadf91a3bdef55a8ae85552b"), + 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()); + + // 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 + CPPUNIT_ASSERT_EQUAL(false, comphelper::DirectoryHelper::fileExists(rSwapFileURL)); + + // 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::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(size_t(223), pVectorData->getBinaryDataContainer().getSize()); + + 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(size_t(223), + aInputGraphic.getVectorGraphicData()->getBinaryDataContainer().getSize()); + + // 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(size_t(223), + aGraphic.getVectorGraphicData()->getBinaryDataContainer().getSize()); + + CPPUNIT_ASSERT_EQUAL(false, aGraphic.IsGfxLink()); + + BitmapChecksum aBitmapChecksumBeforeSwapping = aGraphic.GetBitmapEx().GetChecksum(); + + 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); + + OUString rSwapFileURL = aGraphic.ImplGetImpGraphic()->getSwapFileURL(); + CPPUNIT_ASSERT_EQUAL(true, rSwapFileURL.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 + // TODO: In case we don't trigger GetBitmapEx (above) the size is 0 + CPPUNIT_ASSERT_EQUAL(rByteSize, aGraphic.GetSizeBytes()); + + // 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 + std::unique_ptr xStream = createStream(rSwapFileURL); + CPPUNIT_ASSERT_EQUAL(true, bool(xStream)); + + // Check size of the stream + CPPUNIT_ASSERT_EQUAL(sal_uInt64(247), xStream->remainingSize()); + + std::vector aHash = calculateHash(xStream); + CPPUNIT_ASSERT_EQUAL(std::string("666820973fd95e6cd9e7bc5f1c53732acbc99326"), + toHexString(aHash)); + } + + // Let's swap in + 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())); + + size_t nVectorByteSize = aGraphic.getVectorGraphicData()->getBinaryDataContainer().getSize(); + CPPUNIT_ASSERT_EQUAL(size_t(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::testSwappingGraphicProperties_SVG_WithGfxLink() +{ + // FIXME: the DPI check should be removed when either (1) the test is fixed to work with + // non-default DPI; or (2) unit tests on Windows are made to use svp VCL plugin. + if (!IsDefaultDPI()) + return; + + // 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() +{ + // FIXME: the DPI check should be removed when either (1) the test is fixed to work with + // non-default DPI; or (2) unit tests on Windows are made to use svp VCL plugin. + if (!IsDefaultDPI()) + return; + + 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(size_t(223), + aInputGraphic.getVectorGraphicData()->getBinaryDataContainer().getSize()); + + // 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"; + SvFileStream aStream(aURL, StreamMode::READ); + GraphicFilter& rGraphicFilter = GraphicFilter::GetGraphicFilter(); + Graphic aGraphic = rGraphicFilter.ImportUnloadedGraphic(aStream); + + CPPUNIT_ASSERT_EQUAL(GraphicType::Bitmap, aGraphic.GetType()); + CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable()); + + // Load the vector graphic + CPPUNIT_ASSERT_EQUAL(true, bool(aGraphic.getVectorGraphicData())); + + // Set the page index + aGraphic.getVectorGraphicData()->setPageIndex(1); + + CPPUNIT_ASSERT_EQUAL(VectorGraphicDataType::Pdf, aGraphic.getVectorGraphicData()->getType()); + CPPUNIT_ASSERT_EQUAL(size_t(17693), + aGraphic.getVectorGraphicData()->getBinaryDataContainer().getSize()); + 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::testSwappingVectorGraphic_PDF_WithoutGfxLink() +{ + test::Directories aDirectories; + 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()->getType()); + CPPUNIT_ASSERT_EQUAL(size_t(17693), + aGraphic.getVectorGraphicData()->getBinaryDataContainer().getSize()); + 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); + 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()); + + CPPUNIT_ASSERT_EQUAL(true, aGraphic.makeAvailable()); + CPPUNIT_ASSERT_EQUAL(true, aGraphic.isAvailable()); + + 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(89552), 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(15139), xStream->remainingSize()); + + std::vector aHash = calculateHash(xStream); + CPPUNIT_ASSERT_EQUAL(std::string("ecae5354edd9cf98553eb3153e44181f56d35338"), + 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()); +} + +void GraphicTest::testLoadMET() +{ + Graphic aGraphic = loadGraphic(u"TypeDetectionExample.met"); + CPPUNIT_ASSERT_EQUAL(GraphicType::GdiMetafile, aGraphic.GetType()); +} + +void GraphicTest::testLoadBMP() +{ + Graphic aGraphic = loadGraphic(u"TypeDetectionExample.bmp"); + CPPUNIT_ASSERT_EQUAL(GraphicType::Bitmap, aGraphic.GetType()); + CPPUNIT_ASSERT_EQUAL(tools::Long(10), aGraphic.GetSizePixel().Width()); + CPPUNIT_ASSERT_EQUAL(tools::Long(10), aGraphic.GetSizePixel().Height()); +} + +void GraphicTest::testLoadPSD() +{ + Graphic aGraphic = loadGraphic(u"TypeDetectionExample.psd"); + CPPUNIT_ASSERT_EQUAL(GraphicType::Bitmap, aGraphic.GetType()); + CPPUNIT_ASSERT_EQUAL(tools::Long(10), aGraphic.GetSizePixel().Width()); + CPPUNIT_ASSERT_EQUAL(tools::Long(10), aGraphic.GetSizePixel().Height()); +} + +void GraphicTest::testLoadTGA() +{ + Graphic aGraphic = loadGraphic(u"TypeDetectionExample.tga"); + CPPUNIT_ASSERT_EQUAL(GraphicType::Bitmap, aGraphic.GetType()); + CPPUNIT_ASSERT_EQUAL(tools::Long(10), aGraphic.GetSizePixel().Width()); + CPPUNIT_ASSERT_EQUAL(tools::Long(10), aGraphic.GetSizePixel().Height()); +} + +void GraphicTest::testLoadXBM() +{ + Graphic aGraphic = loadGraphic(u"TypeDetectionExample.xbm"); + CPPUNIT_ASSERT_EQUAL(GraphicType::Bitmap, aGraphic.GetType()); + CPPUNIT_ASSERT_EQUAL(tools::Long(10), aGraphic.GetSizePixel().Width()); + CPPUNIT_ASSERT_EQUAL(tools::Long(10), aGraphic.GetSizePixel().Height()); +} + +void GraphicTest::testLoadXPM() +{ + Graphic aGraphic = loadGraphic(u"TypeDetectionExample.xpm"); + CPPUNIT_ASSERT_EQUAL(GraphicType::Bitmap, aGraphic.GetType()); + CPPUNIT_ASSERT_EQUAL(tools::Long(10), aGraphic.GetSizePixel().Width()); + CPPUNIT_ASSERT_EQUAL(tools::Long(10), aGraphic.GetSizePixel().Height()); +} + +void GraphicTest::testLoadPCX() +{ + Graphic aGraphic = loadGraphic(u"TypeDetectionExample.pcx"); + CPPUNIT_ASSERT_EQUAL(GraphicType::Bitmap, aGraphic.GetType()); + CPPUNIT_ASSERT_EQUAL(tools::Long(10), aGraphic.GetSizePixel().Width()); + CPPUNIT_ASSERT_EQUAL(tools::Long(10), aGraphic.GetSizePixel().Height()); +} + +void GraphicTest::testLoadEPS() +{ + Graphic aGraphic = loadGraphic(u"TypeDetectionExample.eps"); + CPPUNIT_ASSERT_EQUAL(GraphicType::GdiMetafile, aGraphic.GetType()); +} + +void GraphicTest::testLoadWEBP() +{ + Graphic aGraphic = loadGraphic(u"TypeDetectionExample.webp"); + CPPUNIT_ASSERT_EQUAL(GraphicType::Bitmap, aGraphic.GetType()); + CPPUNIT_ASSERT_EQUAL(tools::Long(10), aGraphic.GetSizePixel().Width()); + CPPUNIT_ASSERT_EQUAL(tools::Long(10), aGraphic.GetSizePixel().Height()); +} + +void GraphicTest::testAvailableThreaded() +{ + Graphic jpgGraphic1 = importUnloadedGraphic(u"TypeDetectionExample.jpg"); + Graphic jpgGraphic2 = importUnloadedGraphic(u"Exif1.jpg"); + Graphic pngGraphic1 = importUnloadedGraphic(u"TypeDetectionExample.png"); + Graphic pngGraphic2 = importUnloadedGraphic(u"testBasicMorphology.png"); + std::vector graphics = { &jpgGraphic1, &jpgGraphic2, &pngGraphic1, &pngGraphic2 }; + std::vector sizes; + for (auto& graphic : graphics) + { + CPPUNIT_ASSERT(!graphic->isAvailable()); + sizes.push_back(graphic->GetSizePixel()); + } + GraphicFilter& graphicFilter = GraphicFilter::GetGraphicFilter(); + graphicFilter.MakeGraphicsAvailableThreaded(graphics); + int i = 0; + for (auto& graphic : graphics) + { + CPPUNIT_ASSERT(graphic->isAvailable()); + CPPUNIT_ASSERT_EQUAL(sizes[i], graphic->GetSizePixel()); + ++i; + } +} + +void GraphicTest::testColorChangeToTransparent() +{ + Graphic aGraphic = importUnloadedGraphic(u"testColorChange-red-linear-gradient.png"); + + auto xGraphic = aGraphic.GetXGraphic(); + uno::Reference xGraphicTransformer{ xGraphic, uno::UNO_QUERY }; + ::Color nColorFrom{ ColorTransparency, 0x00, 0xFF, 0x00, 0x00 }; + ::Color nColorTo{ ColorTransparency, 0xFF, 0xFF, 0x00, 0x00 }; + sal_uInt8 nTolerance{ 15 }; + + auto xGraphicAfter = xGraphicTransformer->colorChange( + xGraphic, static_cast(nColorFrom), nTolerance, static_cast(nColorTo), + static_cast(nColorTo.GetAlpha())); + + Graphic aGraphicAfter{ xGraphicAfter }; + const BitmapEx& rBitmapAfter = aGraphicAfter.GetBitmapExRef(); + const BitmapEx& rBitmapBefore = aGraphic.GetBitmapExRef(); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: rgba[ff000000] + // - Actual : rgba[f00000ff] + // i.e. the color change to transparent didn't apply correctly + CPPUNIT_ASSERT_EQUAL(nColorTo, rBitmapAfter.GetPixelColor(386, 140)); + + // Test if color stayed same on 410,140 + // colorChange with nTolerance 15 shouldn't change this pixel. + CPPUNIT_ASSERT_EQUAL(rBitmapBefore.GetPixelColor(410, 140), + rBitmapAfter.GetPixelColor(410, 140)); +} + +} // namespace + +CPPUNIT_TEST_SUITE_REGISTRATION(GraphicTest); + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ -- cgit v1.2.3