diff options
Diffstat (limited to 'filter/qa/unit/svg.cxx')
-rw-r--r-- | filter/qa/unit/svg.cxx | 277 |
1 files changed, 190 insertions, 87 deletions
diff --git a/filter/qa/unit/svg.cxx b/filter/qa/unit/svg.cxx index 3e3508fd52ca..82dc3832e1b8 100644 --- a/filter/qa/unit/svg.cxx +++ b/filter/qa/unit/svg.cxx @@ -9,56 +9,34 @@ #include <sal/config.h> -#include <string_view> +#include <test/unoapixml_test.hxx> -#include <test/bootstrapfixture.hxx> -#include <unotest/macros_test.hxx> -#include <test/xmltesttools.hxx> - -#include <com/sun/star/frame/Desktop.hpp> #include <com/sun/star/frame/XStorable.hpp> #include <com/sun/star/io/XOutputStream.hpp> +#include <com/sun/star/drawing/XShape.hpp> +#include <com/sun/star/drawing/XDrawPagesSupplier.hpp> +#include <com/sun/star/text/XTextRange.hpp> +#include <com/sun/star/text/ControlCharacter.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> + +#include <comphelper/propertyvalue.hxx> #include <unotools/streamwrap.hxx> #include <unotools/mediadescriptor.hxx> #include <tools/stream.hxx> using namespace ::com::sun::star; -constexpr OUStringLiteral DATA_DIRECTORY = u"/filter/qa/unit/data/"; - /// SVG filter tests. -class SvgFilterTest : public test::BootstrapFixture, public unotest::MacrosTest, public XmlTestTools +class SvgFilterTest : public UnoApiXmlTest { -private: - uno::Reference<lang::XComponent> mxComponent; - public: - void setUp() override; - void tearDown() override; + SvgFilterTest(); void registerNamespaces(xmlXPathContextPtr& pXmlXpathCtx) override; - uno::Reference<lang::XComponent>& getComponent() { return mxComponent; } - void load(std::u16string_view rURL); }; -void SvgFilterTest::setUp() +SvgFilterTest::SvgFilterTest() + : UnoApiXmlTest("/filter/qa/unit/data/") { - test::BootstrapFixture::setUp(); - - mxDesktop.set(frame::Desktop::create(mxComponentContext)); -} - -void SvgFilterTest::tearDown() -{ - if (mxComponent.is()) - mxComponent->dispose(); - - test::BootstrapFixture::tearDown(); -} - -void SvgFilterTest::load(std::u16string_view rFileName) -{ - OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + rFileName; - mxComponent = loadFromDesktop(aURL); } void SvgFilterTest::registerNamespaces(xmlXPathContextPtr& pXmlXpathCtx) @@ -68,27 +46,23 @@ void SvgFilterTest::registerNamespaces(xmlXPathContextPtr& pXmlXpathCtx) CPPUNIT_TEST_FIXTURE(SvgFilterTest, testPreserveJpg) { -#if !defined(MACOSX) +// On Windows, SVGFilter::filterWriterOrCalc can't get current frame to obtain selection +#if !defined(MACOSX) && !defined(_WIN32) // Load a document with a jpeg image in it. - load(u"preserve-jpg.odt"); + loadFromFile(u"preserve-jpg.odt"); // Select the image. - dispatchCommand(getComponent(), ".uno:JumpToNextFrame", {}); + dispatchCommand(mxComponent, ".uno:JumpToNextFrame", {}); // Export the selection to SVG. - uno::Reference<frame::XStorable> xStorable(getComponent(), uno::UNO_QUERY_THROW); - SvMemoryStream aStream; - uno::Reference<io::XOutputStream> xOut = new utl::OOutputStreamWrapper(aStream); - utl::MediaDescriptor aMediaDescriptor; - aMediaDescriptor["FilterName"] <<= OUString("writer_svg_Export"); - aMediaDescriptor["SelectionOnly"] <<= true; - aMediaDescriptor["OutputStream"] <<= xOut; - xStorable->storeToURL("private:stream", aMediaDescriptor.getAsConstPropertyValueList()); - aStream.Seek(STREAM_SEEK_TO_BEGIN); + saveWithParams({ + comphelper::makePropertyValue("FilterName", u"writer_svg_Export"_ustr), + comphelper::makePropertyValue("SelectionOnly", true), + }); // Make sure that the original JPG data is reused and we don't perform a PNG re-compress. - xmlDocUniquePtr pXmlDoc = parseXmlStream(&aStream); - OUString aAttributeValue = getXPath(pXmlDoc, "//svg:image", "href"); + xmlDocUniquePtr pXmlDoc = parseExportedFile(); + OUString aAttributeValue = getXPath(pXmlDoc, "//svg:image"_ostr, "href"_ostr); // Without the accompanying fix in place, this test would have failed with: // - Expression: aAttributeValue.startsWith("data:image/jpeg") @@ -101,22 +75,15 @@ CPPUNIT_TEST_FIXTURE(SvgFilterTest, testPreserveJpg) CPPUNIT_TEST_FIXTURE(SvgFilterTest, testSemiTransparentLine) { // Load a document with a semi-transparent line shape. - load(u"semi-transparent-line.odg"); + loadFromFile(u"semi-transparent-line.odg"); // Export it to SVG. - uno::Reference<frame::XStorable> xStorable(getComponent(), uno::UNO_QUERY_THROW); - SvMemoryStream aStream; - uno::Reference<io::XOutputStream> xOut = new utl::OOutputStreamWrapper(aStream); - utl::MediaDescriptor aMediaDescriptor; - aMediaDescriptor["FilterName"] <<= OUString("draw_svg_Export"); - aMediaDescriptor["OutputStream"] <<= xOut; - xStorable->storeToURL("private:stream", aMediaDescriptor.getAsConstPropertyValueList()); - aStream.Seek(STREAM_SEEK_TO_BEGIN); + save("draw_svg_Export"); // Get the style of the group around the actual <path> element. - xmlDocUniquePtr pXmlDoc = parseXmlStream(&aStream); + xmlDocUniquePtr pXmlDoc = parseExportedFile(); OUString aStyle = getXPath( - pXmlDoc, "//svg:g[@class='com.sun.star.drawing.LineShape']/svg:g/svg:g", "style"); + pXmlDoc, "//svg:g[@class='com.sun.star.drawing.LineShape']/svg:g/svg:g"_ostr, "style"_ostr); // Without the accompanying fix in place, this test would have failed, as the style was // "mask:url(#mask1)", not "opacity: <value>". CPPUNIT_ASSERT(aStyle.startsWith("opacity: ", &aStyle)); @@ -125,6 +92,33 @@ CPPUNIT_TEST_FIXTURE(SvgFilterTest, testSemiTransparentLine) CPPUNIT_ASSERT_EQUAL(30, nPercent); } +CPPUNIT_TEST_FIXTURE(SvgFilterTest, testSemiTransparentFillWithTransparentLine) +{ + // Load a document with a shape with semi-transparent fill and line + loadFromFile(u"semi-transparent-fill.odg"); + + // Export it to SVG. + save("draw_svg_Export"); + + // Get the style of the group around the actual <path> element. + xmlDocUniquePtr pXmlDoc = parseExportedFile(); + OUString aStyle + = getXPath(pXmlDoc, "//svg:g[@class='com.sun.star.drawing.EllipseShape']/svg:g/svg:g"_ostr, + "style"_ostr); + CPPUNIT_ASSERT(aStyle.startsWith("opacity: ", &aStyle)); + int nPercent = std::round(aStyle.toDouble() * 100); + // Make sure that the line is still 50% opaque + CPPUNIT_ASSERT_EQUAL(50, nPercent); + + // Get the stroke of the fill of the EllipseShape (it must be "none") + OUString aStroke = getXPath( + pXmlDoc, "//svg:g[@class='com.sun.star.drawing.EllipseShape']/svg:g/svg:path"_ostr, + "stroke"_ostr); + // Without the accompanying fix in place, this test would have failed, as the stroke was + // "rgb(255,255,255)", not "none". + CPPUNIT_ASSERT_EQUAL(OUString("none"), aStroke); +} + CPPUNIT_TEST_FIXTURE(SvgFilterTest, testSemiTransparentText) { // Two shapes, one with transparent text and the other one with @@ -132,21 +126,12 @@ CPPUNIT_TEST_FIXTURE(SvgFilterTest, testSemiTransparentText) // correct transparency factor applied for the first shape. // Load draw document with transparent text in one box - load(u"TransparentText.odg"); + loadFromFile(u"TransparentText.odg"); // Export to SVG. - uno::Reference<frame::XStorable> xStorable(getComponent(), uno::UNO_QUERY_THROW); - - SvMemoryStream aStream; - uno::Reference<io::XOutputStream> xOut = new utl::OOutputStreamWrapper(aStream); - utl::MediaDescriptor aMediaDescriptor; - aMediaDescriptor["FilterName"] <<= OUString("draw_svg_Export"); - aMediaDescriptor["OutputStream"] <<= xOut; - xStorable->storeToURL("private:stream", aMediaDescriptor.getAsConstPropertyValueList()); - aStream.Seek(STREAM_SEEK_TO_BEGIN); - - xmlDocUniquePtr pXmlDoc = parseXmlStream(&aStream); + save("draw_svg_Export"); + xmlDocUniquePtr pXmlDoc = parseExportedFile(); // We expect 2 groups of class "TextShape" that // have some svg:text node inside. // Without the accompanying fix in place, this test would have failed with: @@ -154,22 +139,66 @@ CPPUNIT_TEST_FIXTURE(SvgFilterTest, testSemiTransparentText) // - Actual : 1 // i.e. the 2nd shape lots its text. - assertXPath(pXmlDoc, "//svg:g[@class='TextShape']//svg:text", 2); + assertXPath(pXmlDoc, "//svg:g[@class='TextShape']//svg:text"_ostr, 2); // First shape has semi-transparent text. - assertXPath(pXmlDoc, "//svg:text[1]/svg:tspan/svg:tspan/svg:tspan[@fill-opacity='0.8']"); + assertXPath(pXmlDoc, "//svg:text[1]/svg:tspan/svg:tspan/svg:tspan[@fill-opacity='0.8']"_ostr); // Second shape has normal text. - assertXPath(pXmlDoc, "//svg:text[2]/svg:tspan/svg:tspan/svg:tspan[@fill-opacity]", 0); + assertXPath(pXmlDoc, "//svg:text[2]/svg:tspan/svg:tspan/svg:tspan[@fill-opacity]"_ostr, 0); +} + +CPPUNIT_TEST_FIXTURE(SvgFilterTest, testSemiTransparentMultiParaText) +{ + // Given a shape with semi-transparent, multi-paragraph text: + mxComponent + = loadFromDesktop("private:factory/simpress", "com.sun.star.drawing.DrawingDocument"); + uno::Reference<lang::XMultiServiceFactory> xFactory(mxComponent, uno::UNO_QUERY); + uno::Reference<drawing::XShape> xShape( + xFactory->createInstance("com.sun.star.drawing.TextShape"), uno::UNO_QUERY); + uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(mxComponent, uno::UNO_QUERY); + uno::Reference<drawing::XShapes> xDrawPage(xDrawPagesSupplier->getDrawPages()->getByIndex(0), + uno::UNO_QUERY); + xDrawPage->add(xShape); + xShape->setSize(awt::Size(10000, 10000)); + uno::Reference<text::XSimpleText> xShapeText(xShape, uno::UNO_QUERY); + uno::Reference<text::XTextCursor> xCursor = xShapeText->createTextCursor(); + xShapeText->insertString(xCursor, "foo", /*bAbsorb=*/false); + xShapeText->insertControlCharacter(xCursor, text::ControlCharacter::APPEND_PARAGRAPH, + /*bAbsorb=*/false); + xShapeText->insertString(xCursor, "bar", /*bAbsorb=*/false); + uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY); + xShapeProps->setPropertyValue("CharColor", uno::Any(static_cast<sal_Int32>(0xff0000))); + xShapeProps->setPropertyValue("CharTransparence", uno::Any(static_cast<sal_Int16>(20))); + + // When exporting to SVG: + save("draw_svg_Export"); + + // Then make sure that the two semi-transparent paragraphs have the same X position: + xmlDocUniquePtr pXmlDoc = parseExportedFile(); + assertXPath(pXmlDoc, "(//svg:g[@class='TextShape']//svg:tspan[@class='TextPosition'])[1]"_ostr, + "x"_ostr, "250"); + assertXPath(pXmlDoc, + "(//svg:g[@class='TextShape']//svg:tspan[@class='TextPosition'])[1]/svg:tspan"_ostr, + "fill-opacity"_ostr, "0.8"); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 250 + // - Actual : 8819 + // i.e. the X position of the second paragraph was wrong. + assertXPath(pXmlDoc, "(//svg:g[@class='TextShape']//svg:tspan[@class='TextPosition'])[2]"_ostr, + "x"_ostr, "250"); + assertXPath(pXmlDoc, + "(//svg:g[@class='TextShape']//svg:tspan[@class='TextPosition'])[2]/svg:tspan"_ostr, + "fill-opacity"_ostr, "0.8"); } CPPUNIT_TEST_FIXTURE(SvgFilterTest, testShapeNographic) { // Load a document containing a 3D shape. - load(u"shape-nographic.odp"); + loadFromFile(u"shape-nographic.odp"); // Export to SVG. - uno::Reference<frame::XStorable> xStorable(getComponent(), uno::UNO_QUERY_THROW); + uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY_THROW); SvMemoryStream aStream; uno::Reference<io::XOutputStream> xOut = new utl::OOutputStreamWrapper(aStream); utl::MediaDescriptor aMediaDescriptor; @@ -185,20 +214,13 @@ CPPUNIT_TEST_FIXTURE(SvgFilterTest, testShapeNographic) CPPUNIT_TEST_FIXTURE(SvgFilterTest, testCustomBullet) { // Given a presentation with a custom bullet: - load(u"custom-bullet.fodp"); + loadFromFile(u"custom-bullet.fodp"); // When exporting that to SVG: - uno::Reference<frame::XStorable> xStorable(getComponent(), uno::UNO_QUERY_THROW); - SvMemoryStream aStream; - uno::Reference<io::XOutputStream> xOut = new utl::OOutputStreamWrapper(aStream); - utl::MediaDescriptor aMediaDescriptor; - aMediaDescriptor["FilterName"] <<= OUString("impress_svg_Export"); - aMediaDescriptor["OutputStream"] <<= xOut; - xStorable->storeToURL("private:stream", aMediaDescriptor.getAsConstPropertyValueList()); + save("impress_svg_Export"); // Then make sure the bullet glyph is not lost: - aStream.Seek(STREAM_SEEK_TO_BEGIN); - xmlDocUniquePtr pXmlDoc = parseXmlStream(&aStream); + xmlDocUniquePtr pXmlDoc = parseExportedFile(); // Without the accompanying fix in place, this test would have failed with: // - Expected: 1 // - Actual : 0 @@ -206,7 +228,88 @@ CPPUNIT_TEST_FIXTURE(SvgFilterTest, testCustomBullet) // i.e. the custom bullet used '<use transform="scale(285,285)" // xlink:href="#bullet-char-template-45"/>', but nobody produced a bullet-char-template-45, // instead we need the path of the glyph inline. - CPPUNIT_ASSERT(!getXPath(pXmlDoc, "//svg:g[@class='BulletChars']//svg:path", "d").isEmpty()); + CPPUNIT_ASSERT( + !getXPath(pXmlDoc, "//svg:g[@class='BulletChars']//svg:path"_ostr, "d"_ostr).isEmpty()); +} + +CPPUNIT_TEST_FIXTURE(SvgFilterTest, attributeRedefinedTest) +{ + // Load document containing empty paragraphs with ids. + loadFromFile(u"attributeRedefinedTest.odp"); + + // Export to SVG. + save("impress_svg_Export"); + + xmlDocUniquePtr pXmlDoc = parseExportedFile(); + // We expect four paragraph + // 2 empty paragraphs with ids + // 2 paragraphs with text + // Without the accompanying fix the test would have failed with + // Expected : 4 + // Actual : 2 + // i.e. 2 of the empty paragraph do not get generated even if there + // is id imported for the paragraphs + // If we don't create the empty paragraphs the id attribute gets redefined like this: + // <tspan id="id14" id="id15" id="id17" class="TextParagraph" font-family="Bahnschrift Light" font-size="1129px" font-weight="400"> + + OString xPath = "//svg:g[@class='TextShape']//svg:text[@class='SVGTextShape']//" + "svg:tspan[@class='TextParagraph']"_ostr; + assertXPath(pXmlDoc, xPath, 4); + + //assert that each tspan element with TextParagraph class has id and the tspan element of + //each empty paragraph does not contain tspan element with class TextPosition + assertXPath(pXmlDoc, xPath + "[1]", "id"_ostr, "id4"); + assertXPath(pXmlDoc, xPath + "[2]", "id"_ostr, "id5"); + assertXPath(pXmlDoc, xPath + "[2]//svg:tspan[@class='TextPosition']", 0); + assertXPath(pXmlDoc, xPath + "[3]", "id"_ostr, "id6"); + assertXPath(pXmlDoc, xPath + "[3]//svg:tspan[@class='TextPosition']", 0); + assertXPath(pXmlDoc, xPath + "[4]", "id"_ostr, "id7"); +} + +CPPUNIT_TEST_FIXTURE(SvgFilterTest, testTab) +{ + // Given a shape with "A\tB" text: + mxComponent = loadFromDesktop("private:factory/simpress", + "com.sun.star.presentation.PresentationDocument"); + uno::Reference<lang::XMultiServiceFactory> xFactory(mxComponent, uno::UNO_QUERY); + uno::Reference<drawing::XShape> xShape( + xFactory->createInstance("com.sun.star.drawing.TextShape"), uno::UNO_QUERY); + uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(mxComponent, uno::UNO_QUERY); + uno::Reference<drawing::XShapes> xDrawPage(xDrawPagesSupplier->getDrawPages()->getByIndex(0), + uno::UNO_QUERY); + xDrawPage->add(xShape); + xShape->setSize(awt::Size(10000, 10000)); + uno::Reference<text::XTextRange> xShapeText(xShape, uno::UNO_QUERY); + xShapeText->setString("A\tB"); + + // When exporting that document to SVG: + save("impress_svg_Export"); + + // Then make sure the tab is not lost: + xmlDocUniquePtr pXmlDoc = parseExportedFile(); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 2 + // - Actual : 1 + // i.e. the 2nd text portion was not positioned, which looked as if the tab is lost. + assertXPath(pXmlDoc, "//svg:g[@class='TextShape']//svg:tspan[@class='TextPosition']"_ostr, 2); +} + +CPPUNIT_TEST_FIXTURE(SvgFilterTest, textInImage) +{ + // Load document containing empty paragraphs with ids. + loadFromFile(u"text-in-image.odp"); + + // Export to SVG. + save("impress_svg_Export"); + + xmlDocUniquePtr pXmlDoc = parseExportedFile(); + + // We expect the Graphic to have an image and a text + assertXPath(pXmlDoc, "//svg:g[@class='Graphic']//svg:image"_ostr, 1); + assertXPath(pXmlDoc, "//svg:g[@class='Graphic']//svg:text"_ostr, 1); + // Without the accompanying fix, this test would have failed with: + // - Expected: 1 + // - Actual : 0 } CPPUNIT_PLUGIN_IMPLEMENT(); |