[Libreoffice-commits] core.git: Branch 'distro/vector/vector-5.4' - 2 commits - filter/CppunitTest_filter_svg.mk filter/Module_filter.mk filter/qa filter/source

Miklos Vajna (via logerrit) logerrit at kemper.freedesktop.org
Thu Apr 9 15:24:21 UTC 2020


 filter/CppunitTest_filter_svg.mk              |   47 ++++++++++++
 filter/Module_filter.mk                       |    1 
 filter/qa/unit/data/semi-transparent-line.odg |binary
 filter/qa/unit/svg.cxx                        |   98 ++++++++++++++++++++++++++
 filter/source/svg/svgwriter.cxx               |   58 +++++++++------
 5 files changed, 183 insertions(+), 21 deletions(-)

New commits:
commit ece101f273111cf8d259a46d8cbffedce40b5736
Author:     Miklos Vajna <vmiklos at collabora.com>
AuthorDate: Wed Apr 8 17:47:24 2020 +0200
Commit:     Miklos Vajna <vmiklos at collabora.com>
CommitDate: Thu Apr 9 14:29:24 2020 +0200

    SVG export: fix lost semi-transparent line shapes
    
    The line shape itself didn't really have a height, rather it had a
    stroke. For some reason, the SVG mask then decides that nothing has to
    be painted there, so unless the line is entirely opaque, the line shape
    gets lost on export.
    
    Fix the problem by handling transparency similar to the PDF export,
    which detects if the whole purpose of the transparency gradient is to
    pass around a transparency percentage. We don't need a mask in that
    case, we can just use opacity as described at e.g.
    <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/opacity>.
    
    (cherry picked from commit ea52d24b5a19bb54f91cd679a977332ec330880d)
    
    Conflicts:
            filter/qa/unit/svg.cxx
            test/source/xmltesttools.cxx
    
    Change-Id: I0355b9b09b6dd48bbacc5b7cc54fb71866304ef1

diff --git a/filter/CppunitTest_filter_svg.mk b/filter/CppunitTest_filter_svg.mk
new file mode 100644
index 000000000000..ec0841929f3f
--- /dev/null
+++ b/filter/CppunitTest_filter_svg.mk
@@ -0,0 +1,47 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#*************************************************************************
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+#*************************************************************************
+
+$(eval $(call gb_CppunitTest_CppunitTest,filter_svg))
+
+$(eval $(call gb_CppunitTest_use_externals,filter_svg,\
+	boost_headers \
+	libxml2 \
+))
+
+$(eval $(call gb_CppunitTest_add_exception_objects,filter_svg, \
+    filter/qa/unit/svg \
+))
+
+$(eval $(call gb_CppunitTest_use_libraries,filter_svg, \
+    comphelper \
+    cppu \
+    cppuhelper \
+    sal \
+    test \
+    unotest \
+    utl \
+    tl \
+))
+
+$(eval $(call gb_CppunitTest_use_sdk_api,filter_svg))
+
+$(eval $(call gb_CppunitTest_use_ure,filter_svg))
+$(eval $(call gb_CppunitTest_use_vcl,filter_svg))
+
+$(eval $(call gb_CppunitTest_use_rdb,filter_svg,services))
+
+$(eval $(call gb_CppunitTest_use_custom_headers,filter_svg,\
+	officecfg/registry \
+))
+
+$(eval $(call gb_CppunitTest_use_configuration,filter_svg))
+
+# vim: set noet sw=4 ts=4:
diff --git a/filter/Module_filter.mk b/filter/Module_filter.mk
index 5b329ef62f33..a16fb5d51ac4 100644
--- a/filter/Module_filter.mk
+++ b/filter/Module_filter.mk
@@ -76,6 +76,7 @@ $(eval $(call gb_Module_add_check_targets,filter,\
     CppunitTest_filter_ras_test \
     CppunitTest_filter_tiff_test \
     CppunitTest_filter_tga_test \
+    CppunitTest_filter_svg \
 ))
 endif
 
diff --git a/filter/qa/unit/data/semi-transparent-line.odg b/filter/qa/unit/data/semi-transparent-line.odg
new file mode 100644
index 000000000000..2d28a694cea5
Binary files /dev/null and b/filter/qa/unit/data/semi-transparent-line.odg differ
diff --git a/filter/qa/unit/svg.cxx b/filter/qa/unit/svg.cxx
new file mode 100644
index 000000000000..ee582d52e982
--- /dev/null
+++ b/filter/qa/unit/svg.cxx
@@ -0,0 +1,98 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <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 <unotools/streamwrap.hxx>
+#include <unotools/mediadescriptor.hxx>
+#include <tools/stream.hxx>
+#include <comphelper/processfactory.hxx>
+
+using namespace ::com::sun::star;
+
+char const DATA_DIRECTORY[] = "/filter/qa/unit/data/";
+
+/// SVG filter tests.
+class SvgFilterTest : public test::BootstrapFixture, public unotest::MacrosTest, public XmlTestTools
+{
+private:
+    uno::Reference<lang::XComponent> mxComponent;
+
+public:
+    void setUp() override;
+    void tearDown() override;
+    void registerNamespaces(xmlXPathContextPtr& pXmlXpathCtx) override;
+    uno::Reference<lang::XComponent>& getComponent() { return mxComponent; }
+    void load(const OUString& rURL);
+};
+
+void SvgFilterTest::setUp()
+{
+    test::BootstrapFixture::setUp();
+
+    uno::Reference<uno::XComponentContext> xComponentContext
+        = comphelper::getComponentContext(getMultiServiceFactory());
+    mxDesktop.set(frame::Desktop::create(xComponentContext));
+}
+
+void SvgFilterTest::tearDown()
+{
+    if (mxComponent.is())
+        mxComponent->dispose();
+
+    test::BootstrapFixture::tearDown();
+}
+
+void SvgFilterTest::load(const OUString& rFileName)
+{
+    OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + rFileName;
+    mxComponent = loadFromDesktop(aURL);
+}
+
+void SvgFilterTest::registerNamespaces(xmlXPathContextPtr& pXmlXpathCtx)
+{
+    xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("svg"), BAD_CAST("http://www.w3.org/2000/svg"));
+}
+
+CPPUNIT_TEST_FIXTURE(SvgFilterTest, testSemiTransparentLine)
+{
+    // Load a document with a semi-transparent line shape.
+    load("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);
+
+    // Get the style of the group around the actual <path> element.
+    xmlDocPtr pXmlDoc = parseXmlStream(&aStream);
+    OUString aStyle = getXPath(
+        pXmlDoc, "//svg:g[@class='com.sun.star.drawing.LineShape']/svg:g/svg:g", "style");
+    OUString aPrefix("opacity: ");
+    // 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(aPrefix));
+    int nPercent = std::round(aStyle.copy(aPrefix.getLength()).toDouble() * 100);
+    // Make sure that the line is still 30% opaque, rather than completely invisible.
+    CPPUNIT_ASSERT_EQUAL(30, nPercent);
+}
+
+CPPUNIT_PLUGIN_IMPLEMENT();
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/filter/source/svg/svgwriter.cxx b/filter/source/svg/svgwriter.cxx
index ed932633cb96..148b1ca42bb2 100644
--- a/filter/source/svg/svgwriter.cxx
+++ b/filter/source/svg/svgwriter.cxx
@@ -2408,32 +2408,43 @@ void SVGActionWriter::ImplWriteMask( GDIMetaFile& rMtf,
     if( nMoveX || nMoveY )
         rMtf.Move( nMoveX, nMoveY );
 
-    OUString aMaskId = "mask" + OUString::number( mnCurMaskId++ );
-
+    OUString aStyle;
+    if (rGradient.GetStartColor() == rGradient.GetEndColor())
     {
-        SvXMLElementExport aElemDefs( mrExport, XML_NAMESPACE_NONE, aXMLElemDefs, true, true );
+        // Special case: constant alpha value.
+        const Color& rColor = rGradient.GetStartColor();
+        const double fOpacity = 1.0 - static_cast<double>(rColor.GetLuminance()) / 255;
+        aStyle = "opacity: " + OUString::number(fOpacity);
+    }
+    else
+    {
+        OUString aMaskId = "mask" + OUString::number(mnCurMaskId++);
 
-        mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrId, aMaskId );
         {
-            SvXMLElementExport aElemMask( mrExport, XML_NAMESPACE_NONE, "mask", true, true );
+            SvXMLElementExport aElemDefs(mrExport, XML_NAMESPACE_NONE, aXMLElemDefs, true, true);
 
-            const tools::PolyPolygon aPolyPolygon( tools::PolyPolygon( tools::Rectangle( rDestPt, rDestSize ) ) );
-            Gradient aGradient( rGradient );
+            mrExport.AddAttribute(XML_NAMESPACE_NONE, aXMLAttrId, aMaskId);
+            {
+                SvXMLElementExport aElemMask(mrExport, XML_NAMESPACE_NONE, "mask", true, true);
 
-            // swap gradient stops to adopt SVG mask
-            Color aTmpColor( aGradient.GetStartColor() );
-            sal_uInt16 nTmpIntensity( aGradient.GetStartIntensity() );
-            aGradient.SetStartColor( aGradient.GetEndColor() );
-            aGradient.SetStartIntensity( aGradient.GetEndIntensity() ) ;
-            aGradient.SetEndColor( aTmpColor );
-            aGradient.SetEndIntensity( nTmpIntensity );
+                const tools::PolyPolygon aPolyPolygon(tools::PolyPolygon(tools::Rectangle(rDestPt, rDestSize)));
+                Gradient aGradient(rGradient);
 
-            ImplWriteGradientEx( aPolyPolygon, aGradient, nWriteFlags );
+                // swap gradient stops to adopt SVG mask
+                Color aTmpColor(aGradient.GetStartColor());
+                sal_uInt16 nTmpIntensity(aGradient.GetStartIntensity());
+                aGradient.SetStartColor(aGradient.GetEndColor());
+                aGradient.SetStartIntensity(aGradient.GetEndIntensity());
+                aGradient.SetEndColor(aTmpColor);
+                aGradient.SetEndIntensity(nTmpIntensity);
+
+                ImplWriteGradientEx(aPolyPolygon, aGradient, nWriteFlags);
+            }
         }
-    }
 
-    OUString aMaskStyle = "mask:url(#" + aMaskId + ")";
-    mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrStyle, aMaskStyle );
+        aStyle = "mask:url(#" + aMaskId + ")";
+    }
+    mrExport.AddAttribute(XML_NAMESPACE_NONE, aXMLAttrStyle, aStyle);
 
     {
         SvXMLElementExport aElemG( mrExport, XML_NAMESPACE_NONE, aXMLElemG, true, true );
commit 2b044c9466458d2b2ee33e6aa5806251841613a2
Author:     Marco Cecchetti <marco.cecchetti at collabora.com>
AuthorDate: Mon May 22 12:57:38 2017 +0200
Commit:     Miklos Vajna <vmiklos at collabora.com>
CommitDate: Thu Apr 9 14:29:24 2020 +0200

    tdf#107998 - svg export: shapes are uncorrect both in Draw and Impress
    
    Start Draw, draw a rectangle, export it to a SVG document.
    
    Open the SVG document with a browser or Inkscape: instead of a
    rectangle, you will see a self-crossing polygon.
    
    This issue is due to a clean up commit
    (9d8c206ee4a5c130e11a4e786b4286f3362f9ca1) about string concatenation
    which has not taken into account that operations are performed from
    right to left.
    
    Change-Id: Ib1c0d872b6bd95abe98bb5e22ef69f6b2d5c163b
    Reviewed-on: https://gerrit.libreoffice.org/37899
    Reviewed-by: Jan Holesovsky <kendy at collabora.com>
    Tested-by: Jan Holesovsky <kendy at collabora.com>
    (cherry picked from commit 877b605bf519f20179e5de1beb5bb16cd431aa89)

diff --git a/filter/source/svg/svgwriter.cxx b/filter/source/svg/svgwriter.cxx
index 927cda90f33a..ed932633cb96 100644
--- a/filter/source/svg/svgwriter.cxx
+++ b/filter/source/svg/svgwriter.cxx
@@ -1816,8 +1816,9 @@ OUString SVGActionWriter::GetPathString( const tools::PolyPolygon& rPolyPoly, bo
 
         if( nSize > 1 )
         {
+            aPolyPoint = rPoly[ 0 ];
             aPathData += "M "
-                        + OUString::number( ( aPolyPoint = rPoly[ 0 ] ).X() )
+                        + OUString::number( aPolyPoint.X() )
                         + aComma
                         + OUString::number( aPolyPoint.Y() );
 
@@ -1838,7 +1839,9 @@ OUString SVGActionWriter::GetPathString( const tools::PolyPolygon& rPolyPoly, bo
                     {
                         if ( j )
                             aPathData += aBlank;
-                        aPathData += OUString::number( ( aPolyPoint = rPoly[ n++ ] ).X() )
+
+                        aPolyPoint = rPoly[ n++ ];
+                        aPathData += OUString::number( aPolyPoint.X() )
                                     + aComma
                                     + OUString::number( aPolyPoint.Y() );
                     }
@@ -1850,7 +1853,9 @@ OUString SVGActionWriter::GetPathString( const tools::PolyPolygon& rPolyPoly, bo
                         nCurrentMode = 'L';
                         aPathData += "L ";
                     }
-                    aPathData += OUString::number( ( aPolyPoint = rPoly[ n++ ] ).X() )
+
+                    aPolyPoint = rPoly[ n++ ];
+                    aPathData += OUString::number( aPolyPoint.X() )
                                 + aComma
                                 + OUString::number( aPolyPoint.Y() );
                 }


More information about the Libreoffice-commits mailing list