summaryrefslogtreecommitdiff
path: root/svgio
diff options
context:
space:
mode:
authorXisco Fauli <xiscofauli@libreoffice.org>2023-08-12 02:28:02 +0200
committerXisco Fauli <xiscofauli@libreoffice.org>2023-08-12 10:00:29 +0200
commitdcb3cb0bd4e4bf2bed05ae3b9d370e17a331a9b1 (patch)
tree08503b04609b8574c537b5db0470647e8e4f7b09 /svgio
parent0f3b36bd2749f360df84d1594c01e619ba0f4930 (diff)
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>
Diffstat (limited to 'svgio')
-rw-r--r--svgio/inc/svgcharacternode.hxx4
-rw-r--r--svgio/inc/svgtextnode.hxx7
-rw-r--r--svgio/inc/svgtspannode.hxx7
-rw-r--r--svgio/qa/cppunit/SvgImportTest.cxx38
-rw-r--r--svgio/qa/cppunit/data/tdf156616.svg29
-rw-r--r--svgio/source/svgreader/svgcharacternode.cxx8
-rw-r--r--svgio/source/svgreader/svgdocumenthandler.cxx22
7 files changed, 99 insertions, 16 deletions
diff --git a/svgio/inc/svgcharacternode.hxx b/svgio/inc/svgcharacternode.hxx
index 391c4029e46c..059aa9ece1fd 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 2d5f98ec18fc..787687977e11 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 d5d86c5a7c1a..92ed8319c628 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 cf66e5bb623f..d97892f8d98f 100644
--- a/svgio/qa/cppunit/SvgImportTest.cxx
+++ b/svgio/qa/cppunit/SvgImportTest.cxx
@@ -744,7 +744,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 000000000000..6b3bb3c6c6a5
--- /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 2b88944aa8d0..9ba70ffb3ef5 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 16f100e0b01e..ea70f3c5cbd6 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:
@@ -480,7 +492,7 @@ namespace
if(pTextNode)
{
// cleanup read strings
- whiteSpaceHandling(pTextNode, static_cast< SvgTextNode*>(pTextNode), nullptr);
+ whiteSpaceHandling(pTextNode, static_cast< SvgTspanNode*>(pTextNode), nullptr);
}
}