tdf#166789: use text width from DXArray in MetaActionType::TEXTARRAY
DXArray gives much more reliable data compared to font width, which
is known to require complex corrections (see tdf#127471 and commit
3d33e4ce39).
This fix uses tspan's `lengthAdjust` and `textLength` attributes for
automatic justification, which are already documented as early as in
SVG 1.0 ( https://www.w3.org/TR/SVG10/text.html#TSpanElement ). This
works in LibreOffice and in Chrome, but is not supported in Firefox
yet ( see https://bugzilla.mozilla.org/show_bug.cgi?id=890692 ).
I considered using these attributes on `text` element level, which
is supported in both browsers - but that breaks text elements with
multiple tspans. The `transform` attribute can't be used with tspan
both in Chrome and in Firefox, which creates the same problem, and
has an additional drawback that tspan offsets need tweaks.
Change-Id: I7d4bbb7542a9d60e53bdf6f6cac7fae0729e6e48
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/186033
Tested-by: Jenkins
Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<office:document xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" office:version="1.4" office:mimetype="application/vnd.oasis.opendocument.graphics">
|
||||
<office:font-face-decls>
|
||||
<style:font-face style:name="Liberation Sans" svg:font-family="'Liberation Sans'" style:font-family-generic="roman" style:font-pitch="variable"/>
|
||||
</office:font-face-decls>
|
||||
<office:styles>
|
||||
<style:style style:name="standard" style:family="graphic">
|
||||
<style:graphic-properties draw:stroke="solid" svg:stroke-color="#000000" svg:stroke-width="5" draw:fill="none" fo:padding-top="0" fo:padding-bottom="0" fo:padding-left="0" fo:padding-right="0"/>
|
||||
<style:text-properties style:font-name="Liberation Sans" fo:font-size="18pt" fo:font-variant="normal" fo:language="zxx" fo:country="none" fo:font-style="normal" style:letter-kerning="true"/>
|
||||
</style:style>
|
||||
</office:styles>
|
||||
<office:automatic-styles>
|
||||
<style:page-layout style:name="PM0">
|
||||
<style:page-layout-properties fo:margin-top="0" fo:margin-bottom="0" fo:margin-left="0" fo:margin-right="0" fo:page-width="8cm" fo:page-height="15mm"/>
|
||||
</style:page-layout>
|
||||
<style:style style:name="gr1" style:family="graphic" style:parent-style-name="standard">
|
||||
<style:graphic-properties draw:auto-grow-height="false" draw:auto-grow-width="false" draw:fit-to-size="true" style:shrink-to-fit="false"/>
|
||||
</style:style>
|
||||
</office:automatic-styles>
|
||||
<office:master-styles>
|
||||
<style:master-page style:name="Standard" style:page-layout-name="PM0"/>
|
||||
</office:master-styles>
|
||||
<office:body>
|
||||
<office:drawing>
|
||||
<draw:page draw:name="page1" draw:master-page-name="Standard">
|
||||
<draw:frame draw:style-name="gr1" svg:width="7cm" svg:height="5mm" svg:x="5mm" svg:y="5mm">
|
||||
<draw:text-box>
|
||||
<text:p>= Foo(Bar).method<templateArg>(arg1, arg2, ...)</text:p>
|
||||
</draw:text-box>
|
||||
</draw:frame>
|
||||
</draw:page>
|
||||
</office:drawing>
|
||||
</office:body>
|
||||
</office:document>
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <com/sun/star/beans/XPropertySet.hpp>
|
||||
|
||||
#include <comphelper/propertyvalue.hxx>
|
||||
#include <o3tl/string_view.hxx>
|
||||
#include <unotools/streamwrap.hxx>
|
||||
#include <unotools/mediadescriptor.hxx>
|
||||
#include <tools/stream.hxx>
|
||||
@@ -379,6 +380,21 @@ CPPUNIT_TEST_FIXTURE(SvgFilterTest, testTdf91315)
|
||||
// - Actual : 0
|
||||
}
|
||||
|
||||
CPPUNIT_TEST_FIXTURE(SvgFilterTest, testTdf166789)
|
||||
{
|
||||
// A fit-to-size text
|
||||
loadFromFile(u"fit-to-size-text.fodg");
|
||||
|
||||
save(u"impress_svg_Export"_ustr);
|
||||
|
||||
xmlDocUniquePtr pXmlDoc = parseExportedFile();
|
||||
|
||||
// Without the accompanying fix, the text wasn't adjusted to the given width
|
||||
OUString length = getXPath(pXmlDoc, "//svg:text//svg:tspan[@lengthAdjust='spacingAndGlyphs']",
|
||||
"textLength");
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL(7000, length.toInt32(), 70); // allow 1% for rounding errors
|
||||
}
|
||||
|
||||
CPPUNIT_PLUGIN_IMPLEMENT();
|
||||
|
||||
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|
||||
|
||||
@@ -1623,8 +1623,7 @@ void SVGTextWriter::implWriteEmbeddedBitmaps()
|
||||
}
|
||||
|
||||
|
||||
void SVGTextWriter::writeTextPortion( const Point& rPos,
|
||||
const OUString& rText )
|
||||
void SVGTextWriter::writeTextPortion(const Point& rPos, const OUString& rText, tools::Long nWidth)
|
||||
{
|
||||
if( rText.isEmpty() )
|
||||
return;
|
||||
@@ -1703,7 +1702,7 @@ void SVGTextWriter::writeTextPortion( const Point& rPos,
|
||||
// to be implemented
|
||||
}
|
||||
#else
|
||||
implWriteTextPortion( rPos, rText, mpVDev->GetTextColor() );
|
||||
implWriteTextPortion( rPos, rText, mpVDev->GetTextColor(), nWidth );
|
||||
#endif
|
||||
|
||||
if( bStandAloneTextPortion )
|
||||
@@ -1713,9 +1712,8 @@ void SVGTextWriter::writeTextPortion( const Point& rPos,
|
||||
}
|
||||
|
||||
|
||||
void SVGTextWriter::implWriteTextPortion( const Point& rPos,
|
||||
const OUString& rText,
|
||||
Color aTextColor )
|
||||
void SVGTextWriter::implWriteTextPortion(const Point& rPos, const OUString& rText, Color aTextColor,
|
||||
tools::Long nWidth)
|
||||
{
|
||||
Point aPos;
|
||||
Point aBaseLinePos( rPos );
|
||||
@@ -1808,6 +1806,18 @@ void SVGTextWriter::implWriteTextPortion( const Point& rPos,
|
||||
|
||||
addFontAttributes( /* isTexTContainer: */ false );
|
||||
|
||||
tools::Long nTextWidth;
|
||||
if (nWidth)
|
||||
{
|
||||
Size size;
|
||||
implMap(Size(nWidth, 0), size);
|
||||
nTextWidth = size.Width();
|
||||
mrExport.AddAttribute(XML_NAMESPACE_NONE, u"lengthAdjust"_ustr, u"spacingAndGlyphs"_ustr);
|
||||
mrExport.AddAttribute(XML_NAMESPACE_NONE, u"textLength"_ustr, OUString::number(nTextWidth));
|
||||
}
|
||||
else
|
||||
nTextWidth = mpVDev->GetTextWidth(rText);
|
||||
|
||||
if (!maTextOpacity.isEmpty())
|
||||
{
|
||||
mrExport.AddAttribute(XML_NAMESPACE_NONE, u"fill-opacity"_ustr, maTextOpacity);
|
||||
@@ -1843,7 +1853,7 @@ void SVGTextWriter::implWriteTextPortion( const Point& rPos,
|
||||
mrExport.GetDocHandler()->characters( rText );
|
||||
}
|
||||
|
||||
mnTextWidth += mpVDev->GetTextWidth( rText );
|
||||
mnTextWidth += nTextWidth;
|
||||
}
|
||||
|
||||
|
||||
@@ -4013,7 +4023,10 @@ void SVGActionWriter::ImplWriteActions( const GDIMetaFile& rMtf,
|
||||
}
|
||||
else
|
||||
{
|
||||
maTextWriter.writeTextPortion( pA->GetPoint(), aText );
|
||||
tools::Long nWidth = 0;
|
||||
if (pA->GetDXArray().size() >= o3tl::make_unsigned(aText.getLength()))
|
||||
nWidth = std::round(pA->GetDXArray()[aText.getLength() - 1]);
|
||||
maTextWriter.writeTextPortion(pA->GetPoint(), aText, nWidth);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -259,9 +259,9 @@ class SVGTextWriter final
|
||||
template< typename MetaBitmapActionType >
|
||||
void writeBitmapPlaceholder( const MetaBitmapActionType* pAction );
|
||||
void implWriteEmbeddedBitmaps();
|
||||
void writeTextPortion( const Point& rPos, const OUString& rText );
|
||||
void writeTextPortion(const Point& rPos, const OUString& rText, tools::Long nWidth = 0);
|
||||
void implWriteTextPortion( const Point& rPos, const OUString& rText,
|
||||
Color aTextColor );
|
||||
Color aTextColor, tools::Long nWidth );
|
||||
|
||||
void setVirtualDevice( VirtualDevice* pVDev, MapMode& rTargetMapMode )
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user