From 38da870731123d8ad97b62f95c61ec8c1257d9a9 Mon Sep 17 00:00:00 2001 From: Miklos Vajna Date: Mon, 17 Jan 2022 11:47:14 +0100 Subject: 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 Reviewed-by: Mike Kaganski --- 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(-) create mode 100644 filter/qa/unit/data/custom-bullet.fodp (limited to 'filter') 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 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + hello + + + + + + + + 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 xStorable(getComponent(), uno::UNO_QUERY_THROW); + SvMemoryStream aStream; + uno::Reference 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 '', 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 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 ); - // + if (mrExport.IsEmbeddedBulletGlyph(rInfo.cBulletChar)) { + // // 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 + { + // + 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; -- cgit