tdf#156616: check if character's parent has x or y
if so, only concatenate the characters that are in the same line
so the alignment will be calculated based on the
line's width
Change-Id: I704370c0a470f8b4cff97c51ad9863158118ee8a
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/155636
Tested-by: Jenkins
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
Signed-off-by: Xisco Fauli <xiscofauli@libreoffice.org>
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/155657
diff --git a/svgio/inc/svgcharacternode.hxx b/svgio/inc/svgcharacternode.hxx
index 391c402..059aa9e 100644
--- a/svgio/inc/svgcharacternode.hxx
+++ b/svgio/inc/svgcharacternode.hxx
@@ -40,7 +40,7 @@ namespace svgio::svgreader
// keep a copy of string data before space handling
OUString maTextBeforeSpaceHandling;
SvgTextNode* mpTextParent;
SvgTspanNode* mpParentLine;
/// local helpers
rtl::Reference<drawinglayer::primitive2d::BasePrimitive2D> createSimpleTextPrimitive(
@@ -68,7 +68,7 @@ namespace svgio::svgreader
/// Text content
const OUString& getText() const { return maText; }
void setTextParent(SvgTextNode* pTextParent) { mpTextParent = pTextParent; }
void setParentLine(SvgTspanNode* pParentLine) { mpParentLine = pParentLine; }
};
} // end of namespace svgio::svgreader
diff --git a/svgio/inc/svgtextnode.hxx b/svgio/inc/svgtextnode.hxx
index 2d5f98e..7876879 100644
--- a/svgio/inc/svgtextnode.hxx
+++ b/svgio/inc/svgtextnode.hxx
@@ -33,10 +33,6 @@ namespace svgio::svgreader
std::optional<basegfx::B2DHomMatrix>
mpaTransform;
// The text line composed by the different SvgCharacterNode children
// it will be used to calculate their alignment
OUString maTextLine;
/// local helpers
void DecomposeChild(
const SvgNode& rCandidate,
@@ -59,9 +55,6 @@ namespace svgio::svgreader
/// transform content, set if found in current context
const std::optional<basegfx::B2DHomMatrix>& getTransform() const { return mpaTransform; }
void setTransform(const std::optional<basegfx::B2DHomMatrix>& pMatrix) { mpaTransform = pMatrix; }
void concatenateTextLine(std::u16string_view rText) {maTextLine += rText;}
const OUString& getTextLine() const { return maTextLine; }
};
} // end of namespace svgio::svgreader
diff --git a/svgio/inc/svgtspannode.hxx b/svgio/inc/svgtspannode.hxx
index d5d86c5..92ed831 100644
--- a/svgio/inc/svgtspannode.hxx
+++ b/svgio/inc/svgtspannode.hxx
@@ -39,6 +39,10 @@ namespace svgio::svgreader
bool mbLengthAdjust : 1; // true = spacing, false = spacingAndGlyphs
// The text line composed by the different SvgCharacterNode children
// it will be used to calculate their alignment
OUString maTextLine;
public:
SvgTspanNode(
SVGToken aType,
@@ -78,6 +82,9 @@ namespace svgio::svgreader
/// LengthAdjust content
bool getLengthAdjust() const { return mbLengthAdjust; }
void setLengthAdjust(bool bNew) { mbLengthAdjust = bNew; }
void concatenateTextLine(std::u16string_view rText) {maTextLine += rText;}
const OUString& getTextLine() const { return maTextLine; }
};
} // end of namespace svgio::svgreader
diff --git a/svgio/qa/cppunit/SvgImportTest.cxx b/svgio/qa/cppunit/SvgImportTest.cxx
index c52e205..42cb98c 100644
--- a/svgio/qa/cppunit/SvgImportTest.cxx
+++ b/svgio/qa/cppunit/SvgImportTest.cxx
@@ -740,7 +740,45 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf85770)
assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[3]", "text", " End");
assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[3]", "height", "11");
assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[3]", "familyname", "Times New Roman");
}
CPPUNIT_TEST_FIXTURE(Test, testTdf156616)
{
Primitive2DSequence aSequence = parseSvg(u"/svgio/qa/cppunit/data/tdf156616.svg");
CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(aSequence.getLength()));
drawinglayer::Primitive2dXmlDump dumper;
xmlDocUniquePtr pDocument = dumper.dumpAndParse(Primitive2DContainer(aSequence));
CPPUNIT_ASSERT (pDocument);
assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[1]", "text", "First");
assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[1]", "x", "114");
assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[1]", "y", "103");
assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[2]", "text", " line");
assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[2]", "x", "142");
assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[2]", "y", "103");
assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[3]", "text", "Second line");
assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[3]", "x", "114");
assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[3]", "y", "122");
assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[4]", "text", "First");
assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[4]", "x", "86");
assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[4]", "y", "153");
assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[5]", "text", " line");
assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[5]", "x", "114");
assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[5]", "y", "153");
assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[6]", "text", "Second line");
assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[6]", "x", "77");
assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[6]", "y", "172");
assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[7]", "text", "First");
assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[7]", "x", "59");
assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[7]", "y", "203");
assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[8]", "text", " line");
assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[8]", "x", "87");
assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[8]", "y", "203");
assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[9]", "text", "Second line");
assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[9]", "x", "40");
assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[9]", "y", "222");
}
CPPUNIT_TEST_FIXTURE(Test, testTdf79163)
diff --git a/svgio/qa/cppunit/data/tdf156616.svg b/svgio/qa/cppunit/data/tdf156616.svg
new file mode 100644
index 0000000..6b3bb3c
--- /dev/null
+++ b/svgio/qa/cppunit/data/tdf156616.svg
@@ -0,0 +1,29 @@
<svg viewBox="0 0 500 500" xmlns="http://www.w3.org/2000/svg">
<text
style="text-anchor:start"
x="114"
y="103"><tspan
x="114"
y="103"><tspan>First </tspan>line </tspan><tspan
x="114"
y="122">Second line</tspan>
</text>
<text
style="text-anchor:middle"
x="114"
y="153"><tspan
x="114"
y="153"><tspan>First </tspan>line </tspan><tspan
x="114"
y="172">Second line</tspan>
</text>
<text
style="text-anchor:end"
x="114"
y="203"><tspan
x="114"
y="203"><tspan>First </tspan>line </tspan><tspan
x="114"
y="222">Second line</tspan>
</text>
</svg>
diff --git a/svgio/source/svgreader/svgcharacternode.cxx b/svgio/source/svgreader/svgcharacternode.cxx
index 2b88944..9ba70ff 100644
--- a/svgio/source/svgreader/svgcharacternode.cxx
+++ b/svgio/source/svgreader/svgcharacternode.cxx
@@ -79,7 +79,7 @@ namespace svgio::svgreader
OUString aText)
: SvgNode(SVGToken::Character, rDocument, pParent),
maText(std::move(aText)),
mpTextParent(nullptr)
mpParentLine(nullptr)
{
}
@@ -251,7 +251,7 @@ namespace svgio::svgreader
}
// Use the whole text line to calculate the align position
double fWholeTextLineWidth(aTextLayouterDevice.getTextWidth(mpTextParent->getTextLine(), 0, mpTextParent->getTextLine().getLength()));
double fWholeTextLineWidth(aTextLayouterDevice.getTextWidth(mpParentLine->getTextLine(), 0, mpParentLine->getTextLine().getLength()));
// apply TextAlign
switch(aTextAlign)
{
@@ -482,6 +482,10 @@ namespace svgio::svgreader
if(pPreviousCharacterNode->maTextBeforeSpaceHandling[nLastLength - 1] != ' ' && maTextBeforeSpaceHandling[0] != ' ')
bAddGap = false;
// Do not add a gap if this node and last node are in different lines
if(pPreviousCharacterNode->mpParentLine != mpParentLine)
bAddGap = false;
// With this option a baseline shift between two char parts ('words')
// will not add a space 'gap' to the end of the (non-last) word. This
// seems to be the standard behaviour, see last bugdoc attached #122524#
diff --git a/svgio/source/svgreader/svgdocumenthandler.cxx b/svgio/source/svgreader/svgdocumenthandler.cxx
index 4521399..d552db8 100644
--- a/svgio/source/svgreader/svgdocumenthandler.cxx
+++ b/svgio/source/svgreader/svgdocumenthandler.cxx
@@ -62,7 +62,7 @@ namespace svgio::svgreader
namespace
{
svgio::svgreader::SvgCharacterNode* whiteSpaceHandling(svgio::svgreader::SvgNode const * pNode, svgio::svgreader::SvgTextNode* pText, svgio::svgreader::SvgCharacterNode* pLast)
svgio::svgreader::SvgCharacterNode* whiteSpaceHandling(svgio::svgreader::SvgNode const * pNode, svgio::svgreader::SvgTspanNode* pParentLine, svgio::svgreader::SvgCharacterNode* pLast)
{
if(pNode)
{
@@ -82,19 +82,31 @@ namespace
// clean whitespace in text span
svgio::svgreader::SvgCharacterNode* pCharNode = static_cast< svgio::svgreader::SvgCharacterNode* >(pCandidate);
pCharNode->setParentLine(pParentLine);
pCharNode->whiteSpaceHandling();
pLast = pCharNode->addGap(pLast);
pCharNode->setTextParent(pText);
pText->concatenateTextLine(pCharNode->getText());
pParentLine->concatenateTextLine(pCharNode->getText());
break;
}
case SVGToken::Tspan:
{
svgio::svgreader::SvgTspanNode* pTspanNode = static_cast< svgio::svgreader::SvgTspanNode* >(pCandidate);
// If x or y exist it means it's a new line of text
if(!pTspanNode->getX().empty() || !pTspanNode->getY().empty())
pParentLine = pTspanNode;
// recursively clean whitespaces in subhierarchy
pLast = whiteSpaceHandling(pCandidate, pParentLine, pLast);
break;
}
case SVGToken::TextPath:
case SVGToken::Tref:
{
// recursively clean whitespaces in subhierarchy
pLast = whiteSpaceHandling(pCandidate, pText, pLast);
pLast = whiteSpaceHandling(pCandidate, pParentLine, pLast);
break;
}
default:
@@ -552,7 +564,7 @@ namespace
if(pTextNode)
{
// cleanup read strings
whiteSpaceHandling(pTextNode, static_cast< SvgTextNode*>(pTextNode), nullptr);
whiteSpaceHandling(pTextNode, static_cast< SvgTspanNode*>(pTextNode), nullptr);
}
}