[Libreoffice-commits] core.git: Branch 'distro/vector/vector-5.4' - 2 commits - filter/qa filter/source
Miklos Vajna (via logerrit)
logerrit at kemper.freedesktop.org
Fri Jul 17 15:32:07 UTC 2020
filter/qa/unit/data/TransparentText.odg |binary
filter/qa/unit/svg.cxx | 38 ++++++++++
filter/source/svg/svgwriter.cxx | 113 ++++++++++++++++++++++----------
filter/source/svg/svgwriter.hxx | 11 ++-
4 files changed, 127 insertions(+), 35 deletions(-)
New commits:
commit a16d6e2130f5a4915fd1aca629805f2682e86803
Author: Miklos Vajna <vmiklos at collabora.com>
AuthorDate: Fri Jul 17 09:23:16 2020 +0200
Commit: Miklos Vajna <vmiklos at collabora.com>
CommitDate: Fri Jul 17 17:31:03 2020 +0200
SVG export: fix lost semi-transparent text on shapes
Extend SVGTextWriter::setTextPosition(), so when it looks for a text
action in a metafile, it recurses into transparency groups, so the text
is not lost.
Extract part of SVGActionWriter::ImplWriteMask() into a new StartMask(),
so we can detect the case when the transparency group has a constant
alpha, i.e. no complex mask is needed, just an opacity value.
When looking for text, remember if we saw a request for text opacity and
make the transparency group writing in SVGActionWriter::ImplWriteMask()
conditional to avoid duplication. This is needed because once we're
inside <text>, we don't want to write an invalid transparency group via
<g>, rather we want a fill-opacity on the existing <tspan>.
With this, the SVG export is on par with PDF export for semi-transparent
shape text.
(cherry picked from commit 666f252457bdb4371d15380a0289e107b2dfbe84)
Conflicts:
filter/source/svg/svgwriter.cxx
filter/source/svg/svgwriter.hxx
Change-Id: If43b0ab3446015299acc4b37590358867c5fac5f
diff --git a/filter/qa/unit/svg.cxx b/filter/qa/unit/svg.cxx
index f856cf01d257..2f52377e92bc 100644
--- a/filter/qa/unit/svg.cxx
+++ b/filter/qa/unit/svg.cxx
@@ -114,16 +114,21 @@ CPPUNIT_TEST_FIXTURE(SvgFilterTest, testSemiTransparentText)
aStream.Seek(STREAM_SEEK_TO_BEGIN);
xmlDocPtr pXmlDoc = parseXmlStream(&aStream);
- (void)pXmlDoc;
// We expect 2 groups of class "com.sun.star.drawing.TextShape" that
// have some svg:text node inside.
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 2
+ // - Actual : 1
+ // i.e. the 2nd shape lots its text.
- // TODO: fix the bug
+ assertXPath(pXmlDoc, "//svg:g[@class='com.sun.star.drawing.TextShape']//svg:text", 2);
- // assertXPath(pXmlDoc, "//svg:g[@class='com.sun.star.drawing.TextShape']//svg:text", 2);
+ // First shape has semi-transparent text.
+ assertXPath(pXmlDoc, "//svg:text[1]/svg:tspan/svg:tspan/svg:tspan[@fill-opacity='0.8']");
- // TODO: assert we the text has correctly transparent text (20%)
+ // Second shape has normal text.
+ assertXPath(pXmlDoc, "//svg:text[2]/svg:tspan/svg:tspan/svg:tspan[@fill-opacity]", 0);
}
CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/filter/source/svg/svgwriter.cxx b/filter/source/svg/svgwriter.cxx
index 148b1ca42bb2..abb6877e8902 100644
--- a/filter/source/svg/svgwriter.cxx
+++ b/filter/source/svg/svgwriter.cxx
@@ -440,9 +440,11 @@ void SVGAttributeWriter::setFontFamily()
}
}
-SVGTextWriter::SVGTextWriter( SVGExport& rExport, SVGAttributeWriter& rAttributeWriter )
+SVGTextWriter::SVGTextWriter(SVGExport& rExport, SVGAttributeWriter& rAttributeWriter,
+ SVGActionWriter& rActionWriter)
: mrExport( rExport ),
mrAttributeWriter( rAttributeWriter ),
+ mrActionWriter(rActionWriter),
mpVDev( nullptr ),
mbIsTextShapeStarted( false ),
mrTextShape(),
@@ -581,7 +583,8 @@ bool SVGTextWriter::implGetTextPositionFromBitmap( const MetaAction* pAction, Po
* 0 if no text found and end of text shape is reached
* 1 if text found!
*/
-sal_Int32 SVGTextWriter::setTextPosition( const GDIMetaFile& rMtf, sal_uLong& nCurAction )
+sal_Int32 SVGTextWriter::setTextPosition(const GDIMetaFile& rMtf, sal_uLong& nCurAction,
+ sal_uInt32 nWriteFlags)
{
Point aPos;
sal_uLong nCount = rMtf.GetActionSize();
@@ -617,6 +620,22 @@ sal_Int32 SVGTextWriter::setTextPosition( const GDIMetaFile& rMtf, sal_uLong& nC
}
break;
+ case MetaActionType::FLOATTRANSPARENT:
+ {
+ const MetaFloatTransparentAction* pA
+ = static_cast<const MetaFloatTransparentAction*>(pAction);
+ GDIMetaFile aTmpMtf(pA->GetGDIMetaFile());
+ sal_uLong nTmpAction = 0;
+ if (setTextPosition(aTmpMtf, nTmpAction, nWriteFlags) == 1)
+ {
+ // Text is found in the inner metafile.
+ bConfigured = true;
+ mrActionWriter.StartMask(pA->GetPoint(), pA->GetSize(), pA->GetGradient(),
+ nWriteFlags, &maTextOpacity);
+ }
+ }
+ break;
+
case( MetaActionType::STRETCHTEXT ):
{
bConfigured = implGetTextPosition<MetaStretchTextAction>( pAction, aPos, bEmpty );
@@ -1258,6 +1277,7 @@ void SVGTextWriter::endTextShape()
delete mpTextShapeElem;
mpTextShapeElem = nullptr;
}
+ maTextOpacity.clear();
mbIsTextShapeStarted = false;
// these need to be invoked after the <text> element has been closed
implExportHyperlinkIds();
@@ -1344,6 +1364,7 @@ void SVGTextWriter::endTextPosition()
}
}
+bool SVGTextWriter::hasTextOpacity() { return !maTextOpacity.isEmpty(); }
void SVGTextWriter::implExportHyperlinkIds()
{
@@ -1692,6 +1713,11 @@ void SVGTextWriter::implWriteTextPortion( const Point& rPos,
addFontAttributes( /* isTexTContainer: */ false );
+ if (!maTextOpacity.isEmpty())
+ {
+ mrExport.AddAttribute(XML_NAMESPACE_NONE, "fill-opacity", maTextOpacity);
+ }
+
mrAttributeWriter.AddPaintAttr( COL_TRANSPARENT, aTextColor );
// <a> tag for link should be the innermost tag, inside <tspan>
@@ -1727,7 +1753,7 @@ SVGActionWriter::SVGActionWriter( SVGExport& rExport, SVGFontExport& rFontExport
maContextHandler(),
mrCurrentState( maContextHandler.getCurrentState() ),
maAttributeWriter( rExport, rFontExport, mrCurrentState ),
- maTextWriter( rExport, maAttributeWriter ),
+ maTextWriter( rExport, maAttributeWriter, *this ),
mbClipAttrChanged( false ),
mbIsPlaceholderShape( false )
{
@@ -2382,39 +2408,26 @@ Color SVGActionWriter::ImplGetGradientColor( const Color& rStartColor,
return Color( (sal_uInt8)nNewRed, (sal_uInt8)nNewGreen, (sal_uInt8)nNewBlue );
}
-
-void SVGActionWriter::ImplWriteMask( GDIMetaFile& rMtf,
- const Point& rDestPt,
- const Size& rDestSize,
- const Gradient& rGradient,
- sal_uInt32 nWriteFlags )
+void SVGActionWriter::StartMask(const Point& rDestPt, const Size& rDestSize,
+ const Gradient& rGradient, sal_uInt32 nWriteFlags,
+ OUString* pTextFillOpacity)
{
- Point aSrcPt( rMtf.GetPrefMapMode().GetOrigin() );
- const Size aSrcSize( rMtf.GetPrefSize() );
- const double fScaleX = aSrcSize.Width() ? (double) rDestSize.Width() / aSrcSize.Width() : 1.0;
- const double fScaleY = aSrcSize.Height() ? (double) rDestSize.Height() / aSrcSize.Height() : 1.0;
- long nMoveX, nMoveY;
-
- if( fScaleX != 1.0 || fScaleY != 1.0 )
- {
- rMtf.Scale( fScaleX, fScaleY );
- aSrcPt.X() = FRound( aSrcPt.X() * fScaleX );
- aSrcPt.Y() = FRound( aSrcPt.Y() * fScaleY );
- }
-
- nMoveX = rDestPt.X() - aSrcPt.X();
- nMoveY = rDestPt.Y() - aSrcPt.Y();
-
- if( nMoveX || nMoveY )
- rMtf.Move( nMoveX, nMoveY );
-
OUString aStyle;
if (rGradient.GetStartColor() == rGradient.GetEndColor())
{
// 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);
+ if (pTextFillOpacity)
+ {
+ // Don't write anything, return what is a value suitable for <tspan fill-opacity="...">.
+ *pTextFillOpacity = OUString::number(fOpacity);
+ return;
+ }
+ else
+ {
+ aStyle = "opacity: " + OUString::number(fOpacity);
+ }
}
else
{
@@ -2445,9 +2458,40 @@ void SVGActionWriter::ImplWriteMask( GDIMetaFile& rMtf,
aStyle = "mask:url(#" + aMaskId + ")";
}
mrExport.AddAttribute(XML_NAMESPACE_NONE, aXMLAttrStyle, aStyle);
+}
+
+void SVGActionWriter::ImplWriteMask(GDIMetaFile& rMtf, const Point& rDestPt, const Size& rDestSize,
+ const Gradient& rGradient, sal_uInt32 nWriteFlags)
+{
+ Point aSrcPt(rMtf.GetPrefMapMode().GetOrigin());
+ const Size aSrcSize(rMtf.GetPrefSize());
+ const double fScaleX
+ = aSrcSize.Width() ? static_cast<double>(rDestSize.Width()) / aSrcSize.Width() : 1.0;
+ const double fScaleY
+ = aSrcSize.Height() ? static_cast<double>(rDestSize.Height()) / aSrcSize.Height() : 1.0;
+ long nMoveX, nMoveY;
+ if (fScaleX != 1.0 || fScaleY != 1.0)
{
- SvXMLElementExport aElemG( mrExport, XML_NAMESPACE_NONE, aXMLElemG, true, true );
+ rMtf.Scale(fScaleX, fScaleY);
+ aSrcPt.setX(FRound(aSrcPt.X() * fScaleX));
+ aSrcPt.setY(FRound(aSrcPt.Y() * fScaleY));
+ }
+
+ nMoveX = rDestPt.X() - aSrcPt.X();
+ nMoveY = rDestPt.Y() - aSrcPt.Y();
+
+ if (nMoveX || nMoveY)
+ rMtf.Move(nMoveX, nMoveY);
+
+ {
+ std::unique_ptr<SvXMLElementExport> pElemG;
+ if (!maTextWriter.hasTextOpacity())
+ {
+ StartMask(rDestPt, rDestSize, rGradient, nWriteFlags);
+ pElemG.reset(
+ new SvXMLElementExport(mrExport, XML_NAMESPACE_NONE, aXMLElemG, true, true));
+ }
mpVDev->Push();
ImplWriteActions( rMtf, nWriteFlags, nullptr );
@@ -3372,7 +3416,8 @@ void SVGActionWriter::ImplWriteActions( const GDIMetaFile& rMtf,
sal_Int32 nTextFound = -1;
while( ( nTextFound < 0 ) && ( nCurAction < nCount ) )
{
- nTextFound = maTextWriter.setTextPosition( rMtf, nCurAction );
+ nTextFound
+ = maTextWriter.setTextPosition(rMtf, nCurAction, nWriteFlags);
}
// We found some text in the current text shape.
if( nTextFound > 0 )
@@ -3407,7 +3452,8 @@ void SVGActionWriter::ImplWriteActions( const GDIMetaFile& rMtf,
sal_Int32 nTextFound = -1;
while( ( nTextFound < 0 ) && ( nCurAction < nCount ) )
{
- nTextFound = maTextWriter.setTextPosition( rMtf, nCurAction );
+ nTextFound
+ = maTextWriter.setTextPosition(rMtf, nCurAction, nWriteFlags);
}
// We found a paragraph with some text in the
// current text shape.
@@ -3440,7 +3486,8 @@ void SVGActionWriter::ImplWriteActions( const GDIMetaFile& rMtf,
sal_Int32 nTextFound = -2;
while( ( nTextFound < -1 ) && ( nCurAction < nCount ) )
{
- nTextFound = maTextWriter.setTextPosition( rMtf, nCurAction );
+ nTextFound
+ = maTextWriter.setTextPosition(rMtf, nCurAction, nWriteFlags);
}
// We found a line with some text in the current
// paragraph.
diff --git a/filter/source/svg/svgwriter.hxx b/filter/source/svg/svgwriter.hxx
index 46fced788f72..197c2ff98b93 100644
--- a/filter/source/svg/svgwriter.hxx
+++ b/filter/source/svg/svgwriter.hxx
@@ -222,6 +222,7 @@ class SVGTextWriter final
private:
SVGExport& mrExport;
SVGAttributeWriter& mrAttributeWriter;
+ SVGActionWriter& mrActionWriter;
VclPtr<VirtualDevice> mpVDev;
bool mbIsTextShapeStarted;
Reference<XText> mrTextShape;
@@ -235,6 +236,7 @@ class SVGTextWriter final
SvXMLElementExport* mpTextShapeElem;
SvXMLElementExport* mpTextParagraphElem;
SvXMLElementExport* mpTextPositionElem;
+ OUString maTextOpacity;
sal_Int32 mnLeftTextPortionLength;
Point maTextPos;
long int mnTextWidth;
@@ -254,10 +256,12 @@ class SVGTextWriter final
vcl::Font maParentFont;
public:
- explicit SVGTextWriter( SVGExport& rExport, SVGAttributeWriter& rAttributeWriter );
+ explicit SVGTextWriter(SVGExport& rExport, SVGAttributeWriter& rAttributeWriter,
+ SVGActionWriter& mrActionWriter);
~SVGTextWriter();
- sal_Int32 setTextPosition( const GDIMetaFile& rMtf, sal_uLong& nCurAction );
+ sal_Int32 setTextPosition(const GDIMetaFile& rMtf, sal_uLong& nCurAction,
+ sal_uInt32 nWriteFlags);
void setTextProperties( const GDIMetaFile& rMtf, sal_uLong nCurAction );
void addFontAttributes( bool bIsTextContainer );
@@ -272,6 +276,7 @@ class SVGTextWriter final
void endTextParagraph();
void startTextPosition( bool bExportX = true, bool bExportY = true);
void endTextPosition();
+ bool hasTextOpacity();
void implExportHyperlinkIds();
void implWriteBulletChars();
template< typename MetaBitmapActionType >
@@ -386,6 +391,8 @@ public:
const OUString* pElementId = nullptr,
const Reference< XShape >* pXShape = nullptr,
const GDIMetaFile* pTextEmbeddedBitmapMtf = nullptr );
+ void StartMask(const Point& rDestPt, const Size& rDestSize, const Gradient& rGradient,
+ sal_uInt32 nWriteFlags, OUString* pTextStyle = nullptr);
};
commit 9a35a05b23251f86267eb73b5e67fd05a0d75925
Author: Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
AuthorDate: Mon Jul 13 12:16:48 2020 +0200
Commit: Miklos Vajna <vmiklos at collabora.com>
CommitDate: Fri Jul 17 10:35:02 2020 +0200
Prepare test for SVG export of semi-transparent text, not enabled
This prepares the test for semi-transparent text, but the assert
is not yet enabled until the bug gets fixed.
(cherry picked from commit ebb7cd91ec2bbbba3e4d2ce106b24933b23f4d14)
Change-Id: I31a241910fd7bdf27579f291a497b76292eac775
diff --git a/filter/qa/unit/data/TransparentText.odg b/filter/qa/unit/data/TransparentText.odg
new file mode 100644
index 000000000000..d3027d17d657
Binary files /dev/null and b/filter/qa/unit/data/TransparentText.odg differ
diff --git a/filter/qa/unit/svg.cxx b/filter/qa/unit/svg.cxx
index ee582d52e982..f856cf01d257 100644
--- a/filter/qa/unit/svg.cxx
+++ b/filter/qa/unit/svg.cxx
@@ -93,6 +93,39 @@ CPPUNIT_TEST_FIXTURE(SvgFilterTest, testSemiTransparentLine)
CPPUNIT_ASSERT_EQUAL(30, nPercent);
}
+CPPUNIT_TEST_FIXTURE(SvgFilterTest, testSemiTransparentText)
+{
+ // Two shapes, one with transparent text and the other one with
+ // opaque text. We expect both to be exported to the SVG with the
+ // correct transparency factor applied for the first shape.
+
+ // Load draw document with transparent text in one box
+ load("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);
+
+ xmlDocPtr pXmlDoc = parseXmlStream(&aStream);
+ (void)pXmlDoc;
+
+ // We expect 2 groups of class "com.sun.star.drawing.TextShape" that
+ // have some svg:text node inside.
+
+ // TODO: fix the bug
+
+ // assertXPath(pXmlDoc, "//svg:g[@class='com.sun.star.drawing.TextShape']//svg:text", 2);
+
+ // TODO: assert we the text has correctly transparent text (20%)
+}
+
CPPUNIT_PLUGIN_IMPLEMENT();
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
More information about the Libreoffice-commits
mailing list