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 38da870731123d8ad97b62f95c61ec8c1257d9a9 Author: Miklos Vajna <[email protected]> AuthorDate: Mon Jan 17 11:47:14 2022 +0100 Commit: Mike Kaganski <[email protected]> CommitDate: Tue Jan 18 08:20:36 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. (cherry picked from commit bbc4360b5beb012adf1e2652328d3e18d66224aa) Change-Id: I3de8fab8dc6c78e273629d13566d1f9f289eb752 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/128501 Tested-by: Jenkins CollaboraOffice <[email protected]> Reviewed-by: Mike Kaganski <[email protected]> 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 bb7600d71626..8f03e7120d75 100644 --- a/filter/qa/unit/svg.cxx +++ b/filter/qa/unit/svg.cxx @@ -179,6 +179,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 2c8130667c6b..fc8de3b18f68 100644 --- a/filter/source/svg/svgexport.cxx +++ b/filter/source/svg/svgexport.cxx @@ -1531,6 +1531,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() @@ -2865,4 +2866,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 7bdaa9d60f09..aab158971e0b 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 57ccc67bf6ef..866594439abc 100644 --- a/filter/source/svg/svgwriter.cxx +++ b/filter/source/svg/svgwriter.cxx @@ -1428,11 +1428,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 @@ -1442,6 +1443,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(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 } @@ -1696,7 +1712,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 993d1162fcf3..a052fba16e87 100644 --- a/filter/source/svg/svgwriter.hxx +++ b/filter/source/svg/svgwriter.hxx @@ -189,7 +189,7 @@ class GDIMetaFile; struct BulletListItemInfo { - tools::Long nFontSize; + vcl::Font aFont; Color aColor; Point aPos; sal_Unicode cBulletChar;
