svgio/inc/svgstyleattributes.hxx              |   12 ++++++++
 svgio/qa/cppunit/SvgImportTest.cxx            |    8 +++++
 svgio/qa/cppunit/data/RTLtext.svg             |    7 +++++
 svgio/source/svgreader/svgcharacternode.cxx   |    3 +-
 svgio/source/svgreader/svgstyleattributes.cxx |   35 +++++++++++++++++++++++++-
 5 files changed, 63 insertions(+), 2 deletions(-)

New commits:
commit ae88cf4bc2b69282509128663f54e8c836e15c01
Author:     Xisco Fauli <xiscofa...@libreoffice.org>
AuthorDate: Mon Sep 15 16:53:37 2025 +0200
Commit:     Adolfo Jayme Barrientos <fit...@ubuntu.com>
CommitDate: Wed Sep 17 16:46:53 2025 +0200

    tdf#168421: support RTL text direction in svg
    
    Change-Id: Iba8853d131bf88be3cc94003a73ffe545cf62004
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/190978
    Tested-by: Jenkins
    Reviewed-by: Xisco Fauli <xiscofa...@libreoffice.org>
    (cherry picked from commit 4efae74abc8e7cefe2d7d0c3c55653dc269b8727)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/191004
    Reviewed-by: Adolfo Jayme Barrientos <fit...@ubuntu.com>

diff --git a/svgio/inc/svgstyleattributes.hxx b/svgio/inc/svgstyleattributes.hxx
index 9a9eccb55105..52c08d2ad4c6 100644
--- a/svgio/inc/svgstyleattributes.hxx
+++ b/svgio/inc/svgstyleattributes.hxx
@@ -115,6 +115,13 @@ namespace svgio::svgreader
             lighter,
         };
 
+        enum class FontDirection
+        {
+            notset,
+            LTR,
+            RTL,
+        };
+
         FontWeight getBolder(FontWeight aSource);
         FontWeight getLighter(FontWeight aSource);
         ::FontWeight getVclFontWeight(FontWeight aSource);
@@ -209,6 +216,7 @@ namespace svgio::svgreader
             FontStretch                 maFontStretch;
             FontStyle                   maFontStyle;
             FontWeight                  maFontWeight;
+            FontDirection               maFontDirection;
             TextAlign                   maTextAlign;
             TextDecoration              maTextDecoration;
             TextAnchor                  maTextAnchor;
@@ -416,6 +424,10 @@ namespace svgio::svgreader
             FontWeight getFontWeight() const;
             void setFontWeight(const FontWeight aFontWeight) { maFontWeight = 
aFontWeight; }
 
+            /// FontDirection content
+            FontDirection getFontDirection() const;
+            void setFontDirection(const FontDirection aFontDirection) { 
maFontDirection = aFontDirection; }
+
             /// TextAlign content
             TextAlign getTextAlign() const;
             void setTextAlign(const TextAlign aTextAlign) { maTextAlign = 
aTextAlign; }
diff --git a/svgio/qa/cppunit/SvgImportTest.cxx 
b/svgio/qa/cppunit/SvgImportTest.cxx
index 529ac1e9381e..24eeb8f562a9 100644
--- a/svgio/qa/cppunit/SvgImportTest.cxx
+++ b/svgio/qa/cppunit/SvgImportTest.cxx
@@ -2126,6 +2126,14 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf149880)
             
"/primitive2D/transform/mask/unhandled/mask/transform/transform/bitmap", 28);
 }
 
+CPPUNIT_TEST_FIXTURE(Test, testRTLtext)
+{
+    xmlDocUniquePtr pDocument = 
dumpAndParseSvg(u"/svgio/qa/cppunit/data/RTLtext.svg");
+
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[1]", 
"text", u"داستان SVG 1.1 SE طولا ني است.");
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[1]", 
"rtl", u"true");
+}
+
 CPPUNIT_TEST_FIXTURE(Test, testCssClassRedefinition)
 {
     // Tests for svg css class redefinition behavior
diff --git a/svgio/qa/cppunit/data/RTLtext.svg 
b/svgio/qa/cppunit/data/RTLtext.svg
new file mode 100644
index 000000000000..f360fc559dc6
--- /dev/null
+++ b/svgio/qa/cppunit/data/RTLtext.svg
@@ -0,0 +1,7 @@
+<svg
+  viewBox="0 0 600 72"
+  xmlns="http://www.w3.org/2000/svg";
+  direction="rtl"
+  font-family="DejaVu Sans">
+  <text x="300" y="50" text-anchor="middle">داستان SVG 1.1 SE طولا ني 
است.</text>
+</svg>
diff --git a/svgio/source/svgreader/svgcharacternode.cxx 
b/svgio/source/svgreader/svgcharacternode.cxx
index ca1f91ebb99a..e0ef204c4452 100644
--- a/svgio/source/svgreader/svgcharacternode.cxx
+++ b/svgio/source/svgreader/svgcharacternode.cxx
@@ -118,6 +118,7 @@ namespace svgio::svgreader
 
             const ::FontWeight 
nFontWeight(getVclFontWeight(rSvgStyleAttributes.getFontWeight()));
             bool bItalic(FontStyle::italic == 
rSvgStyleAttributes.getFontStyle() || FontStyle::oblique == 
rSvgStyleAttributes.getFontStyle());
+            bool bRTL(FontDirection::RTL == 
rSvgStyleAttributes.getFontDirection());
 
             return drawinglayer::attribute::FontAttribute(
                 aFontFamily,
@@ -128,7 +129,7 @@ namespace svgio::svgreader
                 bItalic,
                 false/*bMonospaced*/,
                 false/*bOutline*/,
-                false/*bRTL*/,
+                bRTL,
                 false/*bBiDiStrong*/);
         }
 
diff --git a/svgio/source/svgreader/svgstyleattributes.cxx 
b/svgio/source/svgreader/svgstyleattributes.cxx
index 219c0a20161e..6a9a20b56386 100644
--- a/svgio/source/svgreader/svgstyleattributes.cxx
+++ b/svgio/source/svgreader/svgstyleattributes.cxx
@@ -1391,6 +1391,7 @@ namespace svgio::svgreader
             maFontStretch(FontStretch::notset),
             maFontStyle(FontStyle::notset),
             maFontWeight(FontWeight::notset),
+            maFontDirection(FontDirection::notset),
             maTextAlign(TextAlign::notset),
             maTextDecoration(TextDecoration::notset),
             maTextAnchor(TextAnchor::notset),
@@ -1401,7 +1402,7 @@ namespace svgio::svgreader
             maBaselineShift(BaselineShift::Baseline),
             maBaselineShiftNumber(0),
             maDominantBaseline(DominantBaseline::Auto),
-            maResolvingParent(34, 0),
+            maResolvingParent(35, 0),
             mbStrokeDasharraySet(false),
             mbUseFillFromContextFill(false),
             mbUseFillFromContextStroke(false),
@@ -1840,6 +1841,17 @@ namespace svgio::svgreader
                 }
                 case SVGToken::Direction:
                 {
+                    if(!aContent.isEmpty())
+                    {
+                        if(o3tl::equalsIgnoreAsciiCase(o3tl::trim(aContent), 
u"ltr"))
+                        {
+                            setFontDirection(FontDirection::LTR);
+                        }
+                        else 
if(o3tl::equalsIgnoreAsciiCase(o3tl::trim(aContent), u"rtl"))
+                        {
+                            setFontDirection(FontDirection::RTL);
+                        }
+                    }
                     break;
                 }
                 case SVGToken::LetterSpacing:
@@ -2936,6 +2948,27 @@ namespace svgio::svgreader
             return FontWeight::N400;
         }
 
+        FontDirection SvgStyleAttributes::getFontDirection() const
+        {
+            if(maFontDirection != FontDirection::notset)
+            {
+                return maFontDirection;
+            }
+
+            const SvgStyleAttributes* pSvgStyleAttributes = 
getCssStyleOrParentStyle();
+            if (pSvgStyleAttributes && maResolvingParent[34] < 
nStyleDepthLimit)
+            {
+                ++maResolvingParent[34];
+                auto ret = pSvgStyleAttributes->getFontDirection();
+                --maResolvingParent[34];
+
+                return ret;
+            }
+
+            // default is LTR
+            return FontDirection::LTR;
+        }
+
         TextAlign SvgStyleAttributes::getTextAlign() const
         {
             if(maTextAlign != TextAlign::notset)

Reply via email to