graphic: Rework swapping algorithm to take GfxLink into account

This reworks the Graphic swap algorithm to not swap to a file when
GfxLink is available and leaves the compressed data in memory.
With such a sheme, at swap-out we just remember the need specific
properties of the Graphic, and delete the graphic content (Bitmap,
Animation, VectorGraphic, Metafile). At swap-in use the GfxLink
data to decompress and recreate the graphic content, then set
the properties back as they were before (if needed).

If a GfxLink is not available it swaps out to a file and back, but
uses a simpler data format that is specific for swapping only. In
the future this case can be removed, when we switch to automatic
creation of GfxLink if that one is not present.

For reworking of swapping it was also necessary to extensively add
and extend the tests that check various swapping scenarios.

Change-Id: I135a224f74aa48e6006f48dd2be74b8026614728
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/107287
Tested-by: Jenkins
Reviewed-by: Tomaž Vajngerl <quikee@gmail.com>
This commit is contained in:
Tomaž Vajngerl
2020-12-06 21:14:07 +09:00
committed by Tomaž Vajngerl
parent 3dabbb6a5e
commit def31e135e
5 changed files with 926 additions and 458 deletions

View File

@@ -32,6 +32,11 @@ constexpr sal_uInt32 createMagic(char char1, char char2, char char3, char char4)
| (static_cast<sal_uInt32>(char3) << 8) | (static_cast<sal_uInt32>(char4) << 0);
}
constexpr sal_uInt32 constSvgMagic = createMagic('s', 'v', 'g', '0');
constexpr sal_uInt32 constWmfMagic = createMagic('w', 'm', 'f', '0');
constexpr sal_uInt32 constEmfMagic = createMagic('e', 'm', 'f', '0');
constexpr sal_uInt32 constPdfMagic = createMagic('p', 'd', 'f', '0');
class VCL_DLLPUBLIC TypeSerializer : public tools::GenericTypeSerializer
{
public:

View File

@@ -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; }

View File

@@ -50,23 +50,50 @@ private:
void testUnloadedGraphicWmf();
void testUnloadedGraphicAlpha();
void testUnloadedGraphicSizeUnit();
void testSwapping();
void testSwappingVectorGraphic();
void testSwappingPageNumber();
void testWMFRoundtrip();
void testEmfToWmfConversion();
void testSwappingGraphic_PNG_WithGfxLink();
void testSwappingGraphic_PNG_WithoutGfxLink();
void testSwappingGraphicProperties_PNG_WithGfxLink();
void testSwappingGraphicProperties_PNG_WithoutGfxLink();
void testSwappingVectorGraphic_SVG_WithGfxLink();
void testSwappingVectorGraphic_SVG_WithoutGfxLink();
void testSwappingGraphicProperties_SVG_WithGfxLink();
void testSwappingGraphicProperties_SVG_WithoutGfxLink();
void testSwappingVectorGraphic_PDF_WithGfxLink();
void testSwappingVectorGraphic_PDF_WithoutGfxLink();
void testSwappingAnimationGraphic_GIF_WithGfxLink();
void testSwappingAnimationGraphic_GIF_WithoutGfxLink();
CPPUNIT_TEST_SUITE(GraphicTest);
CPPUNIT_TEST(testUnloadedGraphic);
CPPUNIT_TEST(testUnloadedGraphicLoading);
CPPUNIT_TEST(testUnloadedGraphicWmf);
CPPUNIT_TEST(testUnloadedGraphicAlpha);
CPPUNIT_TEST(testUnloadedGraphicSizeUnit);
CPPUNIT_TEST(testSwapping);
CPPUNIT_TEST(testSwappingVectorGraphic);
CPPUNIT_TEST(testSwappingPageNumber);
CPPUNIT_TEST(testWMFRoundtrip);
CPPUNIT_TEST(testEmfToWmfConversion);
CPPUNIT_TEST(testSwappingGraphic_PNG_WithGfxLink);
CPPUNIT_TEST(testSwappingGraphic_PNG_WithoutGfxLink);
CPPUNIT_TEST(testSwappingGraphicProperties_PNG_WithGfxLink);
CPPUNIT_TEST(testSwappingGraphicProperties_PNG_WithoutGfxLink);
CPPUNIT_TEST(testSwappingVectorGraphic_SVG_WithGfxLink);
CPPUNIT_TEST(testSwappingVectorGraphic_SVG_WithoutGfxLink);
CPPUNIT_TEST(testSwappingGraphicProperties_SVG_WithGfxLink);
CPPUNIT_TEST(testSwappingGraphicProperties_SVG_WithoutGfxLink);
CPPUNIT_TEST(testSwappingVectorGraphic_PDF_WithGfxLink);
CPPUNIT_TEST(testSwappingVectorGraphic_PDF_WithoutGfxLink);
CPPUNIT_TEST(testSwappingAnimationGraphic_GIF_WithGfxLink);
CPPUNIT_TEST(testSwappingAnimationGraphic_GIF_WithoutGfxLink);
CPPUNIT_TEST_SUITE_END();
};
@@ -306,6 +333,33 @@ void GraphicTest::testUnloadedGraphicSizeUnit()
CPPUNIT_ASSERT_EQUAL(Size(400, 363), aGraphic.GetPrefSize());
}
void GraphicTest::testWMFRoundtrip()
{
// Load a WMF file.
test::Directories aDirectories;
OUString aURL = aDirectories.getURLFromSrc("vcl/qa/cppunit/data/roundtrip.wmf");
SvFileStream aStream(aURL, StreamMode::READ);
sal_uInt64 nExpectedSize = aStream.TellEnd();
GraphicFilter& rGraphicFilter = GraphicFilter::GetGraphicFilter();
Graphic aGraphic = rGraphicFilter.ImportUnloadedGraphic(aStream);
// Save as WMF.
utl::TempFile aTempFile;
aTempFile.EnableKillingFile();
sal_uInt16 nFormat = rGraphicFilter.GetExportFormatNumberForShortName(u"WMF");
SvStream& rOutStream = *aTempFile.GetStream(StreamMode::READWRITE);
rGraphicFilter.ExportGraphic(aGraphic, OUString(), rOutStream, nFormat);
// Check if we preserved the WMF data perfectly.
sal_uInt64 nActualSize = rOutStream.TellEnd();
// Without the accompanying fix in place, this test would have failed with:
// - Expected: 6475
// - Actual : 2826
// i.e. we lost some of the WMF data on roundtrip.
CPPUNIT_ASSERT_EQUAL(nExpectedSize, nActualSize);
}
void GraphicTest::testEmfToWmfConversion()
{
// Load EMF data.
@@ -363,7 +417,7 @@ void GraphicTest::testEmfToWmfConversion()
CPPUNIT_ASSERT_LESSEQUAL(4, nCommentCount);
}
void GraphicTest::testSwapping()
void GraphicTest::testSwappingGraphic_PNG_WithGfxLink()
{
// Prepare Graphic from a PNG image first
Graphic aGraphic = makeUnloadedGraphic(u"png");
@@ -377,10 +431,64 @@ void GraphicTest::testSwapping()
BitmapChecksum aChecksumBeforeSwapping = aGraphic.GetChecksum();
CPPUNIT_ASSERT_EQUAL(true, aGraphic.IsGfxLink());
CPPUNIT_ASSERT_EQUAL(sal_uInt32(319), aGraphic.GetGfxLink().GetDataSize());
// We loaded the Graphic and made it available
CPPUNIT_ASSERT_EQUAL(false, aGraphic.ImplGetImpGraphic()->isSwappedOut());
// Get the declared byte size of the graphic
sal_uLong rByteSize = aGraphic.GetSizeBytes();
// Check the swap file (shouldn't exist)
CPPUNIT_ASSERT_EQUAL(true, aGraphic.ImplGetImpGraphic()->getSwapFileURL().isEmpty());
// Swapping out
CPPUNIT_ASSERT_EQUAL(true, aGraphic.ImplGetImpGraphic()->swapOut());
CPPUNIT_ASSERT_EQUAL(true, aGraphic.ImplGetImpGraphic()->isSwappedOut());
CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable());
// Byte size doesn't change when we swapped out
CPPUNIT_ASSERT_EQUAL(rByteSize, aGraphic.GetSizeBytes());
// Check the swap file (still shouldn't exist)
CPPUNIT_ASSERT_EQUAL(true, aGraphic.ImplGetImpGraphic()->getSwapFileURL().isEmpty());
// Let's swap in
CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable());
CPPUNIT_ASSERT_EQUAL(true, aGraphic.makeAvailable());
CPPUNIT_ASSERT_EQUAL(true, aGraphic.isAvailable());
CPPUNIT_ASSERT_EQUAL(false, aGraphic.ImplGetImpGraphic()->isSwappedOut());
CPPUNIT_ASSERT_EQUAL(aChecksumBeforeSwapping, aGraphic.GetChecksum());
// Check the bitmap
CPPUNIT_ASSERT_EQUAL(tools::Long(120), aGraphic.GetSizePixel().Width());
CPPUNIT_ASSERT_EQUAL(tools::Long(100), aGraphic.GetSizePixel().Height());
CPPUNIT_ASSERT_EQUAL(true, checkBitmap(aGraphic));
}
void GraphicTest::testSwappingGraphic_PNG_WithoutGfxLink()
{
// Prepare Graphic from a PNG image first
// Make sure to construct the Graphic from BitmapEx, so that we
// don't have the GfxLink present.
Graphic aGraphic(makeUnloadedGraphic(u"png").GetBitmapEx());
CPPUNIT_ASSERT_EQUAL(GraphicType::Bitmap, aGraphic.GetType());
CPPUNIT_ASSERT_EQUAL(true, aGraphic.makeAvailable());
CPPUNIT_ASSERT_EQUAL(true, aGraphic.isAvailable());
CPPUNIT_ASSERT_EQUAL(tools::Long(120), aGraphic.GetSizePixel().Width());
CPPUNIT_ASSERT_EQUAL(tools::Long(100), aGraphic.GetSizePixel().Height());
BitmapChecksum aChecksumBeforeSwapping = aGraphic.GetChecksum();
CPPUNIT_ASSERT_EQUAL(false, aGraphic.IsGfxLink());
// We loaded the Graphic and made it available
CPPUNIT_ASSERT_EQUAL(false, aGraphic.ImplGetImpGraphic()->isSwappedOut());
// Get the declared byte size of the graphic
sal_uLong rByteSize = aGraphic.GetSizeBytes();
OUString rSwapFileURL = aGraphic.ImplGetImpGraphic()->getSwapFileURL();
@@ -403,19 +511,21 @@ void GraphicTest::testSwapping()
CPPUNIT_ASSERT_EQUAL(true, bool(xStream));
// Check size of the stream
CPPUNIT_ASSERT_EQUAL(sal_uInt64(449), xStream->remainingSize());
CPPUNIT_ASSERT_EQUAL(sal_uInt64(36079), xStream->remainingSize());
std::vector<unsigned char> aHash = calculateHash(xStream);
CPPUNIT_ASSERT_EQUAL(std::string("878281e583487b29ae09078e8040c01791c7649a"),
CPPUNIT_ASSERT_EQUAL(std::string("9347511e3b80dfdfaadf91a3bdef55a8ae85552b"),
toHexString(aHash));
}
// Let's swap in
// SWAP IN
CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable());
CPPUNIT_ASSERT_EQUAL(true, aGraphic.makeAvailable());
CPPUNIT_ASSERT_EQUAL(true, aGraphic.isAvailable());
CPPUNIT_ASSERT_EQUAL(false, aGraphic.ImplGetImpGraphic()->isSwappedOut());
// reset the checksum to make sure we don't get the cached value
aGraphic.ImplGetImpGraphic()->resetChecksum();
CPPUNIT_ASSERT_EQUAL(aChecksumBeforeSwapping, aGraphic.GetChecksum());
// File shouldn't be available anymore
@@ -424,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<SvStream> xStream = createStream(rSwapFileURL);
CPPUNIT_ASSERT_EQUAL(true, bool(xStream));
// Check size of the stream
CPPUNIT_ASSERT_EQUAL(sal_uInt64(353), xStream->remainingSize());
CPPUNIT_ASSERT_EQUAL(sal_uInt64(249), xStream->remainingSize());
std::vector<unsigned char> aHash = calculateHash(xStream);
CPPUNIT_ASSERT_EQUAL(std::string("6ae83fc9c06ca253ada0b156d6e4700a4a028c34"),
CPPUNIT_ASSERT_EQUAL(std::string("322da9ea0683f03ce35cf8a71e59b686b9be28e8"),
toHexString(aHash));
}
@@ -486,15 +763,146 @@ void GraphicTest::testSwappingVectorGraphic()
CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable());
CPPUNIT_ASSERT_EQUAL(true, aGraphic.makeAvailable());
CPPUNIT_ASSERT_EQUAL(true, aGraphic.isAvailable());
// Check the Graphic
CPPUNIT_ASSERT_EQUAL(false, aGraphic.ImplGetImpGraphic()->isSwappedOut());
CPPUNIT_ASSERT_EQUAL(GraphicType::Bitmap, aGraphic.GetType());
CPPUNIT_ASSERT_EQUAL(true, bool(aGraphic.getVectorGraphicData()));
sal_uInt32 nVectorByteSize = aGraphic.getVectorGraphicData()->getVectorGraphicDataArrayLength();
CPPUNIT_ASSERT_EQUAL(sal_uInt32(223), nVectorByteSize);
CPPUNIT_ASSERT_EQUAL(false, aGraphic.IsGfxLink());
CPPUNIT_ASSERT_EQUAL(aBitmapChecksumBeforeSwapping, aGraphic.GetBitmapEx().GetChecksum());
// File shouldn't be available anymore
CPPUNIT_ASSERT_EQUAL(false, comphelper::DirectoryHelper::fileExists(rSwapFileURL));
}
void GraphicTest::testSwappingPageNumber()
void GraphicTest::testSwappingGraphicProperties_SVG_WithGfxLink()
{
// We check that Graphic properties like MapMode, PrefSize are properly
// restored through a swap cycle
test::Directories aDirectories;
OUString aURL = aDirectories.getURLFromSrc(DATA_DIRECTORY) + "SimpleExample.svg";
SvFileStream aStream(aURL, StreamMode::READ);
GraphicFilter& rGraphicFilter = GraphicFilter::GetGraphicFilter();
Graphic aGraphic = rGraphicFilter.ImportUnloadedGraphic(aStream);
// Loaded into "prepared" state
// Load the vector graphic
auto pVectorData = aGraphic.getVectorGraphicData();
CPPUNIT_ASSERT_EQUAL(true, bool(pVectorData));
CPPUNIT_ASSERT_EQUAL(true, aGraphic.isAvailable());
// Origin URL
aGraphic.setOriginURL("Origin URL");
CPPUNIT_ASSERT_EQUAL(OUString("Origin URL"), aGraphic.getOriginURL());
// Check size in pixels
CPPUNIT_ASSERT_EQUAL(tools::Long(51), aGraphic.GetSizePixel().Width());
CPPUNIT_ASSERT_EQUAL(tools::Long(51), aGraphic.GetSizePixel().Height());
// Set and check the PrefSize
CPPUNIT_ASSERT_EQUAL(tools::Long(1349), aGraphic.GetPrefSize().Width());
CPPUNIT_ASSERT_EQUAL(tools::Long(1349), aGraphic.GetPrefSize().Height());
aGraphic.SetPrefSize(Size(200, 100));
CPPUNIT_ASSERT_EQUAL(tools::Long(200), aGraphic.GetPrefSize().Width());
CPPUNIT_ASSERT_EQUAL(tools::Long(100), aGraphic.GetPrefSize().Height());
// SWAP OUT the Graphic and make sure it's not available currently
CPPUNIT_ASSERT_EQUAL(true, aGraphic.isAvailable());
CPPUNIT_ASSERT_EQUAL(true, aGraphic.ImplGetImpGraphic()->swapOut());
CPPUNIT_ASSERT_EQUAL(true, aGraphic.ImplGetImpGraphic()->isSwappedOut());
CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable());
// Check properties
CPPUNIT_ASSERT_EQUAL(OUString("Origin URL"), aGraphic.getOriginURL());
CPPUNIT_ASSERT_EQUAL(tools::Long(200), aGraphic.GetPrefSize().Width());
CPPUNIT_ASSERT_EQUAL(tools::Long(100), aGraphic.GetPrefSize().Height());
CPPUNIT_ASSERT_EQUAL(tools::Long(51), aGraphic.GetSizePixel().Width());
CPPUNIT_ASSERT_EQUAL(tools::Long(51), aGraphic.GetSizePixel().Height());
// SWAP IN
CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable());
CPPUNIT_ASSERT_EQUAL(true, aGraphic.makeAvailable());
CPPUNIT_ASSERT_EQUAL(true, aGraphic.isAvailable());
CPPUNIT_ASSERT_EQUAL(false, aGraphic.ImplGetImpGraphic()->isSwappedOut());
// Check properties
CPPUNIT_ASSERT_EQUAL(OUString("Origin URL"), aGraphic.getOriginURL());
CPPUNIT_ASSERT_EQUAL(tools::Long(200), aGraphic.GetPrefSize().Width());
CPPUNIT_ASSERT_EQUAL(tools::Long(100), aGraphic.GetPrefSize().Height());
CPPUNIT_ASSERT_EQUAL(tools::Long(51), aGraphic.GetSizePixel().Width());
CPPUNIT_ASSERT_EQUAL(tools::Long(51), aGraphic.GetSizePixel().Height());
}
void GraphicTest::testSwappingGraphicProperties_SVG_WithoutGfxLink()
{
test::Directories aDirectories;
OUString aURL = aDirectories.getURLFromSrc(DATA_DIRECTORY) + "SimpleExample.svg";
SvFileStream aStream(aURL, StreamMode::READ);
GraphicFilter& rGraphicFilter = GraphicFilter::GetGraphicFilter();
Graphic aInputGraphic = rGraphicFilter.ImportUnloadedGraphic(aStream);
CPPUNIT_ASSERT_EQUAL(sal_uInt32(223),
aInputGraphic.getVectorGraphicData()->getVectorGraphicDataArrayLength());
// Create graphic
Graphic aGraphic(aInputGraphic.getVectorGraphicData());
CPPUNIT_ASSERT_EQUAL(GraphicType::Bitmap, aGraphic.GetType());
CPPUNIT_ASSERT_EQUAL(true, bool(aGraphic.getVectorGraphicData()));
CPPUNIT_ASSERT_EQUAL(true, aGraphic.isAvailable());
CPPUNIT_ASSERT_EQUAL(false, aGraphic.IsGfxLink());
CPPUNIT_ASSERT_EQUAL(false, aGraphic.ImplGetImpGraphic()->isSwappedOut());
// Origin URL
aGraphic.setOriginURL("Origin URL");
CPPUNIT_ASSERT_EQUAL(OUString("Origin URL"), aGraphic.getOriginURL());
// Check size in pixels
CPPUNIT_ASSERT_EQUAL(tools::Long(51), aGraphic.GetSizePixel().Width());
CPPUNIT_ASSERT_EQUAL(tools::Long(51), aGraphic.GetSizePixel().Height());
// Set and check the PrefSize
CPPUNIT_ASSERT_EQUAL(tools::Long(1349), aGraphic.GetPrefSize().Width());
CPPUNIT_ASSERT_EQUAL(tools::Long(1349), aGraphic.GetPrefSize().Height());
aGraphic.SetPrefSize(Size(200, 100));
CPPUNIT_ASSERT_EQUAL(tools::Long(200), aGraphic.GetPrefSize().Width());
CPPUNIT_ASSERT_EQUAL(tools::Long(100), aGraphic.GetPrefSize().Height());
// SWAP OUT the Graphic and make sure it's not available currently
CPPUNIT_ASSERT_EQUAL(true, aGraphic.isAvailable());
CPPUNIT_ASSERT_EQUAL(true, aGraphic.ImplGetImpGraphic()->swapOut());
CPPUNIT_ASSERT_EQUAL(true, aGraphic.ImplGetImpGraphic()->isSwappedOut());
CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable());
CPPUNIT_ASSERT_EQUAL(OUString("Origin URL"), aGraphic.getOriginURL());
CPPUNIT_ASSERT_EQUAL(tools::Long(200), aGraphic.GetPrefSize().Width());
CPPUNIT_ASSERT_EQUAL(tools::Long(100), aGraphic.GetPrefSize().Height());
CPPUNIT_ASSERT_EQUAL(tools::Long(51), aGraphic.GetSizePixel().Width());
CPPUNIT_ASSERT_EQUAL(tools::Long(51), aGraphic.GetSizePixel().Height());
// SWAP IN
CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable());
CPPUNIT_ASSERT_EQUAL(true, aGraphic.makeAvailable());
CPPUNIT_ASSERT_EQUAL(true, aGraphic.isAvailable());
CPPUNIT_ASSERT_EQUAL(false, aGraphic.ImplGetImpGraphic()->isSwappedOut());
CPPUNIT_ASSERT_EQUAL(OUString("Origin URL"), aGraphic.getOriginURL());
CPPUNIT_ASSERT_EQUAL(tools::Long(200), aGraphic.GetPrefSize().Width());
CPPUNIT_ASSERT_EQUAL(tools::Long(100), aGraphic.GetPrefSize().Height());
CPPUNIT_ASSERT_EQUAL(tools::Long(51), aGraphic.GetSizePixel().Width());
CPPUNIT_ASSERT_EQUAL(tools::Long(51), aGraphic.GetSizePixel().Height());
}
void GraphicTest::testSwappingVectorGraphic_PDF_WithGfxLink()
{
test::Directories aDirectories;
OUString aURL = aDirectories.getURLFromSrc(PDFEXPORT_DATA_DIRECTORY) + "SimpleMultiPagePDF.pdf";
@@ -507,6 +915,7 @@ void GraphicTest::testSwappingPageNumber()
// Load the vector graphic
CPPUNIT_ASSERT_EQUAL(true, bool(aGraphic.getVectorGraphicData()));
// Set the page index
aGraphic.getVectorGraphicData()->setPageIndex(1);
@@ -519,12 +928,12 @@ void GraphicTest::testSwappingPageNumber()
CPPUNIT_ASSERT_EQUAL(false, aGraphic.ImplGetImpGraphic()->isSwappedOut());
// Swapping out
// SWAP OUT
CPPUNIT_ASSERT_EQUAL(true, aGraphic.ImplGetImpGraphic()->swapOut());
CPPUNIT_ASSERT_EQUAL(true, aGraphic.ImplGetImpGraphic()->isSwappedOut());
CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable());
// Let's swap in
// SWAP IN
CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable());
CPPUNIT_ASSERT_EQUAL(true, aGraphic.makeAvailable());
CPPUNIT_ASSERT_EQUAL(true, aGraphic.isAvailable());
@@ -533,31 +942,176 @@ void GraphicTest::testSwappingPageNumber()
CPPUNIT_ASSERT_EQUAL(sal_Int32(1), aGraphic.getVectorGraphicData()->getPageIndex());
}
void GraphicTest::testWMFRoundtrip()
void GraphicTest::testSwappingVectorGraphic_PDF_WithoutGfxLink()
{
// Load a WMF file.
test::Directories aDirectories;
OUString aURL = aDirectories.getURLFromSrc("vcl/qa/cppunit/data/roundtrip.wmf");
OUString aURL = aDirectories.getURLFromSrc(PDFEXPORT_DATA_DIRECTORY) + "SimpleMultiPagePDF.pdf";
SvFileStream aStream(aURL, StreamMode::READ);
GraphicFilter& rGraphicFilter = GraphicFilter::GetGraphicFilter();
Graphic aInputGraphic = rGraphicFilter.ImportUnloadedGraphic(aStream);
// Create graphic
Graphic aGraphic(aInputGraphic.getVectorGraphicData());
CPPUNIT_ASSERT_EQUAL(GraphicType::Bitmap, aGraphic.GetType());
CPPUNIT_ASSERT_EQUAL(true, aGraphic.isAvailable());
CPPUNIT_ASSERT_EQUAL(true, bool(aGraphic.getVectorGraphicData()));
// Set the page index
aGraphic.getVectorGraphicData()->setPageIndex(1);
CPPUNIT_ASSERT_EQUAL(VectorGraphicDataType::Pdf,
aGraphic.getVectorGraphicData()->getVectorGraphicDataType());
CPPUNIT_ASSERT_EQUAL(sal_uInt32(17693),
aGraphic.getVectorGraphicData()->getVectorGraphicDataArrayLength());
CPPUNIT_ASSERT_EQUAL(true, aGraphic.isAvailable());
CPPUNIT_ASSERT_EQUAL(sal_Int32(1), aGraphic.getVectorGraphicData()->getPageIndex());
CPPUNIT_ASSERT_EQUAL(false, aGraphic.ImplGetImpGraphic()->isSwappedOut());
// SWAP OUT
CPPUNIT_ASSERT_EQUAL(true, aGraphic.ImplGetImpGraphic()->swapOut());
CPPUNIT_ASSERT_EQUAL(true, aGraphic.ImplGetImpGraphic()->isSwappedOut());
CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable());
// SWAP IN
CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable());
CPPUNIT_ASSERT_EQUAL(true, aGraphic.makeAvailable());
CPPUNIT_ASSERT_EQUAL(true, aGraphic.isAvailable());
CPPUNIT_ASSERT_EQUAL(false, aGraphic.ImplGetImpGraphic()->isSwappedOut());
CPPUNIT_ASSERT_EQUAL(sal_Int32(1), aGraphic.getVectorGraphicData()->getPageIndex());
}
void GraphicTest::testSwappingAnimationGraphic_GIF_WithGfxLink()
{
test::Directories aDirectories;
OUString aURL = aDirectories.getURLFromSrc(DATA_DIRECTORY) + "123_Numbers.gif";
SvFileStream aStream(aURL, StreamMode::READ);
sal_uInt64 nExpectedSize = aStream.TellEnd();
GraphicFilter& rGraphicFilter = GraphicFilter::GetGraphicFilter();
Graphic aGraphic = rGraphicFilter.ImportUnloadedGraphic(aStream);
// Loaded into "prepared" state
// Save as WMF.
utl::TempFile aTempFile;
aTempFile.EnableKillingFile();
sal_uInt16 nFormat = rGraphicFilter.GetExportFormatNumberForShortName(u"WMF");
SvStream& rOutStream = *aTempFile.GetStream(StreamMode::READWRITE);
rGraphicFilter.ExportGraphic(aGraphic, OUString(), rOutStream, nFormat);
// Check that the state is as expected
CPPUNIT_ASSERT_EQUAL(GraphicType::Bitmap, aGraphic.GetType());
CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable());
// Check if we preserved the WMF data perfectly.
sal_uInt64 nActualSize = rOutStream.TellEnd();
CPPUNIT_ASSERT_EQUAL(true, aGraphic.makeAvailable());
CPPUNIT_ASSERT_EQUAL(true, aGraphic.isAvailable());
// Without the accompanying fix in place, this test would have failed with:
// - Expected: 6475
// - Actual : 2826
// i.e. we lost some of the WMF data on roundtrip.
CPPUNIT_ASSERT_EQUAL(nExpectedSize, nActualSize);
CPPUNIT_ASSERT_EQUAL(true, aGraphic.IsGfxLink());
CPPUNIT_ASSERT_EQUAL(tools::Long(124), aGraphic.GetSizePixel().Width());
CPPUNIT_ASSERT_EQUAL(tools::Long(146), aGraphic.GetSizePixel().Height());
CPPUNIT_ASSERT_EQUAL(sal_uInt32(1515), aGraphic.GetGfxLink().GetDataSize());
// Remember checksum so we can compare after swapping back in again
BitmapChecksum aBitmapChecksumBeforeSwapping = aGraphic.GetBitmapEx().GetChecksum();
// Check we are not swapped out yet
CPPUNIT_ASSERT_EQUAL(false, aGraphic.ImplGetImpGraphic()->isSwappedOut());
// Get the declared byte size of the graphic
sal_uLong rByteSize = aGraphic.GetSizeBytes();
CPPUNIT_ASSERT_EQUAL(sal_uLong(50373), rByteSize);
// Make sure we don't have a file
CPPUNIT_ASSERT_EQUAL(true, aGraphic.ImplGetImpGraphic()->getSwapFileURL().isEmpty());
// SWAP OUT the Graphic and make sure it's not available currently
CPPUNIT_ASSERT_EQUAL(true, aGraphic.ImplGetImpGraphic()->swapOut());
CPPUNIT_ASSERT_EQUAL(true, aGraphic.ImplGetImpGraphic()->isSwappedOut());
CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable());
// We use GfxLink so no swap file in this case
CPPUNIT_ASSERT_EQUAL(true, aGraphic.ImplGetImpGraphic()->getSwapFileURL().isEmpty());
// Byte size doesn't change when we swapped out
CPPUNIT_ASSERT_EQUAL(rByteSize, aGraphic.GetSizeBytes());
// SWAP IN
CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable());
CPPUNIT_ASSERT_EQUAL(true, aGraphic.makeAvailable());
CPPUNIT_ASSERT_EQUAL(true, aGraphic.isAvailable());
CPPUNIT_ASSERT_EQUAL(false, aGraphic.ImplGetImpGraphic()->isSwappedOut());
// Compare that the checksum of the bitmap is still the same
CPPUNIT_ASSERT_EQUAL(aBitmapChecksumBeforeSwapping, aGraphic.GetBitmapEx().GetChecksum());
// Byte size shouldn't change
CPPUNIT_ASSERT_EQUAL(rByteSize, aGraphic.GetSizeBytes());
}
void GraphicTest::testSwappingAnimationGraphic_GIF_WithoutGfxLink()
{
test::Directories aDirectories;
OUString aURL = aDirectories.getURLFromSrc(DATA_DIRECTORY) + "123_Numbers.gif";
SvFileStream aStream(aURL, StreamMode::READ);
GraphicFilter& rGraphicFilter = GraphicFilter::GetGraphicFilter();
Graphic aInputGraphic = rGraphicFilter.ImportUnloadedGraphic(aStream);
Graphic aGraphic(aInputGraphic.GetAnimation());
// Check animation graphic
CPPUNIT_ASSERT_EQUAL(GraphicType::Bitmap, aGraphic.GetType());
CPPUNIT_ASSERT_EQUAL(true, aGraphic.makeAvailable());
CPPUNIT_ASSERT_EQUAL(true, aGraphic.isAvailable());
CPPUNIT_ASSERT_EQUAL(true, aGraphic.IsAnimated());
CPPUNIT_ASSERT_EQUAL(tools::Long(124), aGraphic.GetSizePixel().Width());
CPPUNIT_ASSERT_EQUAL(tools::Long(146), aGraphic.GetSizePixel().Height());
CPPUNIT_ASSERT_EQUAL(false, aGraphic.IsGfxLink());
// We loaded the Graphic and made it available
CPPUNIT_ASSERT_EQUAL(false, aGraphic.ImplGetImpGraphic()->isSwappedOut());
// Get the declared byte size of the graphic
sal_uLong rByteSize = aGraphic.GetSizeBytes();
OUString rSwapFileURL = aGraphic.ImplGetImpGraphic()->getSwapFileURL();
CPPUNIT_ASSERT_EQUAL(true, rSwapFileURL.isEmpty());
// SWAP OUT
CPPUNIT_ASSERT_EQUAL(true, aGraphic.isAvailable());
CPPUNIT_ASSERT_EQUAL(true, aGraphic.ImplGetImpGraphic()->swapOut());
CPPUNIT_ASSERT_EQUAL(true, aGraphic.ImplGetImpGraphic()->isSwappedOut());
CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable());
// Byte size doesn't change when we swapped out
CPPUNIT_ASSERT_EQUAL(rByteSize, aGraphic.GetSizeBytes());
// Let's check the swap file
rSwapFileURL = aGraphic.ImplGetImpGraphic()->getSwapFileURL();
CPPUNIT_ASSERT_EQUAL(true, comphelper::DirectoryHelper::fileExists(rSwapFileURL));
{
// Check the swap file content
std::unique_ptr<SvStream> xStream = createStream(rSwapFileURL);
CPPUNIT_ASSERT_EQUAL(true, bool(xStream));
// Check size of the stream
CPPUNIT_ASSERT_EQUAL(sal_uInt64(15183), xStream->remainingSize());
std::vector<unsigned char> aHash = calculateHash(xStream);
CPPUNIT_ASSERT_EQUAL(std::string("deb13fdf0ffa0b58ce92fff0a6ca9e98c5d26ed9"),
toHexString(aHash));
}
// SWAP IN
CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable());
CPPUNIT_ASSERT_EQUAL(true, aGraphic.makeAvailable());
CPPUNIT_ASSERT_EQUAL(true, aGraphic.isAvailable());
CPPUNIT_ASSERT_EQUAL(false, aGraphic.ImplGetImpGraphic()->isSwappedOut());
// File shouldn't be available anymore
CPPUNIT_ASSERT_EQUAL(false, comphelper::DirectoryHelper::fileExists(rSwapFileURL));
// Check the bitmap
CPPUNIT_ASSERT_EQUAL(tools::Long(124), aGraphic.GetSizePixel().Width());
CPPUNIT_ASSERT_EQUAL(tools::Long(146), aGraphic.GetSizePixel().Height());
// Byte size is still the same
CPPUNIT_ASSERT_EQUAL(rByteSize, aGraphic.GetSizeBytes());
}
} // namespace

View File

@@ -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)

View File

@@ -50,23 +50,9 @@
#define GRAPHIC_MTFTOBMP_MAXEXT 2048
#define GRAPHIC_STREAMBUFSIZE 8192UL
#define SYS_WINMETAFILE 0x00000003L
#define SYS_WNTMETAFILE 0x00000004L
#define SYS_OS2METAFILE 0x00000005L
#define SYS_MACMETAFILE 0x00000006L
#define GRAPHIC_FORMAT_50 COMPAT_FORMAT( 'G', 'R', 'F', '5' )
#define SWAP_FORMAT_ID COMPAT_FORMAT( 'S', 'W', 'A', 'P' )
#define NATIVE_FORMAT_50 COMPAT_FORMAT( 'N', 'A', 'T', '5' )
namespace {
constexpr sal_uInt32 constSvgMagic((sal_uInt32('s') << 24) | (sal_uInt32('v') << 16) | (sal_uInt32('g') << 8) | sal_uInt32('0'));
constexpr sal_uInt32 constWmfMagic((sal_uInt32('w') << 24) | (sal_uInt32('m') << 16) | (sal_uInt32('f') << 8) | sal_uInt32('0'));
constexpr sal_uInt32 constEmfMagic((sal_uInt32('e') << 24) | (sal_uInt32('m') << 16) | (sal_uInt32('f') << 8) | sal_uInt32('0'));
constexpr sal_uInt32 constPdfMagic((sal_uInt32('s') << 24) | (sal_uInt32('v') << 16) | (sal_uInt32('g') << 8) | sal_uInt32('0'));
}
using namespace com::sun::star;
class ImpSwapFile : public vcl::SwapFile
@@ -348,6 +334,7 @@ void ImpGraphic::createSwapInfo()
if (isSwappedOut())
return;
maSwapInfo.maSizePixel = ImplGetSizePixel();
maSwapInfo.maPrefMapMode = ImplGetPrefMapMode();
maSwapInfo.maPrefSize = ImplGetPrefSize();
maSwapInfo.mbIsAnimated = ImplIsAnimated();
@@ -363,7 +350,6 @@ void ImpGraphic::ImplClearGraphics()
maBitmapEx.Clear();
maMetaFile.Clear();
mpAnimation.reset();
mpGfxLink.reset();
maVectorGraphicData.reset();
}
@@ -1121,107 +1107,32 @@ bool ImpGraphic::swapInContent(SvStream& rStream)
{
bool bRet = false;
ensureAvailable();
MapMode aMapMode;
Size aSize;
sal_uInt32 nId;
sal_Int32 nType;
sal_Int32 nPageIndex = -1;
const SvStreamEndian nOldFormat = rStream.GetEndian();
sal_Int32 nLength;
rStream.SetEndian(SvStreamEndian::LITTLE);
rStream.ReadUInt32(nId);
// check version
if (GRAPHIC_FORMAT_50 != nId)
if (SWAP_FORMAT_ID != nId)
{
SAL_WARN("vcl", "Incompatible swap file!");
return false;
// read new style header
VersionCompat aCompat(rStream, StreamMode::READ);
}
rStream.ReadInt32(nType);
sal_Int32 nLen;
rStream.ReadInt32(nLen);
TypeSerializer aSerializer(rStream);
aSerializer.readSize(aSize);
ReadMapMode(rStream, aMapMode);
if (aCompat.GetVersion() >= 2)
{
rStream.ReadInt32(nPageIndex);
}
rStream.ReadInt32(nLength);
meType = static_cast<GraphicType>(nType);
if( meType != GraphicType::NONE )
if (meType == GraphicType::NONE || meType == GraphicType::Default)
{
if( meType == GraphicType::Bitmap )
{
if(maVectorGraphicData && maBitmapEx.IsEmpty())
{
// use maBitmapEx as local buffer for rendered svg
maBitmapEx = getVectorGraphicReplacement();
}
maBitmapEx.SetSizePixel(aSize);
if( aMapMode != MapMode() )
{
maBitmapEx.SetPrefMapMode( aMapMode );
maBitmapEx.SetPrefSize( aSize );
}
}
else
{
maMetaFile.SetPrefMapMode( aMapMode );
maMetaFile.SetPrefSize( aSize );
}
if( meType == GraphicType::Bitmap || meType == GraphicType::GdiMetafile )
{
swapInGraphic(rStream);
bRet = rStream.GetError() == ERRCODE_NONE;
}
else if( sal::static_int_cast<sal_uLong>(meType) >= SYS_WINMETAFILE
&& sal::static_int_cast<sal_uLong>(meType) <= SYS_MACMETAFILE )
{
Graphic aSysGraphic;
ConvertDataFormat nCvtType;
switch( sal::static_int_cast<sal_uLong>(meType) )
{
case SYS_WINMETAFILE:
case SYS_WNTMETAFILE: nCvtType = ConvertDataFormat::WMF; break;
case SYS_OS2METAFILE: nCvtType = ConvertDataFormat::MET; break;
case SYS_MACMETAFILE: nCvtType = ConvertDataFormat::PCT; break;
default:
nCvtType = ConvertDataFormat::Unknown;
break;
}
if( nType && GraphicConverter::Import(rStream, aSysGraphic, nCvtType) == ERRCODE_NONE )
{
*this = ImpGraphic( aSysGraphic.GetGDIMetaFile() );
bRet = rStream.GetError() == ERRCODE_NONE;
}
else
meType = GraphicType::Default;
}
if (bRet)
{
ImplSetPrefMapMode( aMapMode );
ImplSetPrefSize( aSize );
if (maVectorGraphicData)
maVectorGraphicData->setPageIndex(nPageIndex);
}
return true;
}
else
bRet = true;
rStream.SetEndian(nOldFormat);
{
bRet = swapInGraphic(rStream);
}
return bRet;
}
@@ -1239,149 +1150,111 @@ bool ImpGraphic::swapOutGraphic(SvStream& rStream)
return false;
}
if (rStream.GetVersion() >= SOFFICE_FILEFORMAT_50 &&
rStream.GetCompressMode() & SvStreamCompressFlags::NATIVE &&
mpGfxLink && mpGfxLink->IsNative())
switch (meType)
{
// native format
rStream.WriteUInt32(NATIVE_FORMAT_50);
// write compat info, destructor writes stuff into the header
case GraphicType::GdiMetafile:
{
VersionCompat aCompat(rStream, StreamMode::WRITE, 1);
WriteGDIMetaFile(rStream, maMetaFile);
}
mpGfxLink->SetPrefMapMode(ImplGetPrefMapMode());
mpGfxLink->SetPrefSize(ImplGetPrefSize());
TypeSerializer aSerializer(rStream);
aSerializer.writeGfxLink(*mpGfxLink);
}
else
{
switch (ImplGetType())
{
case GraphicType::NONE:
case GraphicType::Default:
break;
break;
case GraphicType::Bitmap:
case GraphicType::Bitmap:
{
if (maVectorGraphicData)
{
if (getVectorGraphicData())
rStream.WriteInt32(sal_Int32(GraphicContentType::Vector));
// stream out Vector Graphic defining data (length, byte array and evtl. path)
// this is used e.g. in swapping out graphic data and in transporting it over UNO API
// as sequence of bytes, but AFAIK not written anywhere to any kind of file, so it should be
// no problem to extend it; only used at runtime
switch (maVectorGraphicData->getVectorGraphicDataType())
{
// stream out Vector Graphic defining data (length, byte array and evtl. path)
// this is used e.g. in swapping out graphic data and in transporting it over UNO API
// as sequence of bytes, but AFAIK not written anywhere to any kind of file, so it should be
// no problem to extend it; only used at runtime
switch (getVectorGraphicData()->getVectorGraphicDataType())
case VectorGraphicDataType::Wmf:
{
case VectorGraphicDataType::Wmf:
{
rStream.WriteUInt32(constWmfMagic);
break;
}
case VectorGraphicDataType::Emf:
{
rStream.WriteUInt32(constEmfMagic);
break;
}
case VectorGraphicDataType::Svg:
{
rStream.WriteUInt32(constSvgMagic);
break;
}
case VectorGraphicDataType::Pdf:
{
rStream.WriteUInt32(constPdfMagic);
break;
}
rStream.WriteUInt32(constWmfMagic);
break;
}
case VectorGraphicDataType::Emf:
{
rStream.WriteUInt32(constEmfMagic);
break;
}
case VectorGraphicDataType::Svg:
{
rStream.WriteUInt32(constSvgMagic);
break;
}
case VectorGraphicDataType::Pdf:
{
rStream.WriteUInt32(constPdfMagic);
break;
}
}
rStream.WriteUInt32(getVectorGraphicData()->getVectorGraphicDataArrayLength());
rStream.WriteBytes(
getVectorGraphicData()->getVectorGraphicDataArray().getConstArray(),
getVectorGraphicData()->getVectorGraphicDataArrayLength());
rStream.WriteUniOrByteString(getVectorGraphicData()->getPath(), rStream.GetStreamCharSet());
}
else if (ImplIsAnimated())
{
WriteAnimation(rStream, *mpAnimation);
}
else
{
WriteDIBBitmapEx(maBitmapEx, rStream);
}
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<sal_Int32>(meType));
// write new style header
{
VersionCompat aCompat(rOStm, StreamMode::WRITE, 2);
rOStm.WriteInt32(static_cast<sal_Int32>(meType));
// data size is updated later
nDataFieldPos = rOStm.Tell();
rOStm.WriteInt32(0);
TypeSerializer aSerializer(rOStm);
aSerializer.writeSize(aSize);
WriteMapMode(rOStm, aMapMode);
// Version 2
rOStm.WriteInt32(getPageNumber());
}
bool bRet = false;
// data size is updated later
nDataFieldPos = rStream.Tell();
rStream.WriteInt32(0);
// write data block
if (!rOStm.GetError())
const sal_uLong nDataStart = 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<ImpSwapFile>(aTempFileURL, getOriginURL());
bool bResult = false;
// Open a stream to write the swap file to
// We have GfxLink so we have the source available
if (mpGfxLink && mpGfxLink->IsNative())
{
std::unique_ptr<SvStream> xOutputStream = pSwapFile->openOutputStream();
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<ImpSwapFile>(aTempFileURL, getOriginURL());
// Open a stream to write the swap file to
{
std::unique_ptr<SvStream> xOutputStream = pSwapFile->openOutputStream();
if (!xOutputStream)
return false;
// Write to stream
xOutputStream->SetVersion(SOFFICE_FILEFORMAT_50);
xOutputStream->SetCompressMode(SvStreamCompressFlags::NATIVE);
xOutputStream->SetBufferSize(GRAPHIC_STREAMBUFSIZE);
if (!xOutputStream->GetError() && swapOutContent(*xOutputStream))
{
xOutputStream->Flush();
bResult = !xOutputStream->GetError();
}
}
// Check if writing was successful
if (bResult)
{
// We have swapped out, so can clean memory and prepare swap info
createSwapInfo();
ImplClearGraphics();
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<ImpGraphic*>(this);
bool bResult = true;
if (isSwappedOut())
return pThis->swapIn();
bResult = pThis->swapIn();
pThis->maLastUsed = std::chrono::high_resolution_clock::now();
return true;
return bResult;
}
bool ImpGraphic::loadPrepared()
@@ -1470,30 +1366,95 @@ void ImpGraphic::updateFromLoadedGraphic(ImpGraphic* graphic)
maGraphicExternalLink = aLink;
}
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<BitmapEx&>(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<Animation>(*rImpGraphic.mpAnimation);
maBitmapEx = mpAnimation->GetBitmapEx();
}
else
{
maBitmapEx = rImpGraphic.maBitmapEx;
}
maMetaFile = rImpGraphic.maMetaFile;
maVectorGraphicData = rImpGraphic.maVectorGraphicData;
// Set to 0, to force recalculation
mnSizeBytes = 0;
mnChecksum = 0;
restoreFromSwapInfo();
maLastUsed = std::chrono::high_resolution_clock::now();
mbSwapOut = false;
bReturn = true;
}
else
{
OUString aSwapURL;
if( mpSwapFile )
aSwapURL = mpSwapFile->getSwapURL().GetMainURL( INetURLObject::DecodeMechanism::NONE );
if (mpSwapFile)
aSwapURL = mpSwapFile->getSwapURL().GetMainURL(INetURLObject::DecodeMechanism::NONE);
if( !aSwapURL.isEmpty() )
if (!aSwapURL.isEmpty())
{
std::unique_ptr<SvStream> xStream;
try
{
xStream = ::utl::UcbStreamHelper::CreateStream( aSwapURL, StreamMode::READWRITE | StreamMode::SHARE_DENYWRITE );
xStream = ::utl::UcbStreamHelper::CreateStream(aSwapURL, StreamMode::READWRITE | StreamMode::SHARE_DENYWRITE);
}
catch( const css::uno::Exception& )
{
@@ -1501,51 +1462,43 @@ bool ImpGraphic::swapIn()
if (xStream)
{
xStream->SetVersion( SOFFICE_FILEFORMAT_50 );
xStream->SetCompressMode( SvStreamCompressFlags::NATIVE );
xStream->SetVersion(SOFFICE_FILEFORMAT_50);
xStream->SetCompressMode(SvStreamCompressFlags::NATIVE);
xStream->SetBufferSize(GRAPHIC_STREAMBUFSIZE);
bReturn = swapInFromStream(*xStream);
bRet = swapInFromStream(*xStream);
xStream.reset();
restoreFromSwapInfo();
if (mpSwapFile)
setOriginURL(mpSwapFile->getOriginURL());
mpSwapFile.reset();
}
}
}
if (bRet)
if (bReturn)
vcl::graphic::Manager::get().swappedIn(this);
return bRet;
return bReturn;
}
bool ImpGraphic::swapInFromStream(SvStream& rStream)
{
bool bRet = false;
rStream.SetBufferSize(GRAPHIC_STREAMBUFSIZE);
if (rStream.GetError())
return false;
//keep the swap file alive, because its quite possibly the backing storage
//for xIStm
std::shared_ptr<ImpSwapFile> xSwapFile(std::move(mpSwapFile));
assert(!mpSwapFile);
std::shared_ptr<GraphicReader> xContext(std::move(mpContext));
assert(!mpContext);
bool bDummyContext = mbDummyContext;
mbDummyContext = false;
ImplClearGraphics();
mnSizeBytes = 0;
mnChecksum = 0;
bRet = swapInContent(rStream);
//restore ownership of the swap file and context
mpSwapFile = std::move(xSwapFile);
mpContext = std::move(xContext);
mbDummyContext = bDummyContext;
if (!bRet)
{
//throw away swapfile, etc.
@@ -1557,165 +1510,116 @@ bool ImpGraphic::swapInFromStream(SvStream& rStream)
return bRet;
}
void ImpGraphic::swapInGraphic(SvStream& rStream)
bool ImpGraphic::swapInGraphic(SvStream& rStream)
{
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<GraphicContentType>(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<GfxLink>());
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<GfxLink>(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<Animation>();
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<Animation>();
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<VectorGraphicData>(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<GfxLink>& rGfxLink)