svgio/inc/svgcharacternode.hxx                |    4 +
 svgio/inc/svgtspannode.hxx                    |    8 +-
 svgio/qa/cppunit/SvgImportTest.cxx            |   27 ++++++++++
 svgio/qa/cppunit/data/tdf93583.svg            |    7 ++
 svgio/source/svgreader/svgcharacternode.cxx   |   70 +++++++++++++-------------
 svgio/source/svgreader/svgdocumenthandler.cxx |   24 ++++++++
 svgio/source/svgreader/svgtspannode.cxx       |    3 -
 7 files changed, 104 insertions(+), 39 deletions(-)

New commits:
commit 12eb15a9fac58fe2fb5baeeb35f8c43ba21b2e1e
Author:     Xisco Fauli <xiscofa...@libreoffice.org>
AuthorDate: Mon Aug 14 14:52:41 2023 +0200
Commit:     Michael Stahl <michael.st...@allotropia.de>
CommitDate: Wed Aug 16 11:12:39 2023 +0200

    tdf#93583: use getTextWidth to calculate line's width
    
    Since every character in the line might use different styles
    Change-Id: I2ce079d4308f4acde42a8366838749a7c20331b4
    
    Change-Id: I01f51f157caa667cebc8860ae37d4458fac2d511
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/155666
    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/+/155724
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>

diff --git a/svgio/inc/svgcharacternode.hxx b/svgio/inc/svgcharacternode.hxx
index 059aa9ece1fd..d81066af47a6 100644
--- a/svgio/inc/svgcharacternode.hxx
+++ b/svgio/inc/svgcharacternode.hxx
@@ -24,6 +24,7 @@
 
 #include <string_view>
 
+#include <drawinglayer/attribute/fontattribute.hxx>
 #include "svgtextnode.hxx"
 #include "svgtextposition.hxx"
 
@@ -58,6 +59,9 @@ namespace svgio::svgreader
                 OUString aText);
             virtual ~SvgCharacterNode() override;
 
+            static drawinglayer::attribute::FontAttribute getFontAttribute(
+                const SvgStyleAttributes& rSvgStyleAttributes);
+
             virtual const SvgStyleAttributes* getSvgStyleAttributes() const 
override;
 
             void 
decomposeText(drawinglayer::primitive2d::Primitive2DContainer& rTarget, 
SvgTextPosition& rSvgTextPosition) const;
diff --git a/svgio/inc/svgtspannode.hxx b/svgio/inc/svgtspannode.hxx
index 92ed8319c628..991b0ac451f6 100644
--- a/svgio/inc/svgtspannode.hxx
+++ b/svgio/inc/svgtspannode.hxx
@@ -39,9 +39,9 @@ namespace svgio::svgreader
 
             bool                    mbLengthAdjust : 1; // true = spacing, 
false = spacingAndGlyphs
 
-            // The text line composed by the different SvgCharacterNode 
children
+            // The text line width composed by the different SvgCharacterNode 
children
             // it will be used to calculate their alignment
-            OUString maTextLine;
+            double mnTextLineWidth;
 
         public:
             SvgTspanNode(
@@ -83,8 +83,8 @@ namespace svgio::svgreader
             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; }
+            void concatenateTextLineWidth(double nWidth) {mnTextLineWidth += 
nWidth;}
+            double getTextLineWith() const { return mnTextLineWidth; }
         };
 
 } // end of namespace svgio::svgreader
diff --git a/svgio/qa/cppunit/SvgImportTest.cxx 
b/svgio/qa/cppunit/SvgImportTest.cxx
index 42cb98c4b6be..4032c934658e 100644
--- a/svgio/qa/cppunit/SvgImportTest.cxx
+++ b/svgio/qa/cppunit/SvgImportTest.cxx
@@ -742,6 +742,33 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf85770)
     assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[3]", 
"familyname", "Times New Roman");
 }
 
+CPPUNIT_TEST_FIXTURE(Test, testTdf93583)
+{
+    Primitive2DSequence aSequence = 
parseSvg(u"/svgio/qa/cppunit/data/tdf93583.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", "This is the");
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[1]", "x", 
"62");
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[1]", "y", 
"303");
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[1]", 
"width", "16");
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[1]", 
"height", "16");
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[2]", 
"text", " first");
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[2]", "x", 
"127");
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[2]", "y", 
"303");
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[2]", 
"width", "32");
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[2]", 
"height", "32");
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[3]", 
"text", " line");
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[3]", "x", 
"187");
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[3]", "y", 
"303");
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[3]", 
"width", "16");
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[3]", 
"height", "16");
+}
+
 CPPUNIT_TEST_FIXTURE(Test, testTdf156616)
 {
     Primitive2DSequence aSequence = 
parseSvg(u"/svgio/qa/cppunit/data/tdf156616.svg");
diff --git a/svgio/qa/cppunit/data/tdf93583.svg 
b/svgio/qa/cppunit/data/tdf93583.svg
new file mode 100644
index 000000000000..13e63e677ffb
--- /dev/null
+++ b/svgio/qa/cppunit/data/tdf93583.svg
@@ -0,0 +1,7 @@
+<svg viewBox="0 0 500 500" xmlns="http://www.w3.org/2000/svg";>
+      <text
+         style="text-anchor:end"
+         x="214"
+         y="303"><tspan>This is the<tspan style="font-size:200%"> first 
</tspan>line</tspan>
+      </text>
+</svg>
diff --git a/svgio/source/svgreader/svgcharacternode.cxx 
b/svgio/source/svgreader/svgcharacternode.cxx
index 9ba70ffb3ef5..ebc317c3a445 100644
--- a/svgio/source/svgreader/svgcharacternode.cxx
+++ b/svgio/source/svgreader/svgcharacternode.cxx
@@ -19,7 +19,6 @@
 
 #include <svgcharacternode.hxx>
 #include <svgstyleattributes.hxx>
-#include <drawinglayer/attribute/fontattribute.hxx>
 #include <drawinglayer/primitive2d/textprimitive2d.hxx>
 #include <drawinglayer/primitive2d/textlayoutdevice.hxx>
 #include <drawinglayer/primitive2d/textbreakuphelper.hxx>
@@ -100,6 +99,39 @@ namespace svgio::svgreader
             }
         }
 
+        drawinglayer::attribute::FontAttribute 
SvgCharacterNode::getFontAttribute(
+            const SvgStyleAttributes& rSvgStyleAttributes)
+        {
+            const SvgStringVector& rFontFamilyVector = 
rSvgStyleAttributes.getFontFamily();
+            OUString aFontFamily("Times New Roman");
+            if(!rFontFamilyVector.empty())
+                aFontFamily=rFontFamilyVector[0];
+
+            // #i122324# if the FontFamily name ends on ' embedded' it is 
probably a re-import
+            // of a SVG export with font embedding. Remove this to make font 
matching work. This
+            // is pretty safe since there should be no font family names 
ending on ' embedded'.
+            // Remove again when FontEmbedding is implemented in SVG import
+            if(aFontFamily.endsWith(" embedded"))
+            {
+                aFontFamily = aFontFamily.copy(0, aFontFamily.getLength() - 9);
+            }
+
+            const ::FontWeight 
nFontWeight(getVclFontWeight(rSvgStyleAttributes.getFontWeight()));
+            bool bItalic(FontStyle::italic == 
rSvgStyleAttributes.getFontStyle() || FontStyle::oblique == 
rSvgStyleAttributes.getFontStyle());
+
+            return drawinglayer::attribute::FontAttribute(
+                aFontFamily,
+                OUString(),
+                nFontWeight,
+                false/*bSymbol*/,
+                false/*bVertical*/,
+                bItalic,
+                false/*bMonospaced*/,
+                false/*bOutline*/,
+                false/*bRTL*/,
+                false/*bBiDiStrong*/);
+        }
+
         rtl::Reference<BasePrimitive2D> 
SvgCharacterNode::createSimpleTextPrimitive(
             SvgTextPosition& rSvgTextPosition,
             const SvgStyleAttributes& rSvgStyleAttributes) const
@@ -111,35 +143,9 @@ namespace svgio::svgreader
             if(nLength)
             {
                 sal_uInt32 nIndex(0);
-                // prepare FontAttribute
-                const SvgStringVector& rFontFamilyVector = 
rSvgStyleAttributes.getFontFamily();
-                OUString aFontFamily("Times New Roman");
-                if(!rFontFamilyVector.empty())
-                    aFontFamily=rFontFamilyVector[0];
-
-                // #i122324# if the FontFamily name ends on ' embedded' it is 
probably a re-import
-                // of a SVG export with font embedding. Remove this to make 
font matching work. This
-                // is pretty safe since there should be no font family names 
ending on ' embedded'.
-                // Remove again when FontEmbedding is implemented in SVG import
-                if(aFontFamily.endsWith(" embedded"))
-                {
-                    aFontFamily = aFontFamily.copy(0, aFontFamily.getLength() 
- 9);
-                }
 
-                const ::FontWeight 
nFontWeight(getVclFontWeight(rSvgStyleAttributes.getFontWeight()));
-                bool bItalic(FontStyle::italic == 
rSvgStyleAttributes.getFontStyle() || FontStyle::oblique == 
rSvgStyleAttributes.getFontStyle());
-
-                const drawinglayer::attribute::FontAttribute aFontAttribute(
-                    aFontFamily,
-                    OUString(),
-                    nFontWeight,
-                    false/*bSymbol*/,
-                    false/*bVertical*/,
-                    bItalic,
-                    false/*bMonospaced*/,
-                    false/*bOutline*/,
-                    false/*bRTL*/,
-                    false/*bBiDiStrong*/);
+                // prepare FontAttribute
+                const drawinglayer::attribute::FontAttribute 
aFontAttribute(getFontAttribute(rSvgStyleAttributes));
 
                 // prepare FontSizeNumber
                 double 
fFontWidth(rSvgStyleAttributes.getFontSizeNumber().solve(*this));
@@ -250,19 +256,17 @@ namespace svgio::svgreader
                     }
                 }
 
-                // Use the whole text line to calculate the align position
-                double 
fWholeTextLineWidth(aTextLayouterDevice.getTextWidth(mpParentLine->getTextLine(),
 0, mpParentLine->getTextLine().getLength()));
                 // apply TextAlign
                 switch(aTextAlign)
                 {
                     case TextAlign::right:
                     {
-                        aPosition.setX(aPosition.getX() - fWholeTextLineWidth);
+                        aPosition.setX(aPosition.getX() - 
mpParentLine->getTextLineWith());
                         break;
                     }
                     case TextAlign::center:
                     {
-                        aPosition.setX(aPosition.getX() - (fWholeTextLineWidth 
* 0.5));
+                        aPosition.setX(aPosition.getX() - 
(mpParentLine->getTextLineWith() * 0.5));
                         break;
                     }
                     case TextAlign::notset:
diff --git a/svgio/source/svgreader/svgdocumenthandler.cxx 
b/svgio/source/svgreader/svgdocumenthandler.cxx
index d552db8a0d19..f86d2603de2a 100644
--- a/svgio/source/svgreader/svgdocumenthandler.cxx
+++ b/svgio/source/svgreader/svgdocumenthandler.cxx
@@ -55,6 +55,9 @@
 #include <sal/log.hxx>
 #include <osl/diagnose.h>
 
+#include <com/sun/star/lang/Locale.hpp>
+#include <drawinglayer/primitive2d/textlayoutdevice.hxx>
+
 using namespace com::sun::star;
 
 namespace svgio::svgreader
@@ -87,7 +90,26 @@ namespace
                             pCharNode->whiteSpaceHandling();
                             pLast = pCharNode->addGap(pLast);
 
-                            
pParentLine->concatenateTextLine(pCharNode->getText());
+                            double fTextWidth(0.0);
+
+                            const SvgStyleAttributes* pSvgStyleAttributes = 
pCharNode->getSvgStyleAttributes();
+
+                            if(pSvgStyleAttributes)
+                            {
+                                const drawinglayer::attribute::FontAttribute 
aFontAttribute(
+                                        
svgio::svgreader::SvgCharacterNode::getFontAttribute(*pSvgStyleAttributes));
+
+                                double 
fFontWidth(pSvgStyleAttributes->getFontSizeNumber().solve(*pCharNode));
+                                double fFontHeight(fFontWidth);
+
+                                css::lang::Locale aLocale;
+
+                                drawinglayer::primitive2d::TextLayouterDevice 
aTextLayouterDevice;
+                                
aTextLayouterDevice.setFontAttribute(aFontAttribute, fFontWidth, fFontHeight, 
aLocale);
+                                fTextWidth = 
aTextLayouterDevice.getTextWidth(pCharNode->getText(), 0.0, 
pCharNode->getText().getLength());
+                            }
+
+                            pParentLine->concatenateTextLineWidth(fTextWidth);
                             break;
                         }
                         case SVGToken::Tspan:
diff --git a/svgio/source/svgreader/svgtspannode.cxx 
b/svgio/source/svgreader/svgtspannode.cxx
index 4472b88ab3ad..2ac7ee1118ed 100644
--- a/svgio/source/svgreader/svgtspannode.cxx
+++ b/svgio/source/svgreader/svgtspannode.cxx
@@ -28,7 +28,8 @@ namespace svgio::svgreader
             SvgNode* pParent)
         :   SvgNode(aType, rDocument, pParent),
             maSvgStyleAttributes(*this),
-            mbLengthAdjust(true)
+            mbLengthAdjust(true),
+            mnTextLineWidth(0.0)
         {
         }
 

Reply via email to