include/vcl/outdev.hxx                    |    6 ++--
 starmath/inc/visitors.hxx                 |    7 ++++-
 starmath/source/ElementsDockingWindow.cxx |    2 -
 starmath/source/document.cxx              |   41 ++++++++++++++++++++++--------
 starmath/source/visitors.cxx              |   15 ++++++++++
 5 files changed, 56 insertions(+), 15 deletions(-)

New commits:
commit fb43c497f2cc71c988a967fa0126c27561f8c16d
Author:     Khaled Hosny <kha...@libreoffice.org>
AuthorDate: Wed Aug 16 15:17:41 2023 +0300
Commit:     خالد حسني <kha...@libreoffice.org>
CommitDate: Mon Sep 4 18:17:15 2023 +0200

    tdf#134193: Support rendering math in RTL mode
    
    Respect IsRightToLeft property and render accordingly.
    
    This also fixes math rendering in RTL UI, which was incorrectly rendered 
RTL.
    
    Change-Id: Id8520930f09a21daa1c70e40a765ac25572ea994
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/155738
    Tested-by: Jenkins
    Reviewed-by: خالد حسني <kha...@libreoffice.org>

diff --git a/include/vcl/outdev.hxx b/include/vcl/outdev.hxx
index 898939978daa..f2fdf7ab7db7 100644
--- a/include/vcl/outdev.hxx
+++ b/include/vcl/outdev.hxx
@@ -1217,9 +1217,9 @@ public:
 
     // tells whether this output device is RTL in an LTR UI or LTR in a RTL UI
     SAL_DLLPRIVATE bool         ImplIsAntiparallel() const ;
-    SAL_DLLPRIVATE void         ReMirror( Point &rPoint ) const;
-    SAL_DLLPRIVATE void         ReMirror( tools::Rectangle &rRect ) const;
-    SAL_DLLPRIVATE void         ReMirror( vcl::Region &rRegion ) const;
+                   void         ReMirror( Point &rPoint ) const;
+                   void         ReMirror( tools::Rectangle &rRect ) const;
+                   void         ReMirror( vcl::Region &rRegion ) const;
     SAL_DLLPRIVATE bool         ImplIsRecordLayout() const;
     virtual bool                HasMirroredGraphics() const;
     std::unique_ptr<SalLayout>
diff --git a/starmath/inc/visitors.hxx b/starmath/inc/visitors.hxx
index eaf329034c7d..c1a2a8983286 100644
--- a/starmath/inc/visitors.hxx
+++ b/starmath/inc/visitors.hxx
@@ -211,12 +211,16 @@ public:
      * @param rDevice   Device to draw on
      * @param position  Offset on device to draw the formula
      * @param pTree     Formula tree to draw
+     * @param rFormat   Formula formatting settings
      * @remarks This constructor will do the drawing, no need to anything more.
      */
-    SmDrawingVisitor( OutputDevice &rDevice, Point position, SmNode* pTree )
+    SmDrawingVisitor( OutputDevice &rDevice, Point position, SmNode* pTree, 
const SmFormat& rFormat )
         : mrDev( rDevice )
         , maPosition( position )
+        , mrFormat( rFormat )
     {
+        if (mrFormat.IsRightToLeft())
+            mrDev.ReMirror(maPosition);
         pTree->Accept( this );
     }
     virtual ~SmDrawingVisitor() {}
@@ -265,6 +269,7 @@ private:
                 so if needed cache it locally on the stack.
      */
     Point maPosition;
+    const SmFormat& mrFormat;
 };
 
 // SmSetSelectionVisitor
diff --git a/starmath/source/ElementsDockingWindow.cxx 
b/starmath/source/ElementsDockingWindow.cxx
index 7fdfb3b3ec49..d1feabd921a9 100644
--- a/starmath/source/ElementsDockingWindow.cxx
+++ b/starmath/source/ElementsDockingWindow.cxx
@@ -546,7 +546,7 @@ void SmElementsControl::addElement(const OUString& 
aElementVisual, const OUStrin
     Size aSize = pDevice->LogicToPixel(Size(pNode->GetWidth(), 
pNode->GetHeight()));
     aSize.extendBy(10, 0); // Add 5 pixels from both sides to accommodate 
extending parts of italics
     pDevice->SetOutputSizePixel(aSize);
-    SmDrawingVisitor(*pDevice, pDevice->PixelToLogic(Point(5, 0)), 
pNode.get());
+    SmDrawingVisitor(*pDevice, pDevice->PixelToLogic(Point(5, 0)), 
pNode.get(), maFormat);
 
     maItemDatas.push_back(std::make_unique<ElementData>(aElementSource, 
aHelpText));
     const OUString aId(weld::toId(maItemDatas.back().get()));
diff --git a/starmath/source/document.cxx b/starmath/source/document.cxx
index c0f28ac18190..9bdaad7530e6 100644
--- a/starmath/source/document.cxx
+++ b/starmath/source/document.cxx
@@ -261,10 +261,18 @@ void SmDocShell::ArrangeFormula()
     const SmFormat &rFormat = GetFormat();
     mpTree->Prepare(rFormat, *this, 0);
 
-    // format/draw formulas always from left to right,
-    // and numbers should not be converted
-    pOutDev->Push(vcl::PushFlags::TEXTLAYOUTMODE | 
vcl::PushFlags::TEXTLANGUAGE);
-    pOutDev->SetLayoutMode( vcl::text::ComplexTextLayoutFlags::Default );
+    pOutDev->Push(vcl::PushFlags::TEXTLAYOUTMODE | 
vcl::PushFlags::TEXTLANGUAGE |
+                  vcl::PushFlags::RTLENABLED);
+
+    // We want the device to always be LTR, we handle RTL formulas ourselves.
+    pOutDev->EnableRTL(false);
+
+    // For RTL formulas, we want the brackets to be mirrored.
+    bool bRTL = GetFormat().IsRightToLeft();
+    pOutDev->SetLayoutMode(bRTL ? vcl::text::ComplexTextLayoutFlags::BiDiRtl
+                                : vcl::text::ComplexTextLayoutFlags::Default);
+
+    // Numbers should not be converted, for now.
     pOutDev->SetDigitLanguage( LANGUAGE_ENGLISH );
 
     mpTree->Arrange(*pOutDev, rFormat);
@@ -313,6 +321,8 @@ void SmDocShell::DrawFormula(OutputDevice &rDev, Point 
&rPosition, bool bDrawSel
 
     ArrangeFormula();
 
+    bool bRTL = GetFormat().IsRightToLeft();
+
     // Problem: What happens to WYSIWYG? While we're active inplace, we don't 
have a reference
     // device and aren't aligned to that either. So now there can be a 
difference between the
     // VisArea (i.e. the size within the client) and the current size.
@@ -321,6 +331,10 @@ void SmDocShell::DrawFormula(OutputDevice &rDev, Point 
&rPosition, bool bDrawSel
     rPosition.AdjustX(maFormat.GetDistance( DIS_LEFTSPACE ) );
     rPosition.AdjustY(maFormat.GetDistance( DIS_TOPSPACE  ) );
 
+    Point aPosition(rPosition);
+    if (bRTL)
+        aPosition.AdjustX(GetSize().Width() - 
maFormat.GetDistance(DIS_LEFTSPACE) - maFormat.GetDistance(DIS_RIGHTSPACE));
+
     //! in case of high contrast-mode (accessibility option!)
     //! the draw mode needs to be set to default, because when embedding
     //! Math for example in Calc in "a over b" the fraction bar may not
@@ -335,20 +349,27 @@ void SmDocShell::DrawFormula(OutputDevice &rDev, Point 
&rPosition, bool bDrawSel
         bRestoreDrawMode = true;
     }
 
-    // format/draw formulas always from left to right
-    // and numbers should not be converted
-    rDev.Push(vcl::PushFlags::TEXTLAYOUTMODE | vcl::PushFlags::TEXTLANGUAGE);
-    rDev.SetLayoutMode( vcl::text::ComplexTextLayoutFlags::Default );
+    rDev.Push(vcl::PushFlags::TEXTLAYOUTMODE | vcl::PushFlags::TEXTLANGUAGE |
+              vcl::PushFlags::RTLENABLED);
+
+    // We want the device to always be LTR, we handle RTL formulas ourselves.
+    rDev.EnableRTL(false);
+
+    // For RTL formulas, we want the brackets to be mirrored.
+    rDev.SetLayoutMode(bRTL ? vcl::text::ComplexTextLayoutFlags::BiDiRtl
+                            : vcl::text::ComplexTextLayoutFlags::Default);
+
+    // Numbers should not be converted, for now.
     rDev.SetDigitLanguage( LANGUAGE_ENGLISH );
 
     //Set selection if any
     if(mpCursor && bDrawSelection){
         mpCursor->AnnotateSelection();
-        SmSelectionDrawingVisitor(rDev, mpTree.get(), rPosition);
+        SmSelectionDrawingVisitor(rDev, mpTree.get(), aPosition);
     }
 
     //Drawing using visitor
-    SmDrawingVisitor(rDev, rPosition, mpTree.get());
+    SmDrawingVisitor(rDev, aPosition, mpTree.get(), GetFormat());
 
     rDev.Pop();
 
diff --git a/starmath/source/visitors.cxx b/starmath/source/visitors.cxx
index a15a62a4b048..cece754de276 100644
--- a/starmath/source/visitors.cxx
+++ b/starmath/source/visitors.cxx
@@ -437,6 +437,10 @@ void SmDrawingVisitor::Visit( SmRootSymbolNode* pNode )
     Point aBarPos( maPosition + aBarOffset );
 
     tools::Rectangle  aBar( aBarPos, Size( nBarWidth, nBarHeight ) );
+
+    if (mrFormat.IsRightToLeft())
+        mrDev.ReMirror(aBar);
+
     //! avoid GROWING AND SHRINKING of drawn rectangle when constantly
     //! increasing zoomfactor.
     //  This is done by shifting its output-position to a point that
@@ -460,6 +464,10 @@ void SmDrawingVisitor::Visit( SmPolyLineNode* pNode )
     Point aOffset ( Point( ) - pNode->GetPolygon( ).GetBoundRect( ).TopLeft( )
                    + Point( nBorderwidth, nBorderwidth ) ),
           aPos ( maPosition + aOffset );
+
+    if (mrFormat.IsRightToLeft())
+        mrDev.ReMirror(aPos);
+
     pNode->GetPolygon( ).Move( aPos.X( ), aPos.Y( ) );    //Works because 
Polygon wraps a pointer
 
     SmTmpDevice aTmpDev ( mrDev, false );
@@ -489,6 +497,9 @@ void SmDrawingVisitor::Visit( SmRectangleNode* pNode )
 
     SAL_WARN_IF( aTmp.IsEmpty(), "starmath", "Empty rectangle" );
 
+    if (mrFormat.IsRightToLeft())
+        mrDev.ReMirror(aTmp);
+
     //! avoid GROWING AND SHRINKING of drawn rectangle when constantly
     //! increasing zoomfactor.
     //  This is done by shifting its output-position to a point that
@@ -509,6 +520,10 @@ void SmDrawingVisitor::DrawTextNode( SmTextNode* pNode )
 
     Point  aPos ( maPosition );
     aPos.AdjustY(pNode->GetBaselineOffset( ) );
+
+    if (mrFormat.IsRightToLeft())
+        mrDev.ReMirror(aPos);
+
     // round to pixel coordinate
     aPos = mrDev.PixelToLogic( mrDev.LogicToPixel( aPos ) );
 

Reply via email to