Bump version to 21.06.18.1
[LibreOffice.git] / filter / qa / unit / svg.cxx
blob31c8076637a8842a0080b8607ceb8b354e55279d
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 */
10 #include <test/bootstrapfixture.hxx>
11 #include <unotest/macros_test.hxx>
12 #include <test/xmltesttools.hxx>
14 #include <com/sun/star/frame/Desktop.hpp>
15 #include <com/sun/star/frame/XStorable.hpp>
16 #include <com/sun/star/io/XOutputStream.hpp>
17 #include <unotools/streamwrap.hxx>
18 #include <unotools/mediadescriptor.hxx>
19 #include <tools/stream.hxx>
21 using namespace ::com::sun::star;
23 char const DATA_DIRECTORY[] = "/filter/qa/unit/data/";
25 /// SVG filter tests.
26 class SvgFilterTest : public test::BootstrapFixture, public unotest::MacrosTest, public XmlTestTools
28 private:
29 uno::Reference<lang::XComponent> mxComponent;
31 public:
32 void setUp() override;
33 void tearDown() override;
34 void registerNamespaces(xmlXPathContextPtr& pXmlXpathCtx) override;
35 uno::Reference<lang::XComponent>& getComponent() { return mxComponent; }
36 void load(const OUString& rURL);
39 void SvgFilterTest::setUp()
41 test::BootstrapFixture::setUp();
43 mxDesktop.set(frame::Desktop::create(mxComponentContext));
46 void SvgFilterTest::tearDown()
48 if (mxComponent.is())
49 mxComponent->dispose();
51 test::BootstrapFixture::tearDown();
54 void SvgFilterTest::load(const OUString& rFileName)
56 OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + rFileName;
57 mxComponent = loadFromDesktop(aURL);
60 void SvgFilterTest::registerNamespaces(xmlXPathContextPtr& pXmlXpathCtx)
62 xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("svg"), BAD_CAST("http://www.w3.org/2000/svg"));
65 CPPUNIT_TEST_FIXTURE(SvgFilterTest, testPreserveJpg)
67 #if !defined(MACOSX)
68 // Load a document with a jpeg image in it.
69 load("preserve-jpg.odt");
71 // Select the image.
72 dispatchCommand(getComponent(), ".uno:JumpToNextFrame", {});
74 // Export the selection to SVG.
75 uno::Reference<frame::XStorable> xStorable(getComponent(), uno::UNO_QUERY_THROW);
76 SvMemoryStream aStream;
77 uno::Reference<io::XOutputStream> xOut = new utl::OOutputStreamWrapper(aStream);
78 utl::MediaDescriptor aMediaDescriptor;
79 aMediaDescriptor["FilterName"] <<= OUString("writer_svg_Export");
80 aMediaDescriptor["SelectionOnly"] <<= true;
81 aMediaDescriptor["OutputStream"] <<= xOut;
82 xStorable->storeToURL("private:stream", aMediaDescriptor.getAsConstPropertyValueList());
83 aStream.Seek(STREAM_SEEK_TO_BEGIN);
85 // Make sure that the original JPG data is reused and we don't perform a PNG re-compress.
86 xmlDocUniquePtr pXmlDoc = parseXmlStream(&aStream);
87 OUString aAttributeValue = getXPath(pXmlDoc, "//svg:image", "href");
89 // Without the accompanying fix in place, this test would have failed with:
90 // - Expression: aAttributeValue.startsWith("data:image/jpeg")
91 // i.e. the SVG export result re-compressed the image as PNG, even if the original and the
92 // transformed image is the same, so there is no need for that.
93 CPPUNIT_ASSERT(aAttributeValue.startsWith("data:image/jpeg"));
94 #endif
97 CPPUNIT_TEST_FIXTURE(SvgFilterTest, testSemiTransparentLine)
99 // Load a document with a semi-transparent line shape.
100 load("semi-transparent-line.odg");
102 // Export it to SVG.
103 uno::Reference<frame::XStorable> xStorable(getComponent(), uno::UNO_QUERY_THROW);
104 SvMemoryStream aStream;
105 uno::Reference<io::XOutputStream> xOut = new utl::OOutputStreamWrapper(aStream);
106 utl::MediaDescriptor aMediaDescriptor;
107 aMediaDescriptor["FilterName"] <<= OUString("draw_svg_Export");
108 aMediaDescriptor["OutputStream"] <<= xOut;
109 xStorable->storeToURL("private:stream", aMediaDescriptor.getAsConstPropertyValueList());
110 aStream.Seek(STREAM_SEEK_TO_BEGIN);
112 // Get the style of the group around the actual <path> element.
113 xmlDocUniquePtr pXmlDoc = parseXmlStream(&aStream);
114 OUString aStyle = getXPath(
115 pXmlDoc, "//svg:g[@class='com.sun.star.drawing.LineShape']/svg:g/svg:g", "style");
116 OUString aPrefix("opacity: ");
117 // Without the accompanying fix in place, this test would have failed, as the style was
118 // "mask:url(#mask1)", not "opacity: <value>".
119 CPPUNIT_ASSERT(aStyle.startsWith(aPrefix));
120 int nPercent = std::round(aStyle.copy(aPrefix.getLength()).toDouble() * 100);
121 // Make sure that the line is still 30% opaque, rather than completely invisible.
122 CPPUNIT_ASSERT_EQUAL(30, nPercent);
125 CPPUNIT_TEST_FIXTURE(SvgFilterTest, testSemiTransparentText)
127 // Two shapes, one with transparent text and the other one with
128 // opaque text. We expect both to be exported to the SVG with the
129 // correct transparency factor applied for the first shape.
131 // Load draw document with transparent text in one box
132 load("TransparentText.odg");
134 // Export to SVG.
135 uno::Reference<frame::XStorable> xStorable(getComponent(), uno::UNO_QUERY_THROW);
137 SvMemoryStream aStream;
138 uno::Reference<io::XOutputStream> xOut = new utl::OOutputStreamWrapper(aStream);
139 utl::MediaDescriptor aMediaDescriptor;
140 aMediaDescriptor["FilterName"] <<= OUString("draw_svg_Export");
141 aMediaDescriptor["OutputStream"] <<= xOut;
142 xStorable->storeToURL("private:stream", aMediaDescriptor.getAsConstPropertyValueList());
143 aStream.Seek(STREAM_SEEK_TO_BEGIN);
145 xmlDocUniquePtr pXmlDoc = parseXmlStream(&aStream);
147 // We expect 2 groups of class "TextShape" that
148 // have some svg:text node inside.
149 // Without the accompanying fix in place, this test would have failed with:
150 // - Expected: 2
151 // - Actual : 1
152 // i.e. the 2nd shape lots its text.
154 assertXPath(pXmlDoc, "//svg:g[@class='TextShape']//svg:text", 2);
156 // First shape has semi-transparent text.
157 assertXPath(pXmlDoc, "//svg:text[1]/svg:tspan/svg:tspan/svg:tspan[@fill-opacity='0.8']");
159 // Second shape has normal text.
160 assertXPath(pXmlDoc, "//svg:text[2]/svg:tspan/svg:tspan/svg:tspan[@fill-opacity]", 0);
163 CPPUNIT_TEST_FIXTURE(SvgFilterTest, testShapeNographic)
165 // Load a document containing a 3D shape.
166 load("shape-nographic.odp");
168 // Export to SVG.
169 uno::Reference<frame::XStorable> xStorable(getComponent(), uno::UNO_QUERY_THROW);
170 SvMemoryStream aStream;
171 uno::Reference<io::XOutputStream> xOut = new utl::OOutputStreamWrapper(aStream);
172 utl::MediaDescriptor aMediaDescriptor;
173 aMediaDescriptor["FilterName"] <<= OUString("impress_svg_Export");
174 aMediaDescriptor["OutputStream"] <<= xOut;
176 // Without the accompanying fix in place, this test would have failed with:
177 // An uncaught exception of type com.sun.star.io.IOException
178 // - SfxBaseModel::impl_store <private:stream> failed: 0xc10(Error Area:Io Class:Write Code:16)
179 xStorable->storeToURL("private:stream", aMediaDescriptor.getAsConstPropertyValueList());
182 CPPUNIT_TEST_FIXTURE(SvgFilterTest, testCustomBullet)
184 // Given a presentation with a custom bullet:
185 load(u"custom-bullet.fodp");
187 // When exporting that to SVG:
188 uno::Reference<frame::XStorable> xStorable(getComponent(), uno::UNO_QUERY_THROW);
189 SvMemoryStream aStream;
190 uno::Reference<io::XOutputStream> xOut = new utl::OOutputStreamWrapper(aStream);
191 utl::MediaDescriptor aMediaDescriptor;
192 aMediaDescriptor["FilterName"] <<= OUString("impress_svg_Export");
193 aMediaDescriptor["OutputStream"] <<= xOut;
194 xStorable->storeToURL("private:stream", aMediaDescriptor.getAsConstPropertyValueList());
196 // Then make sure the bullet glyph is not lost:
197 aStream.Seek(STREAM_SEEK_TO_BEGIN);
198 xmlDocUniquePtr pXmlDoc = parseXmlStream(&aStream);
199 // Without the accompanying fix in place, this test would have failed with:
200 // - Expected: 1
201 // - Actual : 0
202 // - XPath '//svg:g[@class='BulletChars']//svg:path' number of nodes is incorrect
203 // i.e. the custom bullet used '<use transform="scale(285,285)"
204 // xlink:href="#bullet-char-template-45"/>', but nobody produced a bullet-char-template-45,
205 // instead we need the path of the glyph inline.
206 CPPUNIT_ASSERT(!getXPath(pXmlDoc, "//svg:g[@class='BulletChars']//svg:path", "d").isEmpty());
209 CPPUNIT_TEST_FIXTURE(SvgFilterTest, attributeRedefinedTest)
211 // Load document containing empty paragraphs with ids.
212 load("attributeRedefinedTest.odp");
214 // Export to SVG.
215 uno::Reference<frame::XStorable> xStorable(getComponent(), uno::UNO_QUERY_THROW);
216 SvMemoryStream aStream;
217 uno::Reference<io::XOutputStream> xOut = new utl::OOutputStreamWrapper(aStream);
218 utl::MediaDescriptor aMediaDescriptor;
219 aMediaDescriptor["FilterName"] <<= OUString("impress_svg_Export");
220 aMediaDescriptor["OutputStream"] <<= xOut;
221 xStorable->storeToURL("private:stream", aMediaDescriptor.getAsConstPropertyValueList());
222 aStream.Seek(STREAM_SEEK_TO_BEGIN);
224 xmlDocUniquePtr pXmlDoc = parseXmlStream(&aStream);
226 // We expect four paragraph
227 // 2 empty paragraphs with ids
228 // 2 paragraphs with text
229 // Without the accompanying fix the test would have failed with
230 // Expected : 4
231 // Actual : 2
232 // i.e. 2 of the empty paragraph do not get generated even if there
233 // is id imported for the paragraphs
234 // If we don't create the empty paragraphs the id attribute attribute gets redefined like this:
235 // <tspan id="id14" id="id15" id="id17" class="TextParagraph" font-family="Bahnschrift Light" font-size="1129px" font-weight="400">
237 OString xPath = "//svg:g[@class='TextShape']//svg:text[@class='SVGTextShape']//"
238 "svg:tspan[@class='TextParagraph']";
239 assertXPath(pXmlDoc, xPath, 4);
241 //assert that each tspan element with TextParagraph class has id and the tspan element of
242 //each empty paragraph doesnot contain tspan element with class TextPosition
243 assertXPath(pXmlDoc, xPath + "[1]", "id", "id4");
244 assertXPath(pXmlDoc, xPath + "[2]", "id", "id5");
245 assertXPath(pXmlDoc, xPath + "[2]//svg:tspan[@class='TextPosition']", 0);
246 assertXPath(pXmlDoc, xPath + "[3]", "id", "id6");
247 assertXPath(pXmlDoc, xPath + "[3]//svg:tspan[@class='TextPosition']", 0);
248 assertXPath(pXmlDoc, xPath + "[4]", "id", "id7");
251 CPPUNIT_PLUGIN_IMPLEMENT();
253 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */