summaryrefslogtreecommitdiffstats
path: root/filter/qa/unit/svg.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'filter/qa/unit/svg.cxx')
-rw-r--r--filter/qa/unit/svg.cxx277
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();