filter/qa/unit/data/custom-bullet.fodp |   36 +++++++++++++++++++++++++++++++++
 filter/qa/unit/svg.cxx                 |   27 ++++++++++++++++++++++++
 filter/source/svg/svgexport.cxx        |   12 +++++++++++
 filter/source/svg/svgfilter.hxx        |    4 +++
 filter/source/svg/svgwriter.cxx        |   24 ++++++++++++++++++----
 filter/source/svg/svgwriter.hxx        |    2 -
 6 files changed, 100 insertions(+), 5 deletions(-)

New commits:
commit bbc4360b5beb012adf1e2652328d3e18d66224aa
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Mon Jan 17 11:47:14 2022 +0100
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Mon Jan 17 13:23:57 2022 +0100

    SVG export: fix missing custom bullets
    
    It seems this was broken since b76628acb1ae4fc06f8c1b70ec2e0cf39356deef
    (text export support for bullets and hyperlinks, 2012-08-11), the
    problem is that SVGFilter::implEmbedBulletGlyphs() has a fixed list of
    characters that are typically used as bullets, but e.g. "-" is missing
    from that list.
    
    Fix this by improving SVGTextWriter::implWriteBulletChars() to continue
    working from those shared glyph paths when the glyph is in the fixed
    list, but otherwise call GetTextOutline() to look up the path for the
    custom bullet.
    
    Change-Id: I3de8fab8dc6c78e273629d13566d1f9f289eb752
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/128495
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>
    Tested-by: Jenkins

diff --git a/filter/qa/unit/data/custom-bullet.fodp 
b/filter/qa/unit/data/custom-bullet.fodp
new file mode 100644
index 000000000000..4139260f9780
--- /dev/null
+++ b/filter/qa/unit/data/custom-bullet.fodp
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<office:document 
xmlns:presentation="urn:oasis:names:tc:opendocument:xmlns:presentation:1.0" 
xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" 
xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" 
xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" 
xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" 
xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" 
xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" 
office:version="1.3" 
office:mimetype="application/vnd.oasis.opendocument.presentation">
+  <office:automatic-styles>
+    <style:page-layout style:name="PM1">
+      <style:page-layout-properties fo:margin-top="0cm" fo:margin-bottom="0cm" 
fo:margin-left="0cm" fo:margin-right="0cm" fo:page-width="28cm" 
fo:page-height="15.75cm" style:print-orientation="landscape"/>
+    </style:page-layout>
+    <style:style style:name="gr1" style:family="graphic" 
style:parent-style-name="standard">
+      <style:graphic-properties draw:stroke="none" svg:stroke-color="#000000" 
draw:fill="none" draw:fill-color="#ffffff" draw:auto-grow-height="true" 
draw:auto-grow-width="false" fo:max-height="0cm" fo:min-height="0cm"/>
+    </style:style>
+    <text:list-style style:name="L1">
+      <text:list-level-style-bullet text:level="1" text:bullet-char="-">
+        <style:list-level-properties text:min-label-width="0.6cm"/>
+        <style:text-properties fo:font-family="OpenSymbol" 
style:font-style-name="Regular" style:font-charset="x-symbol" 
style:use-window-font-color="true" fo:font-size="45%"/>
+      </text:list-level-style-bullet>
+    </text:list-style>
+  </office:automatic-styles>
+  <office:master-styles>
+    <style:master-page style:name="Default" style:page-layout-name="PM1">
+    </style:master-page>
+  </office:master-styles>
+  <office:body>
+    <office:presentation>
+      <draw:page draw:name="page1" draw:master-page-name="Default">
+        <draw:frame draw:style-name="gr1" draw:text-style-name="P8" 
draw:layer="layout" svg:width="9.525cm" svg:height="0.962cm" svg:x="3.175cm" 
svg:y="2.54cm">
+          <draw:text-box>
+            <text:list text:style-name="L1">
+              <text:list-item>
+                <text:p>hello</text:p>
+              </text:list-item>
+            </text:list>
+          </draw:text-box>
+        </draw:frame>
+      </draw:page>
+    </office:presentation>
+  </office:body>
+</office:document>
diff --git a/filter/qa/unit/svg.cxx b/filter/qa/unit/svg.cxx
index e1b54fb2a294..3e3508fd52ca 100644
--- a/filter/qa/unit/svg.cxx
+++ b/filter/qa/unit/svg.cxx
@@ -182,6 +182,33 @@ CPPUNIT_TEST_FIXTURE(SvgFilterTest, testShapeNographic)
     xStorable->storeToURL("private:stream", 
aMediaDescriptor.getAsConstPropertyValueList());
 }
 
+CPPUNIT_TEST_FIXTURE(SvgFilterTest, testCustomBullet)
+{
+    // Given a presentation with a custom bullet:
+    load(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());
+
+    // Then make sure the bullet glyph is not lost:
+    aStream.Seek(STREAM_SEEK_TO_BEGIN);
+    xmlDocUniquePtr pXmlDoc = parseXmlStream(&aStream);
+    // Without the accompanying fix in place, this test would have failed with:
+    // - Expected: 1
+    // - Actual  : 0
+    // - XPath '//svg:g[@class='BulletChars']//svg:path' number of nodes is 
incorrect
+    // 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_PLUGIN_IMPLEMENT();
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/filter/source/svg/svgexport.cxx b/filter/source/svg/svgexport.cxx
index 170b2cf1437b..ef0c1ea37a80 100644
--- a/filter/source/svg/svgexport.cxx
+++ b/filter/source/svg/svgexport.cxx
@@ -1524,6 +1524,7 @@ void SVGFilter::implEmbedBulletGlyph( sal_Unicode 
cBullet, const OUString & sPat
     mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "d", sPathData );
     SvXMLElementExport aPathElem( *mpSVGExport, XML_NAMESPACE_NONE, "path", 
true, true );
 
+    mpSVGExport->SetEmbeddedBulletGlyph(cBullet);
 }
 
 void SVGFilter::implExportBackgroundBitmaps()
@@ -2858,4 +2859,15 @@ void SVGExport::writeMtf( const GDIMetaFile& rMtf )
     }
 }
 
+void SVGExport::SetEmbeddedBulletGlyph(sal_Unicode cBullet)
+{
+    maEmbeddedBulletGlyphs.insert(cBullet);
+}
+
+bool SVGExport::IsEmbeddedBulletGlyph(sal_Unicode cBullet) const
+{
+    auto it = maEmbeddedBulletGlyphs.find(cBullet);
+    return it != maEmbeddedBulletGlyphs.end();
+}
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/filter/source/svg/svgfilter.hxx b/filter/source/svg/svgfilter.hxx
index 1a8796bd9046..eb889e81662e 100644
--- a/filter/source/svg/svgfilter.hxx
+++ b/filter/source/svg/svgfilter.hxx
@@ -66,6 +66,7 @@ class SVGExport : public SvXMLExport
     bool    mbIsUseOpacity;
     bool    mbIsUseNativeTextDecoration;
     bool    mbIsUsePositionedCharacters;
+    std::set<sal_Unicode> maEmbeddedBulletGlyphs;
 
 public:
 
@@ -84,6 +85,9 @@ public:
 
     void writeMtf( const GDIMetaFile& rMtf );
 
+    void SetEmbeddedBulletGlyph(sal_Unicode cBullet);
+    bool IsEmbeddedBulletGlyph(sal_Unicode cBullet) const;
+
 protected:
 
     virtual void            ExportStyles_( bool /* bUsed */ ) override {}
diff --git a/filter/source/svg/svgwriter.cxx b/filter/source/svg/svgwriter.cxx
index a9dcfccbb627..e066806cea9a 100644
--- a/filter/source/svg/svgwriter.cxx
+++ b/filter/source/svg/svgwriter.cxx
@@ -1416,11 +1416,12 @@ void SVGTextWriter::implWriteBulletChars()
 
             SvXMLElementExport aPositioningElem( mrExport, XML_NAMESPACE_NONE, 
aXMLElemG, true, true );
 
-            // <use transform="scale(font-size)" xlink:ref="/" >
+            if (mrExport.IsEmbeddedBulletGlyph(rInfo.cBulletChar))
             {
+                // <use transform="scale(font-size)" xlink:ref="/" >
                 // Add size attribute through a scaling
-                sScaling = "scale(" + OUString::number( rInfo.nFontSize ) +
-                           "," + OUString::number( rInfo.nFontSize )+ ")";
+                sScaling = "scale(" + OUString::number( 
rInfo.aFont.GetFontHeight() ) +
+                           "," + OUString::number( rInfo.aFont.GetFontHeight() 
)+ ")";
                 mrExport.AddAttribute( XML_NAMESPACE_NONE, "transform", 
sScaling );
 
                 // Add ref attribute
@@ -1430,6 +1431,21 @@ void SVGTextWriter::implWriteBulletChars()
 
                 SvXMLElementExport aRefElem( mrExport, XML_NAMESPACE_NONE, 
"use", true, true );
             }
+            else
+            {
+                // <path d="...">
+                tools::PolyPolygon aPolyPolygon;
+                OUString aStr(rInfo.cBulletChar);
+                mpVDev->Push(vcl::PushFlags::FONT);
+                mpVDev->SetFont(rInfo.aFont);
+                if (mpVDev->GetTextOutline(aPolyPolygon, aStr))
+                {
+                    OUString 
aPathString(SVGActionWriter::GetPathString(aPolyPolygon, false));
+                    mrExport.AddAttribute(XML_NAMESPACE_NONE, "d", 
aPathString);
+                    SvXMLElementExport aPath(mrExport, XML_NAMESPACE_NONE, 
"path", true, true);
+                }
+                mpVDev->Pop();
+            }
         } // close aPositioningElem
     }
 
@@ -1684,7 +1700,7 @@ void SVGTextWriter::implWriteTextPortion( const Point& 
rPos,
             {
                 sId += ".bp";
                 BulletListItemInfo& aBulletListItemInfo = maBulletListItemMap[ 
sId ];
-                aBulletListItemInfo.nFontSize = rFont.GetFontHeight();
+                aBulletListItemInfo.aFont = rFont;
                 aBulletListItemInfo.aColor = aTextColor;
                 aBulletListItemInfo.aPos = maTextPos;
                 aBulletListItemInfo.cBulletChar = mcBulletChar;
diff --git a/filter/source/svg/svgwriter.hxx b/filter/source/svg/svgwriter.hxx
index 9fe8a698c85e..fdfcd24d32b2 100644
--- a/filter/source/svg/svgwriter.hxx
+++ b/filter/source/svg/svgwriter.hxx
@@ -188,7 +188,7 @@ class GDIMetaFile;
 
 struct BulletListItemInfo
 {
-    tools::Long nFontSize;
+    vcl::Font aFont;
     Color aColor;
     Point aPos;
     sal_Unicode cBulletChar;

Reply via email to