svgio/Library_svgio.mk                        |    1 
 svgio/inc/svgcharacternode.hxx                |   98 -------
 svgio/inc/svgtextnode.hxx                     |   11 
 svgio/inc/svgtextposition.hxx                 |   72 +++++
 svgio/inc/svgtspannode.hxx                    |   51 +++-
 svgio/qa/cppunit/SvgImportTest.cxx            |  140 ++++++++++-
 svgio/qa/cppunit/data/tdf151103.svg           |   18 +
 svgio/qa/cppunit/data/tdf156616.svg           |   29 ++
 svgio/source/svgreader/svgcharacternode.cxx   |  322 +++-----------------------
 svgio/source/svgreader/svgdocumenthandler.cxx |   92 ++-----
 svgio/source/svgreader/svgtextnode.cxx        |   25 --
 svgio/source/svgreader/svgtextposition.cxx    |  200 ++++++++++++++++
 svgio/source/svgreader/svgtspannode.cxx       |   85 ++++++
 13 files changed, 668 insertions(+), 476 deletions(-)

New commits:
commit 87e0ac2b92f7a7aac16bf66d2379688238496a75
Author:     Xisco Fauli <xiscofa...@libreoffice.org>
AuthorDate: Sat Aug 12 02:28:02 2023 +0200
Commit:     Xisco Fauli <xiscofa...@libreoffice.org>
CommitDate: Tue Aug 15 19:01:22 2023 +0200

    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 <xiscofa...@libreoffice.org>
    Signed-off-by: Xisco Fauli <xiscofa...@libreoffice.org>
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/155657

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 c52e20594b10..42cb98c4b6be 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 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 45213997144c..d552db8a0d19 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);
             }
         }
 
commit 00871b79164d7dfb50820cdcae05b9050639a014
Author:     Xisco Fauli <xiscofa...@libreoffice.org>
AuthorDate: Thu Aug 3 17:47:36 2023 +0200
Commit:     Xisco Fauli <xiscofa...@libreoffice.org>
CommitDate: Tue Aug 15 19:01:16 2023 +0200

    tdf#151103: Use the whole text line to calculate the align position
    
    Change-Id: I7ecd41c422afbf028101924972c47a510834ba5a
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/155314
    Tested-by: Jenkins
    Reviewed-by: Xisco Fauli <xiscofa...@libreoffice.org>
    Signed-off-by: Xisco Fauli <xiscofa...@libreoffice.org>
    
    This commit also contains the following commits:
    
    svgio: remove recurrent checks
    
    Change-Id: I26c37e6b58e7c54e2bdc2c77543896daceb638d3
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/155520
    Tested-by: Jenkins
    Reviewed-by: Xisco Fauli <xiscofa...@libreoffice.org>
    Signed-off-by: Xisco Fauli <xiscofa...@libreoffice.org>
    
    svgio: get rid of SvgTextPositions
    
    and make SvgText inherit from SvgTspan
    
    Change-Id: Ief25e52ba2a493936f82f1674f73168ed5647278
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/155521
    Tested-by: Jenkins
    Reviewed-by: Xisco Fauli <xiscofa...@libreoffice.org>
    Signed-off-by: Xisco Fauli <xiscofa...@libreoffice.org>
    
    svgio: avoid dynamic_cast
    
    Change-Id: I9a2e2c4341476a59ffb001c42e7812cb8249c856
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/155548
    Tested-by: Jenkins
    Reviewed-by: Xisco Fauli <xiscofa...@libreoffice.org>
    Signed-off-by: Xisco Fauli <xiscofa...@libreoffice.org>
    
    svgio: handle addGap internally inside SvgCharacterNode
    
    Also add the gap at the beginning of the current node,
    not at the end of the previous one
    
    Change-Id: I6583059b4a7418010ac2af459e00fb0d02d39605
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/155552
    Tested-by: Jenkins
    Reviewed-by: Xisco Fauli <xiscofa...@libreoffice.org>
    Signed-off-by: Xisco Fauli <xiscofa...@libreoffice.org>
    
    svgio: move SvgTextPosition to its own file
    
    In order to avoid a circular dependency in a follow-up commit
    
    Change-Id: Ib7b16e73282dfa6f3ca87aab1044cb92df72b6bf
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/155555
    Tested-by: Jenkins
    Reviewed-by: Xisco Fauli <xiscofa...@libreoffice.org>
    Signed-off-by: Xisco Fauli <xiscofa...@libreoffice.org>
    
    related: tdf#151103: simplify code
    
    Keep the text line in the SvgTextNode and not in each
    SvgCharacterNode
    
    Change-Id: Ia33e46cc974a39a915e7b933337b4c529e6eeca5
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/155558
    Tested-by: Jenkins
    Reviewed-by: Xisco Fauli <xiscofa...@libreoffice.org>
    Signed-off-by: Xisco Fauli <xiscofa...@libreoffice.org>
    
    cid#1539807 Uninitialized pointer field
    
    Change-Id: I500c5d9f15c6a57622a28ea7cbf3b5f90761b5c0
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/155582
    Tested-by: Caolán McNamara <caolan.mcnam...@collabora.com>
    Reviewed-by: Caolán McNamara <caolan.mcnam...@collabora.com>
    Signed-off-by: Xisco Fauli <xiscofa...@libreoffice.org>
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/155656
    Tested-by: Jenkins

diff --git a/svgio/Library_svgio.mk b/svgio/Library_svgio.mk
index c25077ed94d3..edd83ed57251 100644
--- a/svgio/Library_svgio.mk
+++ b/svgio/Library_svgio.mk
@@ -85,6 +85,7 @@ $(eval $(call gb_Library_add_exception_objects,svgio,\
     svgio/source/svgreader/svgsvgnode \
     svgio/source/svgreader/svgsymbolnode \
     svgio/source/svgreader/svgtextnode \
+    svgio/source/svgreader/svgtextposition \
     svgio/source/svgreader/svgtitledescnode \
     svgio/source/svgreader/svgtoken \
     svgio/source/svgreader/svgtrefnode \
diff --git a/svgio/inc/svgcharacternode.hxx b/svgio/inc/svgcharacternode.hxx
index 8861055f8e65..391c4029e46c 100644
--- a/svgio/inc/svgcharacternode.hxx
+++ b/svgio/inc/svgcharacternode.hxx
@@ -24,100 +24,13 @@
 
 #include <string_view>
 
-#include "svgnode.hxx"
+#include "svgtextnode.hxx"
+#include "svgtextposition.hxx"
 
 namespace drawinglayer::primitive2d { class TextSimplePortionPrimitive2D; }
 
 namespace svgio::svgreader
     {
-        class SvgTextPositions
-        {
-        private:
-            SvgNumberVector         maX;
-            SvgNumberVector         maY;
-            SvgNumberVector         maDx;
-            SvgNumberVector         maDy;
-            SvgNumberVector         maRotate;
-            SvgNumber               maTextLength;
-
-            bool                    mbLengthAdjust : 1; // true = spacing, 
false = spacingAndGlyphs
-
-        public:
-            SvgTextPositions();
-
-            void parseTextPositionAttributes(SVGToken aSVGToken, 
std::u16string_view aContent);
-
-            /// X content
-            const SvgNumberVector& getX() const { return maX; }
-            void setX(SvgNumberVector&& aX) { maX = std::move(aX); }
-
-            /// Y content
-            const SvgNumberVector& getY() const { return maY; }
-            void setY(SvgNumberVector&& aY) { maY = std::move(aY); }
-
-            /// Dx content
-            const SvgNumberVector& getDx() const { return maDx; }
-            void setDx(SvgNumberVector&& aDx) { maDx = std::move(aDx); }
-
-            /// Dy content
-            const SvgNumberVector& getDy() const { return maDy; }
-            void setDy(SvgNumberVector&& aDy) { maDy = std::move(aDy); }
-
-            /// Rotate content
-            const SvgNumberVector& getRotate() const { return maRotate; }
-            void setRotate(SvgNumberVector&& aRotate) { maRotate = 
std::move(aRotate); }
-
-            /// TextLength content
-            const SvgNumber& getTextLength() const { return maTextLength; }
-            void setTextLength(const SvgNumber& rTextLength) { maTextLength = 
rTextLength; }
-
-            /// LengthAdjust content
-            bool getLengthAdjust() const { return mbLengthAdjust; }
-            void setLengthAdjust(bool bNew) { mbLengthAdjust = bNew; }
-        };
-
-        class SvgTextPosition
-        {
-        private:
-            SvgTextPosition*            mpParent;
-            ::std::vector< double >     maX;
-            ::std::vector< double >     maY;
-            ::std::vector< double >     maDx;
-            ::std::vector< double >     maRotate;
-            double                      mfTextLength;
-
-            // absolute, current, advancing position
-            basegfx::B2DPoint           maPosition;
-
-            // advancing rotation index
-            sal_uInt32                  mnRotationIndex;
-
-            bool                        mbLengthAdjust : 1; // true = spacing, 
false = spacingAndGlyphs
-            bool                        mbAbsoluteX : 1;
-
-        public:
-            SvgTextPosition(
-                SvgTextPosition* pParent,
-                const InfoProvider& rInfoProvider,
-                const SvgTextPositions& rSvgTextPositions);
-
-            // data read access
-            const SvgTextPosition* getParent() const { return mpParent; }
-            const ::std::vector< double >& getX() const { return maX; }
-            const ::std::vector< double >& getDx() const { return maDx; }
-            double getTextLength() const { return mfTextLength; }
-            bool getLengthAdjust() const { return mbLengthAdjust; }
-            bool getAbsoluteX() const { return mbAbsoluteX; }
-
-            // get/set absolute, current, advancing position
-            const basegfx::B2DPoint& getPosition() const { return maPosition; }
-            void setPosition(const basegfx::B2DPoint& rNew) { maPosition = 
rNew; }
-
-            // rotation handling
-            bool isRotated() const;
-            double consumeRotation();
-        };
-
         class SvgCharacterNode final : public SvgNode
         {
         private:
@@ -127,6 +40,8 @@ namespace svgio::svgreader
             // keep a copy of string data before space handling
             OUString           maTextBeforeSpaceHandling;
 
+            SvgTextNode*        mpTextParent;
+
             /// local helpers
             rtl::Reference<drawinglayer::primitive2d::BasePrimitive2D> 
createSimpleTextPrimitive(
                 SvgTextPosition& rSvgTextPosition,
@@ -144,15 +59,16 @@ namespace svgio::svgreader
             virtual ~SvgCharacterNode() override;
 
             virtual const SvgStyleAttributes* getSvgStyleAttributes() const 
override;
+
             void 
decomposeText(drawinglayer::primitive2d::Primitive2DContainer& rTarget, 
SvgTextPosition& rSvgTextPosition) const;
             void whiteSpaceHandling();
-            void addGap();
+            SvgCharacterNode* addGap(SvgCharacterNode* pPreviousCharacterNode);
             void concatenate(std::u16string_view rText);
 
             /// Text content
             const OUString& getText() const { return maText; }
 
-            const OUString& getTextBeforeSpaceHandling() const { return 
maTextBeforeSpaceHandling; }
+            void setTextParent(SvgTextNode* pTextParent) { mpTextParent = 
pTextParent; }
         };
 
 } // end of namespace svgio::svgreader
diff --git a/svgio/inc/svgtextnode.hxx b/svgio/inc/svgtextnode.hxx
index 0cc78f130aed..2d5f98ec18fc 100644
--- a/svgio/inc/svgtextnode.hxx
+++ b/svgio/inc/svgtextnode.hxx
@@ -19,23 +19,23 @@
 
 #pragma once
 
-#include "svgnode.hxx"
 #include "svgstyleattributes.hxx"
-#include "svgcharacternode.hxx"
+#include "svgtextposition.hxx"
+#include "svgtspannode.hxx"
 #include <basegfx/matrix/b2dhommatrix.hxx>
 
 namespace svgio::svgreader
     {
-        class SvgTextNode final : public SvgNode
+        class SvgTextNode final : public SvgTspanNode
         {
         private:
-            /// use styles
-            SvgStyleAttributes      maSvgStyleAttributes;
-
             /// variable scan values, dependent of given XAttributeList
             std::optional<basegfx::B2DHomMatrix>
                                     mpaTransform;
-            SvgTextPositions        maSvgTextPositions;
+
+            // The text line composed by the different SvgCharacterNode 
children
+            // it will be used to calculate their alignment
+            OUString maTextLine;
 
             /// local helpers
             void DecomposeChild(
@@ -53,13 +53,15 @@ namespace svgio::svgreader
                 SvgNode* pParent);
             virtual ~SvgTextNode() override;
 
-            virtual const SvgStyleAttributes* getSvgStyleAttributes() const 
override;
             virtual void parseAttribute(const OUString& rTokenName, SVGToken 
aSVGToken, const OUString& aContent) override;
             virtual void 
decomposeSvgNode(drawinglayer::primitive2d::Primitive2DContainer& rTarget, bool 
bReferenced) const override;
 
             /// 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/svgtextposition.hxx b/svgio/inc/svgtextposition.hxx
new file mode 100644
index 000000000000..df6adc16ab1e
--- /dev/null
+++ b/svgio/inc/svgtextposition.hxx
@@ -0,0 +1,72 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements. See the NOTICE file distributed
+ *   with this work for additional information regarding copyright
+ *   ownership. The ASF licenses this file to you under the Apache
+ *   License, Version 2.0 (the "License"); you may not use this file
+ *   except in compliance with the License. You may obtain a copy of
+ *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+#include <rtl/ref.hxx>
+
+#include <string_view>
+
+#include "svgtspannode.hxx"
+
+namespace svgio::svgreader
+{
+class SvgTextPosition
+{
+private:
+    SvgTextPosition* mpParent;
+    ::std::vector<double> maX;
+    ::std::vector<double> maY;
+    ::std::vector<double> maDx;
+    ::std::vector<double> maRotate;
+    double mfTextLength;
+
+    // absolute, current, advancing position
+    basegfx::B2DPoint maPosition;
+
+    // advancing rotation index
+    sal_uInt32 mnRotationIndex;
+
+    bool mbLengthAdjust : 1; // true = spacing, false = spacingAndGlyphs
+    bool mbAbsoluteX : 1;
+
+public:
+    SvgTextPosition(SvgTextPosition* pParent, const SvgTspanNode& 
rSvgCharacterNode);
+
+    // data read access
+    const SvgTextPosition* getParent() const { return mpParent; }
+    const ::std::vector<double>& getX() const { return maX; }
+    const ::std::vector<double>& getDx() const { return maDx; }
+    double getTextLength() const { return mfTextLength; }
+    bool getLengthAdjust() const { return mbLengthAdjust; }
+    bool getAbsoluteX() const { return mbAbsoluteX; }
+
+    // get/set absolute, current, advancing position
+    const basegfx::B2DPoint& getPosition() const { return maPosition; }
+    void setPosition(const basegfx::B2DPoint& rNew) { maPosition = rNew; }
+
+    // rotation handling
+    bool isRotated() const;
+    double consumeRotation();
+};
+
+} // end of namespace svgio::svgreader
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svgio/inc/svgtspannode.hxx b/svgio/inc/svgtspannode.hxx
index 10a7b7ee16a9..d5d86c5a7c1a 100644
--- a/svgio/inc/svgtspannode.hxx
+++ b/svgio/inc/svgtspannode.hxx
@@ -19,22 +19,29 @@
 
 #pragma once
 
-#include "svgcharacternode.hxx"
+#include "svgnode.hxx"
 #include "svgstyleattributes.hxx"
 
 namespace svgio::svgreader
     {
-        class SvgTspanNode final : public SvgNode
+        class SvgTspanNode : public SvgNode
         {
         private:
             /// use styles
             SvgStyleAttributes      maSvgStyleAttributes;
 
-            /// variable scan values, dependent of given XAttributeList
-            SvgTextPositions        maSvgTextPositions;
+            SvgNumberVector         maX;
+            SvgNumberVector         maY;
+            SvgNumberVector         maDx;
+            SvgNumberVector         maDy;
+            SvgNumberVector         maRotate;
+            SvgNumber               maTextLength;
+
+            bool                    mbLengthAdjust : 1; // true = spacing, 
false = spacingAndGlyphs
 
         public:
             SvgTspanNode(
+                SVGToken aType,
                 SvgDocument& rDocument,
                 SvgNode* pParent);
             virtual ~SvgTspanNode() override;
@@ -44,8 +51,33 @@ namespace svgio::svgreader
 
             double getCurrentFontSize() const;
 
-            /// access to SvgTextPositions
-            const SvgTextPositions& getSvgTextPositions() const { return 
maSvgTextPositions; }
+            /// X content
+            const SvgNumberVector& getX() const { return maX; }
+            void setX(SvgNumberVector&& aX) { maX = std::move(aX); }
+
+            /// Y content
+            const SvgNumberVector& getY() const { return maY; }
+            void setY(SvgNumberVector&& aY) { maY = std::move(aY); }
+
+            /// Dx content
+            const SvgNumberVector& getDx() const { return maDx; }
+            void setDx(SvgNumberVector&& aDx) { maDx = std::move(aDx); }
+
+            /// Dy content
+            const SvgNumberVector& getDy() const { return maDy; }
+            void setDy(SvgNumberVector&& aDy) { maDy = std::move(aDy); }
+
+            /// Rotate content
+            const SvgNumberVector& getRotate() const { return maRotate; }
+            void setRotate(SvgNumberVector&& aRotate) { maRotate = 
std::move(aRotate); }
+
+            /// TextLength content
+            const SvgNumber& getTextLength() const { return maTextLength; }
+            void setTextLength(const SvgNumber& rTextLength) { maTextLength = 
rTextLength; }
+
+            /// LengthAdjust content
+            bool getLengthAdjust() const { return mbLengthAdjust; }
+            void setLengthAdjust(bool bNew) { mbLengthAdjust = bNew; }
         };
 
 } // end of namespace svgio::svgreader
diff --git a/svgio/qa/cppunit/SvgImportTest.cxx 
b/svgio/qa/cppunit/SvgImportTest.cxx
index 7a8ba6e82ec0..c52e20594b10 100644
--- a/svgio/qa/cppunit/SvgImportTest.cxx
+++ b/svgio/qa/cppunit/SvgImportTest.cxx
@@ -733,11 +733,11 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf85770)
     assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[1]", 
"height", "11");
     assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[1]", 
"familyname", "Times New Roman");
     assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[2]", 
"fontcolor", "#000000");
-    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[2]", 
"text", "Start ");
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[2]", 
"text", "Start");
     assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[2]", 
"height", "11");
     assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[2]", 
"familyname", "Times New Roman");
     assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[3]", 
"fontcolor", "#000000");
-    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[3]", 
"text", "End");
+    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");
 
@@ -1159,12 +1159,12 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf156251)
     // Without the fix in place, this test would have failed with
     // - Expected: 'You are '
     // - Actual  : 'You are'
-    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[1]", 
"text", "You are ");
-    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[2]", 
"text", "not ");
-    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[3]", 
"text", "a banana!");
-    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[4]", 
"text", "You are ");
-    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[5]", 
"text", "not ");
-    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[6]", 
"text", "a banana!");
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[1]", 
"text", "You are");
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[2]", 
"text", " not");
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[3]", 
"text", " a banana!");
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[4]", 
"text", "You are");
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[5]", 
"text", " not");
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[6]", 
"text", " a banana!");
 }
 
 CPPUNIT_TEST_FIXTURE(Test, testMaskText)
@@ -1454,6 +1454,92 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf95400)
     assertXPathNoAttribute(pDocument, 
"/primitive2D/transform/textsimpleportion[2]", "dx0");
 }
 
+CPPUNIT_TEST_FIXTURE(Test, testTextAnchor)
+{
+    Primitive2DSequence aSequence = 
parseSvg(u"/svgio/qa/cppunit/data/tdf151103.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]", "x", 
"60");
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[1]", "y", 
"40");
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[1]", 
"text", "ABC");
+
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[2]", "x", 
"43");
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[2]", "y", 
"50");
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[2]", 
"text", "ABC");
+
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[3]", "x", 
"26");
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[3]", "y", 
"60");
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[3]", 
"text", "ABC");
+
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[4]", "x", 
"60");
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[4]", "y", 
"40");
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[4]", 
"text", "ABC");
+
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[5]", "x", 
"43");
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[5]", "y", 
"50");
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[5]", 
"text", "ABC");
+
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[6]", "x", 
"26");
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[6]", "y", 
"60");
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[6]", 
"text", "ABC");
+
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[7]", "x", 
"60");
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[7]", "y", 
"40");
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[7]", 
"text", "ABC");
+
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[8]", "x", 
"43");
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[8]", "y", 
"50");
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[8]", 
"text", "ABC");
+
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[9]", "x", 
"26");
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[9]", "y", 
"60");
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[9]", 
"text", "ABC");
+
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[10]", 
"x", "60");
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[10]", 
"y", "40");
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[10]", 
"text", "A");
+
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[11]", 
"x", "72");
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[11]", 
"y", "40");
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[11]", 
"text", "B");
+
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[12]", 
"x", "83");
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[12]", 
"y", "40");
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[12]", 
"text", "C");
+
+    // Without the fix in place, this test would have failed with
+    // - Expected: 43
+    // - Actual  : 54
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[13]", 
"x", "43");
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[13]", 
"y", "50");
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[13]", 
"text", "A");
+
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[14]", 
"x", "55");
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[14]", 
"y", "50");
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[14]", 
"text", "B");
+
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[15]", 
"x", "66");
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[15]", 
"y", "50");
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[15]", 
"text", "C");
+
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[16]", 
"x", "26");
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[16]", 
"y", "60");
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[16]", 
"text", "A");
+
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[17]", 
"x", "38");
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[17]", 
"y", "60");
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[17]", 
"text", "B");
+
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[18]", 
"x", "49");
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[18]", 
"y", "60");
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[18]", 
"text", "C");
+}
+
 CPPUNIT_TEST_FIXTURE(Test, testTdf156577)
 {
     Primitive2DSequence aSequence = 
parseSvg(u"/svgio/qa/cppunit/data/tdf156577.svg");
diff --git a/svgio/qa/cppunit/data/tdf151103.svg 
b/svgio/qa/cppunit/data/tdf151103.svg
new file mode 100644
index 000000000000..664253f8df06
--- /dev/null
+++ b/svgio/qa/cppunit/data/tdf151103.svg
@@ -0,0 +1,18 @@
+<svg viewBox="0 0 120 120" xmlns="http://www.w3.org/2000/svg";>
+  <text text-anchor="start" x="60" y="40">ABC</text>
+  <text text-anchor="middle" x="60" y="50">ABC</text>
+  <text text-anchor="end" x="60" y="60">ABC</text>
+
+  <text><tspan text-anchor="start" x="60" y="40">ABC</tspan></text>
+  <text><tspan text-anchor="middle" x="60" y="50">ABC</tspan></text>
+  <text><tspan text-anchor="end" x="60" y="60">ABC</tspan></text>
+
+  <text text-anchor="start" x="60" y="40"><tspan>ABC</tspan></text>
+  <text text-anchor="middle" x="60" y="50"><tspan>ABC</tspan></text>
+  <text text-anchor="end" x="60" y="60"><tspan>ABC</tspan></text>
+
+  <text text-anchor="start" x="60" y="40">A<tspan>B</tspan>C</text>
+  <text text-anchor="middle" x="60" y="50">A<tspan>B</tspan>C</text>
+  <text text-anchor="end" x="60" y="60">A<tspan>B</tspan>C</text>
+</svg>
+
diff --git a/svgio/source/svgreader/svgcharacternode.cxx 
b/svgio/source/svgreader/svgcharacternode.cxx
index 8a6610c91d25..2b88944aa8d0 100644
--- a/svgio/source/svgreader/svgcharacternode.cxx
+++ b/svgio/source/svgreader/svgcharacternode.cxx
@@ -33,116 +33,6 @@ using namespace drawinglayer::primitive2d;
 
 namespace svgio::svgreader
 {
-        SvgTextPositions::SvgTextPositions()
-        :  mbLengthAdjust(true)
-        {
-        }
-
-        void SvgTextPositions::parseTextPositionAttributes(SVGToken aSVGToken, 
std::u16string_view aContent)
-        {
-            // parse own
-            switch(aSVGToken)
-            {
-                case SVGToken::X:
-                {
-                    if(!aContent.empty())
-                    {
-                        SvgNumberVector aVector;
-
-                        if(readSvgNumberVector(aContent, aVector))
-                        {
-                            setX(std::move(aVector));
-                        }
-                    }
-                    break;
-                }
-                case SVGToken::Y:
-                {
-                    if(!aContent.empty())
-                    {
-                        SvgNumberVector aVector;
-
-                        if(readSvgNumberVector(aContent, aVector))
-                        {
-                            setY(std::move(aVector));
-                        }
-                    }
-                    break;
-                }
-                case SVGToken::Dx:
-                {
-                    if(!aContent.empty())
-                    {
-                        SvgNumberVector aVector;
-
-                        if(readSvgNumberVector(aContent, aVector))
-                        {
-                            setDx(std::move(aVector));
-                        }
-                    }
-                    break;
-                }
-                case SVGToken::Dy:
-                {
-                    if(!aContent.empty())
-                    {
-                        SvgNumberVector aVector;
-
-                        if(readSvgNumberVector(aContent, aVector))
-                        {
-                            setDy(std::move(aVector));
-                        }
-                    }
-                    break;
-                }
-                case SVGToken::Rotate:
-                {
-                    if(!aContent.empty())
-                    {
-                        SvgNumberVector aVector;
-
-                        if(readSvgNumberVector(aContent, aVector))
-                        {
-                            setRotate(std::move(aVector));
-                        }
-                    }
-                    break;
-                }
-                case SVGToken::TextLength:
-                {
-                    SvgNumber aNum;
-
-                    if(readSingleNumber(aContent, aNum))
-                    {
-                        if(aNum.isPositive())
-                        {
-                            setTextLength(aNum);
-                        }
-                    }
-                    break;
-                }
-                case SVGToken::LengthAdjust:
-                {
-                    if(!aContent.empty())
-                    {
-                        if(o3tl::equalsIgnoreAsciiCase(o3tl::trim(aContent), 
u"spacing"))
-                        {
-                            setLengthAdjust(true);
-                        }
-                        else 
if(o3tl::equalsIgnoreAsciiCase(o3tl::trim(aContent), u"spacingAndGlyphs"))
-                        {
-                            setLengthAdjust(false);
-                        }
-                    }
-                    break;
-                }
-                default:
-                {
-                    break;
-                }
-            }
-        }
-
         namespace {
 
         class localTextBreakupHelper : public TextBreakupHelper
@@ -188,7 +78,8 @@ namespace svgio::svgreader
             SvgNode* pParent,
             OUString aText)
         :   SvgNode(SVGToken::Character, rDocument, pParent),
-            maText(std::move(aText))
+            maText(std::move(aText)),
+            mpTextParent(nullptr)
         {
         }
 
@@ -359,17 +250,19 @@ namespace svgio::svgreader
                     }
                 }
 
+                // Use the whole text line to calculate the align position
+                double 
fWholeTextLineWidth(aTextLayouterDevice.getTextWidth(mpTextParent->getTextLine(),
 0, mpTextParent->getTextLine().getLength()));
                 // apply TextAlign
                 switch(aTextAlign)
                 {
                     case TextAlign::right:
                     {
-                        aPosition.setX(aPosition.getX() - fTextWidth);
+                        aPosition.setX(aPosition.getX() - fWholeTextLineWidth);
                         break;
                     }
                     case TextAlign::center:
                     {
-                        aPosition.setX(aPosition.getX() - (fTextWidth * 0.5));
+                        aPosition.setX(aPosition.getX() - (fWholeTextLineWidth 
* 0.5));
                         break;
                     }
                     case TextAlign::notset:
@@ -573,197 +466,64 @@ namespace svgio::svgreader
             }
         }
 
-        void SvgCharacterNode::addGap()
-        {
-            maText += " ";
-        }
-
-        void SvgCharacterNode::concatenate(std::u16string_view rText)
-        {
-            maText += rText;
-        }
-
-        void SvgCharacterNode::decomposeText(Primitive2DContainer& rTarget, 
SvgTextPosition& rSvgTextPosition) const
+        SvgCharacterNode* SvgCharacterNode::addGap(SvgCharacterNode* 
pPreviousCharacterNode)
         {
-            if(!getText().isEmpty())
+            // maText may have lost all text. If that's the case, ignore as 
invalid character node
+            // Also ignore if maTextBeforeSpaceHandling just have spaces
+            if(!maText.isEmpty() && 
!o3tl::trim(maTextBeforeSpaceHandling).empty())
             {
-                const SvgStyleAttributes* pSvgStyleAttributes = 
getSvgStyleAttributes();
-
-                if(pSvgStyleAttributes)
+                if(pPreviousCharacterNode)
                 {
-                    decomposeTextWithStyle(rTarget, rSvgTextPosition, 
*pSvgStyleAttributes);
-                }
-            }
-        }
+                    bool bAddGap(true);
 
+                    // Do not add a gap if last node doesn't end with a space 
and
+                    // current note doesn't start with a space
+                    const sal_uInt32 
nLastLength(pPreviousCharacterNode->maTextBeforeSpaceHandling.getLength());
+                    
if(pPreviousCharacterNode->maTextBeforeSpaceHandling[nLastLength - 1] != ' ' && 
maTextBeforeSpaceHandling[0] != ' ')
+                        bAddGap = false;
 
-        SvgTextPosition::SvgTextPosition(
-            SvgTextPosition* pParent,
-            const InfoProvider& rInfoProvider,
-            const SvgTextPositions& rSvgTextPositions)
-        :   mpParent(pParent),
-            maRotate(solveSvgNumberVector(rSvgTextPositions.getRotate(), 
rInfoProvider)),
-            mfTextLength(0.0),
-            mnRotationIndex(0),
-            mbLengthAdjust(rSvgTextPositions.getLengthAdjust()),
-            mbAbsoluteX(false)
-        {
-            // get TextLength if provided
-            if(rSvgTextPositions.getTextLength().isSet())
-            {
-                mfTextLength = 
rSvgTextPositions.getTextLength().solve(rInfoProvider);
-            }
-
-            // SVG does not really define in which units a \91rotate\92 for 
Text/TSpan is given,
-            // but it seems to be degrees. Convert here to radians
-            if(!maRotate.empty())
-            {
-                for (double& f : maRotate)
-                {
-                    f = basegfx::deg2rad(f);
-                }
-            }
-
-            // get text positions X
-            const sal_uInt32 nSizeX(rSvgTextPositions.getX().size());
-
-            if(nSizeX)
-            {
-                // we have absolute positions, get first one as current text 
position X
-                
maPosition.setX(rSvgTextPositions.getX()[0].solve(rInfoProvider, 
NumberType::xcoordinate));
-                mbAbsoluteX = true;
-            }
-            else
-            {
-                // no absolute position, get from parent
-                if(pParent)
-                {
-                    maPosition.setX(pParent->getPosition().getX());
-                }
-            }
-
-            const sal_uInt32 nSizeDx(rSvgTextPositions.getDx().size());
-            if(nSizeDx)
-            {
-                // relative positions given, translate position derived from 
parent
-                maPosition.setX(maPosition.getX() + 
rSvgTextPositions.getDx()[0].solve(rInfoProvider, NumberType::xcoordinate));
-            }
-
-            // fill deltas to maX
-            maX.reserve(nSizeX);
+                    // 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#
+                    const SvgStyleAttributes* pStyleLast = 
pPreviousCharacterNode->getSvgStyleAttributes();
+                    const SvgStyleAttributes* pStyleCurrent = 
getSvgStyleAttributes();
 
-            for(sal_uInt32 a(1); a < std::max(nSizeX, nSizeDx); ++a)
-            {
-                if (a < nSizeX)
-                {
-                    double nPos = 
rSvgTextPositions.getX()[a].solve(rInfoProvider, NumberType::xcoordinate) - 
maPosition.getX();
-
-                    if(a < nSizeDx)
+                    if(pStyleLast && pStyleCurrent && 
pStyleLast->getBaselineShift() != pStyleCurrent->getBaselineShift())
                     {
-                        nPos += 
rSvgTextPositions.getDx()[a].solve(rInfoProvider, NumberType::xcoordinate);
+                        bAddGap = false;
                     }
 
-                    maX.push_back(nPos);
-                }
-                else
-                {
-                    // Apply them later since it also needs the character 
width to calculate
-                    // the final character position
-                    
maDx.push_back(rSvgTextPositions.getDx()[a].solve(rInfoProvider, 
NumberType::xcoordinate));
+                    // add in-between whitespace (single space) to last
+                    // known character node
+                    if(bAddGap)
+                    {
+                        maText = " " + maText;
+                    }
                 }
-            }
-
-            // get text positions Y
-            const sal_uInt32 nSizeY(rSvgTextPositions.getY().size());
 
-            if(nSizeY)
-            {
-                // we have absolute positions, get first one as current text 
position Y
-                
maPosition.setY(rSvgTextPositions.getY()[0].solve(rInfoProvider, 
NumberType::ycoordinate));
-                mbAbsoluteX = true;
+                // this becomes the previous character node
+                return this;
             }
-            else
-            {
-                // no absolute position, get from parent
-                if(pParent)
-                {
-                    maPosition.setY(pParent->getPosition().getY());
-                }
-            }
-
-            const sal_uInt32 nSizeDy(rSvgTextPositions.getDy().size());
 
-            if(nSizeDy)
-            {
-                // relative positions given, translate position derived from 
parent
-                maPosition.setY(maPosition.getY() + 
rSvgTextPositions.getDy()[0].solve(rInfoProvider, NumberType::ycoordinate));
-            }
-
-            // fill deltas to maY
-            maY.reserve(nSizeY);
-
-            for(sal_uInt32 a(1); a < nSizeY; a++)
-            {
-                double nPos = rSvgTextPositions.getY()[a].solve(rInfoProvider, 
NumberType::ycoordinate) - maPosition.getY();
-
-                if(a < nSizeDy)
-                {
-                    nPos += rSvgTextPositions.getDy()[a].solve(rInfoProvider, 
NumberType::ycoordinate);
-                }
-
-                maY.push_back(nPos);
-            }
+            return pPreviousCharacterNode;
         }
 
-        bool SvgTextPosition::isRotated() const
+        void SvgCharacterNode::concatenate(std::u16string_view rText)
         {
-            if(maRotate.empty())
-            {
-                if(getParent())
-                {
-                    return getParent()->isRotated();
-                }
-                else
-                {
-                    return false;
-                }
-            }
-            else
-            {
-                return true;
-            }
+            maText += rText;
         }
 
-        double SvgTextPosition::consumeRotation()
+        void SvgCharacterNode::decomposeText(Primitive2DContainer& rTarget, 
SvgTextPosition& rSvgTextPosition) const
         {
-            double fRetval(0.0);
-
-            if(maRotate.empty())
-            {
-                if(getParent())
-                {
-                    fRetval = mpParent->consumeRotation();
-                }
-                else
-                {
-                    fRetval = 0.0;
-                }
-            }
-            else
+            if(!getText().isEmpty())
             {
-                const sal_uInt32 nSize(maRotate.size());
+                const SvgStyleAttributes* pSvgStyleAttributes = 
getSvgStyleAttributes();
 
-                if(mnRotationIndex < nSize)
-                {
-                    fRetval = maRotate[mnRotationIndex++];
-                }
-                else
+                if(pSvgStyleAttributes)
                 {
-                    fRetval = maRotate[nSize - 1];
+                    decomposeTextWithStyle(rTarget, rSvgTextPosition, 
*pSvgStyleAttributes);
                 }
             }
-
-            return fRetval;
         }
 
 } // end of namespace svgio
diff --git a/svgio/source/svgreader/svgdocumenthandler.cxx 
b/svgio/source/svgreader/svgdocumenthandler.cxx
index 2e7785f2626d..45213997144c 100644
--- a/svgio/source/svgreader/svgdocumenthandler.cxx
+++ b/svgio/source/svgreader/svgdocumenthandler.cxx
@@ -54,7 +54,6 @@
 #include <svgtitledescnode.hxx>
 #include <sal/log.hxx>
 #include <osl/diagnose.h>
-#include <o3tl/string_view.hxx>
 
 using namespace com::sun::star;
 
@@ -63,7 +62,7 @@ namespace svgio::svgreader
 
 namespace
 {
-    svgio::svgreader::SvgCharacterNode* 
whiteSpaceHandling(svgio::svgreader::SvgNode const * pNode, 
svgio::svgreader::SvgCharacterNode* pLast)
+    svgio::svgreader::SvgCharacterNode* 
whiteSpaceHandling(svgio::svgreader::SvgNode const * pNode, 
svgio::svgreader::SvgTextNode* pText, svgio::svgreader::SvgCharacterNode* pLast)
     {
         if(pNode)
         {
@@ -84,45 +83,10 @@ namespace
                             svgio::svgreader::SvgCharacterNode* pCharNode = 
static_cast< svgio::svgreader::SvgCharacterNode* >(pCandidate);
 
                             pCharNode->whiteSpaceHandling();
+                            pLast = pCharNode->addGap(pLast);
 
-                            // pCharNode may have lost all text. If that's the 
case, ignore
-                            // as invalid character node
-                            // Also ignore if textBeforeSpaceHandling just 
have spaces
-                            if(!pCharNode->getText().isEmpty() && 
!o3tl::trim(pCharNode->getTextBeforeSpaceHandling()).empty())
-                            {
-                                if(pLast)
-                                {
-                                    bool bAddGap(true);
-
-                                    // Do not add a gap if last node doesn't 
end with a space and
-                                    // current note doesn't start with a space
-                                    const sal_uInt32 
nLastLength(pLast->getTextBeforeSpaceHandling().getLength());
-                                    
if(pLast->getTextBeforeSpaceHandling()[nLastLength - 1] != ' ' && 
pCharNode->getTextBeforeSpaceHandling()[0] != ' ')
-                                        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#
-                                    const 
svgio::svgreader::SvgStyleAttributes* pStyleLast = 
pLast->getSvgStyleAttributes();
-                                    const 
svgio::svgreader::SvgStyleAttributes* pStyleCurrent = 
pCandidate->getSvgStyleAttributes();
-
-                                    if(pStyleLast && pStyleCurrent && 
pStyleLast->getBaselineShift() != pStyleCurrent->getBaselineShift())
-                                    {
-                                        bAddGap = false;
-                                    }
-
-                                    // add in-between whitespace (single 
space) to last
-                                    // known character node
-                                    if(bAddGap)
-                                    {
-                                        pLast->addGap();
-                                    }
-                                }
-
-                                // remember new last corrected character node
-                                pLast = pCharNode;
-                            }
-
+                            pCharNode->setTextParent(pText);
+                            pText->concatenateTextLine(pCharNode->getText());
                             break;
                         }
                         case SVGToken::Tspan:
@@ -130,7 +94,7 @@ namespace
                         case SVGToken::Tref:
                         {
                             // recursively clean whitespaces in subhierarchy
-                            pLast = whiteSpaceHandling(pCandidate, pLast);
+                            pLast = whiteSpaceHandling(pCandidate, pText, 
pLast);
                             break;
                         }
                         default:
@@ -145,6 +109,7 @@ namespace
 
         return pLast;
     }
+
 } // end anonymous namespace
 
         SvgDocHdl::SvgDocHdl(const OUString& aAbsolutePath)
@@ -323,7 +288,7 @@ namespace
                 }
                 case SVGToken::Tspan:
                 {
-                    mpTarget = new SvgTspanNode(maDocument, mpTarget);
+                    mpTarget = new SvgTspanNode(aSVGToken, maDocument, 
mpTarget);
                     mpTarget->parseAttributes(xAttribs);
                     break;
                 }
@@ -463,7 +428,7 @@ namespace
                 return;
 
             const SVGToken aSVGToken(StrToSVGToken(aName, false));
-            SvgNode* pWhitespaceCheck(SVGToken::Text == aSVGToken ? mpTarget : 
nullptr);
+            SvgNode* pTextNode(SVGToken::Text == aSVGToken ? mpTarget : 
nullptr);
             SvgStyleNode* pCssStyle(SVGToken::Style == aSVGToken ? 
static_cast< SvgStyleNode* >(mpTarget) : nullptr);
             SvgTitleDescNode* pSvgTitleDescNode(SVGToken::Title == aSVGToken 
|| SVGToken::Desc == aSVGToken ? static_cast< SvgTitleDescNode* >(mpTarget) : 
nullptr);
 
@@ -584,10 +549,10 @@ namespace
                 }
             }
 
-            if(pWhitespaceCheck)
+            if(pTextNode)
             {
                 // cleanup read strings
-                whiteSpaceHandling(pWhitespaceCheck, nullptr);
+                whiteSpaceHandling(pTextNode, static_cast< 
SvgTextNode*>(pTextNode), nullptr);
             }
         }
 
@@ -605,24 +570,23 @@ namespace
                 case SVGToken::TextPath:
                 {
                     const auto& rChilds = mpTarget->getChildren();
-                    SvgCharacterNode* pTarget = nullptr;
 
                     if(!rChilds.empty())
                     {
-                        pTarget = dynamic_cast< SvgCharacterNode* 
>(rChilds[rChilds.size() - 1].get());
-                    }
+                        SvgNode* pChild = rChilds[rChilds.size() - 1].get();
+                        if ( pChild->getType() == SVGToken::Character )
+                        {
+                            SvgCharacterNode& rSvgCharacterNode = static_cast< 
SvgCharacterNode& >(*pChild);
 
-                    if(pTarget)
-                    {
-                        // concatenate to current character span
-                        pTarget->concatenate(aChars);
-                    }
-                    else
-                    {
-                        // add character span as simplified tspan (no 
arguments)
-                        // as direct child of 
SvgTextNode/SvgTspanNode/SvgTextPathNode
-                        new SvgCharacterNode(maDocument, mpTarget, aChars);
+                            // concatenate to current character span
+                            rSvgCharacterNode.concatenate(aChars);
+                            break;
+                        }
                     }
+
+                    // add character span as simplified tspan (no arguments)
+                    // as direct child of 
SvgTextNode/SvgTspanNode/SvgTextPathNode
+                    new SvgCharacterNode(maDocument, mpTarget, aChars);
                     break;
                 }
                 case SVGToken::Style:
diff --git a/svgio/source/svgreader/svgtextnode.cxx 
b/svgio/source/svgreader/svgtextnode.cxx
index 5b8cc3187070..bd8a334c5e11 100644
--- a/svgio/source/svgreader/svgtextnode.cxx
+++ b/svgio/source/svgreader/svgtextnode.cxx
@@ -30,8 +30,7 @@ namespace svgio::svgreader
         SvgTextNode::SvgTextNode(
             SvgDocument& rDocument,
             SvgNode* pParent)
-        :   SvgNode(SVGToken::Text, rDocument, pParent),
-            maSvgStyleAttributes(*this)
+        :   SvgTspanNode(SVGToken::Text, rDocument, pParent)
         {
         }
 
@@ -39,30 +38,14 @@ namespace svgio::svgreader
         {
         }
 
-        const SvgStyleAttributes* SvgTextNode::getSvgStyleAttributes() const
-        {
-            return checkForCssStyle(maSvgStyleAttributes);
-        }
-
         void SvgTextNode::parseAttribute(const OUString& rTokenName, SVGToken 
aSVGToken, const OUString& aContent)
         {
             // call parent
-            SvgNode::parseAttribute(rTokenName, aSVGToken, aContent);
-
-            // read style attributes
-            maSvgStyleAttributes.parseStyleAttribute(aSVGToken, aContent);
-
-            // read text position attributes
-            maSvgTextPositions.parseTextPositionAttributes(aSVGToken, 
aContent);
+            SvgTspanNode::parseAttribute(rTokenName, aSVGToken, aContent);
 
             // parse own
             switch(aSVGToken)
             {
-                case SVGToken::Style:
-                {
-                    readLocalCssStyle(aContent);
-                    break;
-                }
                 case SVGToken::Transform:
                 {
                     const basegfx::B2DHomMatrix 
aMatrix(readTransform(aContent, *this));
@@ -159,7 +142,7 @@ namespace svgio::svgreader
 
                     if(nCount)
                     {
-                        SvgTextPosition aSvgTextPosition(&rSvgTextPosition, 
rSvgTspanNode, rSvgTspanNode.getSvgTextPositions());
+                        SvgTextPosition aSvgTextPosition(&rSvgTextPosition, 
rSvgTspanNode);
                         drawinglayer::primitive2d::Primitive2DContainer 
aNewTarget;
 
                         for(sal_uInt32 a(0); a < nCount; a++)
@@ -229,7 +212,7 @@ namespace svgio::svgreader
             if(fOpacity <= 0.0)
                 return;
 
-            SvgTextPosition aSvgTextPosition(nullptr, *this, 
maSvgTextPositions);
+            SvgTextPosition aSvgTextPosition(nullptr, *this);
             drawinglayer::primitive2d::Primitive2DContainer aNewTarget;
             const auto& rChildren = getChildren();
             const sal_uInt32 nCount(rChildren.size());
diff --git a/svgio/source/svgreader/svgtextposition.cxx 
b/svgio/source/svgreader/svgtextposition.cxx
new file mode 100644
index 000000000000..50a896ba2204
--- /dev/null
+++ b/svgio/source/svgreader/svgtextposition.cxx
@@ -0,0 +1,200 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements. See the NOTICE file distributed
+ *   with this work for additional information regarding copyright
+ *   ownership. The ASF licenses this file to you under the Apache
+ *   License, Version 2.0 (the "License"); you may not use this file
+ *   except in compliance with the License. You may obtain a copy of
+ *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svgtextposition.hxx>
+
+using namespace drawinglayer::primitive2d;
+
+namespace svgio::svgreader
+{
+SvgTextPosition::SvgTextPosition(SvgTextPosition* pParent, const SvgTspanNode& 
rSvgTspanNode)
+    : mpParent(pParent)
+    , maRotate(solveSvgNumberVector(rSvgTspanNode.getRotate(), rSvgTspanNode))
+    , mfTextLength(0.0)
+    , mnRotationIndex(0)
+    , mbLengthAdjust(rSvgTspanNode.getLengthAdjust())
+    , mbAbsoluteX(false)
+{
+    const InfoProvider& rInfoProvider(rSvgTspanNode);
+
+    // get TextLength if provided
+    if (rSvgTspanNode.getTextLength().isSet())
+    {
+        mfTextLength = rSvgTspanNode.getTextLength().solve(rInfoProvider);
+    }
+
+    // SVG does not really define in which units a \91rotate\92 for Text/TSpan 
is given,
+    // but it seems to be degrees. Convert here to radians
+    if (!maRotate.empty())
+    {
+        for (double& f : maRotate)
+        {
+            f = basegfx::deg2rad(f);
+        }
+    }
+
+    // get text positions X
+    const sal_uInt32 nSizeX(rSvgTspanNode.getX().size());
+
+    if (nSizeX)
+    {
+        // we have absolute positions, get first one as current text position X
+        maPosition.setX(rSvgTspanNode.getX()[0].solve(rInfoProvider, 
NumberType::xcoordinate));
+        mbAbsoluteX = true;
+    }
+    else
+    {
+        // no absolute position, get from parent
+        if (pParent)
+        {
+            maPosition.setX(pParent->getPosition().getX());
+        }
+    }
+
+    const sal_uInt32 nSizeDx(rSvgTspanNode.getDx().size());
+    if (nSizeDx)
+    {
+        // relative positions given, translate position derived from parent
+        maPosition.setX(maPosition.getX()
+                        + rSvgTspanNode.getDx()[0].solve(rInfoProvider, 
NumberType::xcoordinate));
+    }
+
+    // fill deltas to maX
+    maX.reserve(nSizeX);
+
+    for (sal_uInt32 a(1); a < std::max(nSizeX, nSizeDx); ++a)
+    {
+        if (a < nSizeX)
+        {
+            double nPos = rSvgTspanNode.getX()[a].solve(rInfoProvider, 
NumberType::xcoordinate)
+                          - maPosition.getX();
+
+            if (a < nSizeDx)
+            {
+                nPos += rSvgTspanNode.getDx()[a].solve(rInfoProvider, 
NumberType::xcoordinate);
+            }
+
+            maX.push_back(nPos);
+        }
+        else
+        {
+            // Apply them later since it also needs the character width to 
calculate
+            // the final character position
+            maDx.push_back(rSvgTspanNode.getDx()[a].solve(rInfoProvider, 
NumberType::xcoordinate));
+        }
+    }
+
+    // get text positions Y
+    const sal_uInt32 nSizeY(rSvgTspanNode.getY().size());
+
+    if (nSizeY)
+    {
+        // we have absolute positions, get first one as current text position Y
+        maPosition.setY(rSvgTspanNode.getY()[0].solve(rInfoProvider, 
NumberType::ycoordinate));
+        mbAbsoluteX = true;
+    }
+    else
+    {
+        // no absolute position, get from parent
+        if (pParent)
+        {
+            maPosition.setY(pParent->getPosition().getY());
+        }
+    }
+
+    const sal_uInt32 nSizeDy(rSvgTspanNode.getDy().size());
+
+    if (nSizeDy)
+    {
+        // relative positions given, translate position derived from parent
+        maPosition.setY(maPosition.getY()
+                        + rSvgTspanNode.getDy()[0].solve(rInfoProvider, 
NumberType::ycoordinate));
+    }
+
+    // fill deltas to maY
+    maY.reserve(nSizeY);
+
+    for (sal_uInt32 a(1); a < nSizeY; a++)
+    {
+        double nPos = rSvgTspanNode.getY()[a].solve(rInfoProvider, 
NumberType::ycoordinate)
+                      - maPosition.getY();
+
+        if (a < nSizeDy)
+        {
+            nPos += rSvgTspanNode.getDy()[a].solve(rInfoProvider, 
NumberType::ycoordinate);
+        }
+
+        maY.push_back(nPos);
+    }
+}
+
+bool SvgTextPosition::isRotated() const
+{
+    if (maRotate.empty())
+    {
+        if (getParent())
+        {
+            return getParent()->isRotated();
+        }
+        else
+        {
+            return false;
+        }
+    }
+    else
+    {
+        return true;
+    }
+}
+
+double SvgTextPosition::consumeRotation()
+{
+    double fRetval(0.0);
+
+    if (maRotate.empty())
+    {
+        if (getParent())
+        {
+            fRetval = mpParent->consumeRotation();
+        }
+        else
+        {
+            fRetval = 0.0;
+        }
+    }
+    else
+    {
+        const sal_uInt32 nSize(maRotate.size());
+
+        if (mnRotationIndex < nSize)
+        {
+            fRetval = maRotate[mnRotationIndex++];
+        }
+        else
+        {
+            fRetval = maRotate[nSize - 1];
+        }
+    }
+
+    return fRetval;
+}
+
+} // end of namespace svgio
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svgio/source/svgreader/svgtspannode.cxx 
b/svgio/source/svgreader/svgtspannode.cxx
index df5e440080f8..4472b88ab3ad 100644
--- a/svgio/source/svgreader/svgtspannode.cxx
+++ b/svgio/source/svgreader/svgtspannode.cxx
@@ -18,14 +18,17 @@
  */
 
 #include <svgtspannode.hxx>
+#include <o3tl/string_view.hxx>
 
 namespace svgio::svgreader
 {
         SvgTspanNode::SvgTspanNode(
+            SVGToken aType,
             SvgDocument& rDocument,
             SvgNode* pParent)
-        :   SvgNode(SVGToken::Tspan, rDocument, pParent),
-            maSvgStyleAttributes(*this)
+        :   SvgNode(aType, rDocument, pParent),
+            maSvgStyleAttributes(*this),
+            mbLengthAdjust(true)
         {
         }
 
@@ -47,9 +50,6 @@ namespace svgio::svgreader
             // read style attributes
             maSvgStyleAttributes.parseStyleAttribute(aSVGToken, aContent);
 
-            // read text position attributes
-            maSvgTextPositions.parseTextPositionAttributes(aSVGToken, 
aContent);
-
             // parse own
             switch(aSVGToken)
             {
@@ -58,6 +58,81 @@ namespace svgio::svgreader
                     readLocalCssStyle(aContent);
                     break;
                 }
+                case SVGToken::X:
+                {
+                    SvgNumberVector aVector;
+
+                    if(readSvgNumberVector(aContent, aVector))
+                    {
+                        setX(std::move(aVector));
+                    }
+                    break;
+                }
+                case SVGToken::Y:
+                {
+                    SvgNumberVector aVector;
+
+                    if(readSvgNumberVector(aContent, aVector))
+                    {
+                        setY(std::move(aVector));
+                    }
+                    break;
+                }
+                case SVGToken::Dx:
+                {
+                    SvgNumberVector aVector;
+
+                    if(readSvgNumberVector(aContent, aVector))
+                    {
+                        setDx(std::move(aVector));
+                    }
+                    break;
+                }
+                case SVGToken::Dy:
+                {
+                    SvgNumberVector aVector;
+
+                    if(readSvgNumberVector(aContent, aVector))
+                    {
+                        setDy(std::move(aVector));
+                    }
+                    break;
+                }
+                case SVGToken::Rotate:
+                {
+                    SvgNumberVector aVector;
+
+                    if(readSvgNumberVector(aContent, aVector))
+                    {
+                        setRotate(std::move(aVector));
+                    }
+                    break;
+                }
+                case SVGToken::TextLength:
+                {
+                    SvgNumber aNum;
+
+                    if(readSingleNumber(aContent, aNum))
+                    {
+                        if(aNum.isPositive())
+                        {
+                            setTextLength(aNum);
+                        }
+                    }
+                    break;
+                }
+                case SVGToken::LengthAdjust:
+                {
+                    if(o3tl::equalsIgnoreAsciiCase(o3tl::trim(aContent), 
u"spacing"))
+                    {
+                        setLengthAdjust(true);
+                    }
+                    else if(o3tl::equalsIgnoreAsciiCase(o3tl::trim(aContent), 
u"spacingAndGlyphs"))
+                    {
+                        setLengthAdjust(false);
+                    }
+                    break;
+                }
                 default:
                 {
                     break;

Reply via email to