sc/inc/document.hxx                                 |    3 
 sc/inc/drwlayer.hxx                                 |   14 +
 sc/inc/table.hxx                                    |    4 
 sc/qa/unit/data/ods/tdf137081_RTL_page_anchored.ods |binary
 sc/qa/unit/data/ods/tdf137082_LTR_arrow_image.ods   |binary
 sc/qa/unit/data/ods/tdf137082_RTL_cell_anchored.ods |binary
 sc/qa/unit/scshapetest.cxx                          |  155 +++++++++++++++++++
 sc/source/core/data/documen9.cxx                    |    4 
 sc/source/core/data/document.cxx                    |   14 -
 sc/source/core/data/drwlayer.cxx                    |  162 +++++++++++++++++---
 sc/source/core/data/table2.cxx                      |    6 
 sc/source/filter/xml/xmlexprt.cxx                   |   78 ++++++---
 sc/source/ui/docshell/docfunc.cxx                   |    2 
 sc/source/ui/undo/undotab.cxx                       |    2 
 14 files changed, 375 insertions(+), 69 deletions(-)

New commits:
commit 65129e0bc5abfe7afc612eb46f1434e627265a7d
Author:     Regina Henschel <rb.hensc...@t-online.de>
AuthorDate: Tue Jan 26 14:28:40 2021 +0100
Commit:     Regina Henschel <rb.hensc...@t-online.de>
CommitDate: Tue Feb 2 22:06:18 2021 +0100

    tdf#137081, tdf137082 fixes shape handling in RTL sheets
    
    The patch introduces an enum ScObjectHandling as parameter of
    ScDrawLayer::SetPageSize to distinguish page size changes from show or
    hide col/row from changes because of sheet flip for RTL.
    
    RTL is now handled this way: On save/reload objects are not mirrored
    but only shifted between positive and negative part of draw page. When
    a user flips sheet to RTL or back, the objects are mirrored.
    
    The 'noRotate' anchor is set to this meaning: maShapeRect contains the
    logic rectangle of the object at time the anchor was created. It is
    used to detect position relevant object changes in ScDrawView::Notify().
    maStart contains the address of that cell, which is parent element of
    the object in xml. The logic rectangle need not be in that cell.
    
    Handling of DetectiveArrow and CellNote is not changed. Validation
    circles were not drawn, when switching to RTL mode (no bug report).
    That is fixed.
    
    SetVisualCellAnchored handles 'noRotate' anchor. That anchor is not
    visible on screen. I have changed the misleading name to
    SetNonRotatedAnchor.
    
    Change-Id: I3dd2d3e37c138c8418369c760293a1f19dddb753
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/109959
    Reviewed-by: Regina Henschel <rb.hensc...@t-online.de>
    Tested-by: Regina Henschel <rb.hensc...@t-online.de>

diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index a8bfba521437..79091e89504c 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -53,6 +53,7 @@
 #include <vector>
 
 #include "markdata.hxx"
+#include "drwlayer.hxx"
 
 namespace com::sun::star::chart2 { class XChartDocument; }
 
@@ -963,7 +964,7 @@ public:
     bool                        IsStreamValidLocked() const { return 
mbStreamValidLocked; }
     bool                        IsPendingRowHeights( SCTAB nTab ) const;
     void                        SetPendingRowHeights( SCTAB nTab, bool bSet );
-    SC_DLLPUBLIC void           SetLayoutRTL( SCTAB nTab, bool bRTL );
+    SC_DLLPUBLIC void           SetLayoutRTL( SCTAB nTab, bool bRTL, 
ScObjectHandling eObjectHandling = ScObjectHandling::RecalcPosMode);
     SC_DLLPUBLIC bool           IsLayoutRTL( SCTAB nTab ) const;
     SC_DLLPUBLIC bool           IsNegativePage( SCTAB nTab ) const;
     SC_DLLPUBLIC void           SetScenario( SCTAB nTab, bool bFlag );
diff --git a/sc/inc/drwlayer.hxx b/sc/inc/drwlayer.hxx
index 030fd3855ec8..008e56f8b8c6 100644
--- a/sc/inc/drwlayer.hxx
+++ b/sc/inc/drwlayer.hxx
@@ -86,6 +86,14 @@ public:
     virtual void     Redo() override;
 };
 
+// for ScDrawLayer::SetPageSize
+enum class ScObjectHandling
+{
+    RecalcPosMode, // used for row height or col width changes
+    MoveRTLMode, // used for switch to RTL during import of right-to-left sheet
+    MirrorRTLMode // used for switch between RTL and LTR by 
.uno:SheetRightToLeft
+};
+
 class SC_DLLPUBLIC ScDrawLayer final : public FmFormModel
 {
 private:
@@ -150,10 +158,12 @@ public:
                                     SCTAB nSourceTab, const tools::Rectangle& 
rSourceRange,
                                     const ScAddress& rDestPos, const 
tools::Rectangle& rDestRange );
 
-    void            SetPageSize( sal_uInt16 nPageNo, const Size& rSize, bool 
bUpdateNoteCaptionPos );
+    void            SetPageSize(sal_uInt16 nPageNo, const Size& rSize, bool 
bUpdateNoteCaptionPos,
+                                const ScObjectHandling eObjectHandling = 
ScObjectHandling::RecalcPosMode);
 
                     //  mirror or move between positive and negative positions 
for RTL
     void            MirrorRTL( SdrObject* pObj );
+    void            MoveRTL(SdrObject* pObj);
     static void     MirrorRectRTL( tools::Rectangle& rRect );      // for 
bounding rectangles etc.
 
     /** Returns the rectangle for the passed cell address in 1/100 mm.
@@ -174,7 +184,7 @@ public:
     static bool IsResizeWithCell( const SdrObject& rObj );
     static void             SetPageAnchored( SdrObject& );
     static void             SetCellAnchored( SdrObject&, const ScDrawObjData 
&rAnchor );
-    static void             SetVisualCellAnchored( SdrObject&, const 
ScDrawObjData &rAnchor );
+    static void             SetNonRotatedAnchor( SdrObject&, const 
ScDrawObjData &rAnchor );
 
     // Updates rAnchor based on position of rObj
     static void GetCellAnchorFromPosition(
diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx
index a09781366821..309d49d4f140 100644
--- a/sc/inc/table.hxx
+++ b/sc/inc/table.hxx
@@ -34,6 +34,7 @@
 #include "calcmacros.hxx"
 #include <formula/errorcodes.hxx>
 #include "document.hxx"
+#include "drwlayer.hxx"
 
 #include <set>
 #include <memory>
@@ -965,7 +966,8 @@ public:
     bool        IsSortCollatorGlobal() const;
     void        InitSortCollator( const ScSortParam& rPar );
     void        DestroySortCollator();
-    void        SetDrawPageSize( bool bResetStreamValid = true, bool 
bUpdateNoteCaptionPos = true );
+    void        SetDrawPageSize( bool bResetStreamValid = true, bool 
bUpdateNoteCaptionPos = true,
+                                 const ScObjectHandling eObjectHandling = 
ScObjectHandling::RecalcPosMode);
 
     void SetRangeName(std::unique_ptr<ScRangeName> pNew);
     ScRangeName* GetRangeName() const;
diff --git a/sc/qa/unit/data/ods/tdf137081_RTL_page_anchored.ods 
b/sc/qa/unit/data/ods/tdf137081_RTL_page_anchored.ods
new file mode 100644
index 000000000000..f0d0583d5934
Binary files /dev/null and 
b/sc/qa/unit/data/ods/tdf137081_RTL_page_anchored.ods differ
diff --git a/sc/qa/unit/data/ods/tdf137082_LTR_arrow_image.ods 
b/sc/qa/unit/data/ods/tdf137082_LTR_arrow_image.ods
new file mode 100644
index 000000000000..ed315c8f6996
Binary files /dev/null and b/sc/qa/unit/data/ods/tdf137082_LTR_arrow_image.ods 
differ
diff --git a/sc/qa/unit/data/ods/tdf137082_RTL_cell_anchored.ods 
b/sc/qa/unit/data/ods/tdf137082_RTL_cell_anchored.ods
new file mode 100644
index 000000000000..7b39927b1317
Binary files /dev/null and 
b/sc/qa/unit/data/ods/tdf137082_RTL_cell_anchored.ods differ
diff --git a/sc/qa/unit/scshapetest.cxx b/sc/qa/unit/scshapetest.cxx
index 1c54c0e5ac5c..6d8fa9f1f09a 100644
--- a/sc/qa/unit/scshapetest.cxx
+++ b/sc/qa/unit/scshapetest.cxx
@@ -40,6 +40,9 @@ public:
     ScShapeTest();
     void saveAndReload(css::uno::Reference<css::lang::XComponent>& xComponent,
                        const OUString& rFilter);
+    void testTdf137082_LTR_to_RTL();
+    void testTdf137082_RTL_cell_anchored();
+    void testTdf137081_RTL_page_anchored();
     void testTdf139583_Rotate180deg();
     void testTdf137033_FlipHori_Resize();
     void testTdf137033_RotShear_ResizeHide();
@@ -60,6 +63,9 @@ public:
     void testCustomShapeCellAnchoredRotatedShape();
 
     CPPUNIT_TEST_SUITE(ScShapeTest);
+    CPPUNIT_TEST(testTdf137082_LTR_to_RTL);
+    CPPUNIT_TEST(testTdf137082_RTL_cell_anchored);
+    CPPUNIT_TEST(testTdf137081_RTL_page_anchored);
     CPPUNIT_TEST(testTdf139583_Rotate180deg);
     CPPUNIT_TEST(testTdf137033_FlipHori_Resize);
     CPPUNIT_TEST(testTdf137033_RotShear_ResizeHide);
@@ -186,6 +192,155 @@ static SdrObject* lcl_getSdrObjectWithAssert(ScDocument& 
rDoc, sal_uInt16 nObjNu
     return pObj;
 }
 
+void ScShapeTest::testTdf137082_LTR_to_RTL()
+{
+    // Before the fix for tdf137081 and tdf137082, when flipping sheet from 
LTR to RTL, page anchored
+    // shapes were mirrored, but cell anchored shapes not. This was changed 
so, that shapes are always
+    // mirrored. Graphics are still not mirrored but shifted. This test makes 
sure a shape is mirrored
+    // and an image is not mirrored.
+
+    OUString aFileURL;
+    createFileURL(u"tdf137082_LTR_arrow_image.ods", aFileURL);
+    uno::Reference<css::lang::XComponent> xComponent = 
loadFromDesktop(aFileURL);
+    CPPUNIT_ASSERT(xComponent.is());
+
+    // Get document
+    ScDocShell* pDocSh = lcl_getScDocShellWithAssert(xComponent);
+    ScDocument& rDoc = pDocSh->GetDocument();
+
+    // Get objects and their transformation angles
+    SdrObject* pObjCS = lcl_getSdrObjectWithAssert(rDoc, 0);
+    const Degree100 nRotateLTR = pObjCS->GetRotateAngle();
+    SdrObject* pObjImage = lcl_getSdrObjectWithAssert(rDoc, 1);
+    const Degree100 nShearLTR = pObjImage->GetShearAngle();
+
+    // Switch to RTL
+    ScTabViewShell* pViewShell = lcl_getScTabViewShellWithAssert(pDocSh);
+    pViewShell->GetViewData().GetDispatcher().Execute(FID_TAB_RTL);
+
+    // Check custom shape is mirrored, image not.
+    const Degree100 nShearRTLActual = pObjImage->GetShearAngle();
+    CPPUNIT_ASSERT_EQUAL_MESSAGE("image should not be mirrored", 
nShearLTR.get(),
+                                 nShearRTLActual.get());
+    const Degree100 nRotateRTLExpected = 36000_deg100 - nRotateLTR;
+    const Degree100 nRotateRTLActual = pObjCS->GetRotateAngle();
+    CPPUNIT_ASSERT_EQUAL_MESSAGE("custom shape should be mirrored", 
nRotateRTLExpected.get(),
+                                 nRotateRTLActual.get());
+
+    pDocSh->DoClose();
+}
+
+void ScShapeTest::testTdf137082_RTL_cell_anchored()
+{
+    // Error was, that cell anchored custom shapes wrote wrong offsets to file 
and thus were wrong on
+    // reloading. The file contains one custome shape with "resize" and 
another one without.
+    OUString aFileURL;
+    createFileURL(u"tdf137082_RTL_cell_anchored.ods", aFileURL);
+    uno::Reference<css::lang::XComponent> xComponent = 
loadFromDesktop(aFileURL);
+    CPPUNIT_ASSERT(xComponent.is());
+
+    // Get document
+    ScDocShell* pDocSh = lcl_getScDocShellWithAssert(xComponent);
+    ScDocument& rDoc = pDocSh->GetDocument();
+
+    // Expected values.
+    const Point aTopLeftA(-20500, 3500); // shape A without "resize"
+    const Point aTopLeftB(-9500, 3500); // shape B with "resize"
+    const Size aSize(2278, 5545); // both
+    const tools::Rectangle aSnapRectA(aTopLeftA, aSize);
+    const tools::Rectangle aSnapRectB(aTopLeftB, aSize);
+
+    // Test reading was correct
+    SdrObject* pObj = lcl_getSdrObjectWithAssert(rDoc, 0);
+    lcl_AssertRectEqualWithTolerance("load shape A: ", aSnapRectA, 
pObj->GetSnapRect(), 1);
+    pObj = lcl_getSdrObjectWithAssert(rDoc, 1);
+    lcl_AssertRectEqualWithTolerance("load shape B: ", aSnapRectB, 
pObj->GetSnapRect(), 1);
+
+    // Save and reload.
+    saveAndReload(xComponent, "calc8");
+    CPPUNIT_ASSERT(xComponent);
+
+    // Get document
+    pDocSh = lcl_getScDocShellWithAssert(xComponent);
+    ScDocument& rDoc2 = pDocSh->GetDocument();
+
+    // And test again
+    pObj = lcl_getSdrObjectWithAssert(rDoc2, 0);
+    lcl_AssertRectEqualWithTolerance("reload shape A: ", aSnapRectA, 
pObj->GetSnapRect(), 1);
+    pObj = lcl_getSdrObjectWithAssert(rDoc2, 1);
+    lcl_AssertRectEqualWithTolerance("reload shape B: ", aSnapRectB, 
pObj->GetSnapRect(), 1);
+
+    pDocSh->DoClose();
+}
+
+void ScShapeTest::testTdf137081_RTL_page_anchored()
+{
+    // Error was, that page anchored lines and custom shapes were mirrored on 
opening. The document
+    // contains measure line, polyline and transformed custom shape.
+    OUString aFileURL;
+    createFileURL(u"tdf137081_RTL_page_anchored.ods", aFileURL);
+    uno::Reference<css::lang::XComponent> xComponent = 
loadFromDesktop(aFileURL);
+    CPPUNIT_ASSERT(xComponent.is());
+
+    // Get document
+    ScDocShell* pDocSh = lcl_getScDocShellWithAssert(xComponent);
+    ScDocument& rDoc = pDocSh->GetDocument();
+
+    // Expected values.
+    // Measure line
+    const Point aStart(-3998, 2490);
+    const Point aEnd(-8488, 5490);
+    // Polyline
+    const Point aFirst(-10010, 2500);
+    const Point aSecond(-14032, 5543);
+    const Point aThird(-14500, 3500);
+    // Custom shape
+    const Point aTopLeft(-20500, 4583);
+
+    // Test reading was correct
+    SdrObject* pObj = lcl_getSdrObjectWithAssert(rDoc, 0);
+    // Measure line
+    lcl_AssertPointEqualWithTolerance("measure line start", aStart, 
pObj->GetPoint(0), 1);
+    lcl_AssertPointEqualWithTolerance("measure line end", aEnd, 
pObj->GetPoint(1), 1);
+    // Polyline
+    pObj = lcl_getSdrObjectWithAssert(rDoc, 1);
+    lcl_AssertPointEqualWithTolerance("polyline 1: ", aFirst, 
pObj->GetPoint(0), 1);
+    lcl_AssertPointEqualWithTolerance("polyline 2: ", aSecond, 
pObj->GetPoint(1), 1);
+    lcl_AssertPointEqualWithTolerance("polyline 3: ", aThird, 
pObj->GetPoint(2), 1);
+    //Custom shape
+    SdrObjCustomShape* pObjCS
+        = static_cast<SdrObjCustomShape*>(lcl_getSdrObjectWithAssert(rDoc, 2));
+    CPPUNIT_ASSERT(!pObjCS->IsMirroredX());
+    lcl_AssertPointEqualWithTolerance("custom shape top left: ", aTopLeft,
+                                      pObjCS->GetLogicRect().TopLeft(), 1);
+
+    // Save and reload.
+    saveAndReload(xComponent, "calc8");
+    CPPUNIT_ASSERT(xComponent);
+
+    // Get document
+    pDocSh = lcl_getScDocShellWithAssert(xComponent);
+    ScDocument& rDoc2 = pDocSh->GetDocument();
+
+    // And test again
+    pObj = lcl_getSdrObjectWithAssert(rDoc2, 0);
+    // Measure line
+    lcl_AssertPointEqualWithTolerance("measure line start", aStart, 
pObj->GetPoint(0), 1);
+    lcl_AssertPointEqualWithTolerance("measure line end", aEnd, 
pObj->GetPoint(1), 1);
+    // Polyline
+    pObj = lcl_getSdrObjectWithAssert(rDoc2, 1);
+    lcl_AssertPointEqualWithTolerance("polyline 1: ", aFirst, 
pObj->GetPoint(0), 1);
+    lcl_AssertPointEqualWithTolerance("polyline 2: ", aSecond, 
pObj->GetPoint(1), 1);
+    lcl_AssertPointEqualWithTolerance("polyline 3: ", aThird, 
pObj->GetPoint(2), 1);
+    //Custom shape
+    pObjCS = static_cast<SdrObjCustomShape*>(lcl_getSdrObjectWithAssert(rDoc2, 
2));
+    CPPUNIT_ASSERT(!pObjCS->IsMirroredX());
+    lcl_AssertPointEqualWithTolerance("custom shape top left: ", aTopLeft,
+                                      pObjCS->GetLogicRect().TopLeft(), 1);
+
+    pDocSh->DoClose();
+}
+
 void ScShapeTest::testTdf139583_Rotate180deg()
 {
     // Load an empty document.
diff --git a/sc/source/core/data/documen9.cxx b/sc/source/core/data/documen9.cxx
index 46d1b1c3750d..f44159d6c436 100644
--- a/sc/source/core/data/documen9.cxx
+++ b/sc/source/core/data/documen9.cxx
@@ -600,8 +600,10 @@ void ScDocument::SetImportingXML( bool bVal )
         for ( SCTAB nTab=0; nTab< static_cast<SCTAB>(maTabs.size()) && 
maTabs[nTab]; nTab++ )
             if ( maTabs[nTab]->IsLoadingRTL() )
             {
+                // SetLayoutRTL => SetDrawPageSize => 
ScDrawLayer::SetPageSize, includes RTL-mirroring;
+                // bImportingXML must be cleared first
                 maTabs[nTab]->SetLoadingRTL( false );
-                SetLayoutRTL( nTab, true );             // includes mirroring; 
bImportingXML must be cleared first
+                SetLayoutRTL( nTab, true, ScObjectHandling::MoveRTLMode );
             }
     }
 
diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx
index be588062c5df..48282126b0fc 100644
--- a/sc/source/core/data/document.cxx
+++ b/sc/source/core/data/document.cxx
@@ -945,7 +945,7 @@ void ScDocument::SetPendingRowHeights( SCTAB nTab, bool 
bSet )
         maTabs[nTab]->SetPendingRowHeights( bSet );
 }
 
-void ScDocument::SetLayoutRTL( SCTAB nTab, bool bRTL )
+void ScDocument::SetLayoutRTL( SCTAB nTab, bool bRTL, ScObjectHandling 
eObjectHandling)
 {
     if ( !(ValidTab(nTab) && nTab < static_cast<SCTAB> (maTabs.size()) && 
maTabs[nTab]) )
         return;
@@ -961,10 +961,9 @@ void ScDocument::SetLayoutRTL( SCTAB nTab, bool bRTL )
     }
 
     maTabs[nTab]->SetLayoutRTL( bRTL );     // only sets the flag
-    maTabs[nTab]->SetDrawPageSize();
-
-    //  mirror existing objects:
+    maTabs[nTab]->SetDrawPageSize(true, true, eObjectHandling);
 
+    //  objects are already repositioned via SetDrawPageSize, only writing 
mode is missing
     if (!mpDrawLayer)
         return;
 
@@ -977,14 +976,7 @@ void ScDocument::SetLayoutRTL( SCTAB nTab, bool bRTL )
     SdrObject* pObject = aIter.Next();
     while (pObject)
     {
-        //  objects with ScDrawObjData are re-positioned in SetPageSize,
-        //  don't mirror again
-        ScDrawObjData* pData = ScDrawLayer::GetObjData( pObject );
-        if ( !pData )
-            mpDrawLayer->MirrorRTL( pObject );
-
         pObject->SetContextWritingMode( bRTL ? WritingMode2::RL_TB : 
WritingMode2::LR_TB );
-
         pObject = aIter.Next();
     }
 }
diff --git a/sc/source/core/data/drwlayer.cxx b/sc/source/core/data/drwlayer.cxx
index 067b2bc38b0f..3d2eb834a6c0 100644
--- a/sc/source/core/data/drwlayer.cxx
+++ b/sc/source/core/data/drwlayer.cxx
@@ -570,7 +570,8 @@ void ScDrawLayer::MoveCells( SCTAB nTab, SCCOL nCol1,SCROW 
nRow1, SCCOL nCol2,SC
     }
 }
 
-void ScDrawLayer::SetPageSize( sal_uInt16 nPageNo, const Size& rSize, bool 
bUpdateNoteCaptionPos )
+void ScDrawLayer::SetPageSize(sal_uInt16 nPageNo, const Size& rSize, bool 
bUpdateNoteCaptionPos,
+                              const ScObjectHandling eObjectHandling)
 {
     SdrPage* pPage = GetPage(nPageNo);
     if (!pPage)
@@ -582,31 +583,65 @@ void ScDrawLayer::SetPageSize( sal_uInt16 nPageNo, const 
Size& rSize, bool bUpda
         Broadcast( ScTabSizeChangedHint( static_cast<SCTAB>(nPageNo) ) );   // 
SetWorkArea() on the views
     }
 
-    // Implement Detective lines (adjust to new heights / widths)
-    //  even if size is still the same
-    //  (individual rows/columns can have been changed))
-
     // Do not call RecalcPos while loading, because row height is not 
finished, when SetPageSize
     // is called first time. Instead the objects are initialized from 
ScXMLImport::endDocument() and
     // RecalcPos is called from there.
     if (!pDoc || pDoc->IsImportingXML())
         return;
 
+    // Implement Detective lines (adjust to new heights / widths)
+    //  even if size is still the same
+    //  (individual rows/columns can have been changed))
+
     bool bNegativePage = pDoc && pDoc->IsNegativePage( 
static_cast<SCTAB>(nPageNo) );
 
     // Disable mass broadcasts from drawing objects' position changes.
     bool bWasLocked = isLocked();
     setLock(true);
+
     const size_t nCount = pPage->GetObjCount();
     for ( size_t i = 0; i < nCount; ++i )
     {
         SdrObject* pObj = pPage->GetObj( i );
         ScDrawObjData* pData = GetObjDataTab( pObj, 
static_cast<SCTAB>(nPageNo) );
-        if( pData )
-            RecalcPos( pObj, *pData, bNegativePage, bUpdateNoteCaptionPos );
+        if( pData ) // cell anchored
+        {
+            if (pData->meType == ScDrawObjData::DrawingObject
+                || pData->meType == ScDrawObjData::ValidationCircle)
+            {
+                switch (eObjectHandling)
+                {
+                    case ScObjectHandling::RecalcPosMode:
+                        RecalcPos(pObj, *pData, bNegativePage, 
bUpdateNoteCaptionPos);
+                        break;
+                    case ScObjectHandling::MoveRTLMode:
+                        MoveRTL(pObj);
+                        break;
+                    case ScObjectHandling::MirrorRTLMode:
+                        MirrorRTL(pObj);
+                        break;
+                }
+            }
+            else // DetectiveArrow and CellNote
+                RecalcPos(pObj, *pData, bNegativePage, bUpdateNoteCaptionPos);
+        }
+        else // page anchored
+        {
+            switch (eObjectHandling)
+            {
+                case ScObjectHandling::MoveRTLMode:
+                    MoveRTL(pObj);
+                    break;
+                case ScObjectHandling::MirrorRTLMode:
+                    MirrorRTL(pObj);
+                    break;
+                case ScObjectHandling::RecalcPosMode: // does not occur for 
page anchored shapes
+                    break;
+            }
+        }
     }
-    setLock(bWasLocked);
 
+    setLock(bWasLocked);
 }
 
 namespace
@@ -1177,9 +1212,9 @@ void ScDrawLayer::RecalcPos( SdrObject* pObj, 
ScDrawObjData& rData, bool bNegati
                 else
                     pObj->SetSnapRect(rData.getShapeRect());
 
-                // update 'unrotated anchor' it's the anchor we persist, it 
must be kept in sync
-                // with the normal Anchor.
-                ResizeLastRectFromAnchor(pObj, rNoRotatedAnchor, true, 
bNegativePage, bCanResize);
+                // The shape rectangle in the 'unrotated' anchor needs to be 
updated to the changed
+                // object geometry. It is used in adjustAnchoredPosition() in 
ScDrawView::Notify().
+                rNoRotatedAnchor.setShapeRect(pDoc, pObj->GetLogicRect(), 
pObj->IsVisible());
             }
         }
         else
@@ -1190,6 +1225,7 @@ void ScDrawLayer::RecalcPos( SdrObject* pObj, 
ScDrawObjData& rData, bool bNegati
                 if (bRecording)
                     AddCalcUndo( std::make_unique<SdrUndoGeoObj>( *pObj ) );
                 pObj->SetRelativePos( aPos );
+                rNoRotatedAnchor.setShapeRect(pDoc, pObj->GetLogicRect(), 
pObj->IsVisible());
             }
         }
         /*
@@ -1954,6 +1990,10 @@ void ScDrawLayer::CopyFromClip( ScDrawLayer* pClipModel, 
SCTAB nSourceTab, const
 
 void ScDrawLayer::MirrorRTL( SdrObject* pObj )
 {
+    OSL_ENSURE( pDoc, "ScDrawLayer::MirrorRTL - missing document" );
+    if( !pDoc )
+        return;
+
     sal_uInt16 nIdent = pObj->GetObjIdentifier();
 
     //  don't mirror OLE or graphics, otherwise ask the object
@@ -1968,23 +2008,87 @@ void ScDrawLayer::MirrorRTL( SdrObject* pObj )
 
     if (bCanMirror)
     {
-        Point aRef1( 0, 0 );
-        Point aRef2( 0, 1 );
-        if (bRecording)
-            AddCalcUndo( std::make_unique<SdrUndoGeoObj>( *pObj ) );
-        pObj->Mirror( aRef1, aRef2 );
+        ScDrawObjData* pData = GetObjData(pObj);
+        if (pData) // cell anchored
+        {
+            // Remember values from positive side.
+            const tools::Rectangle aOldSnapRect = pObj->GetSnapRect();
+            const tools::Rectangle aOldLogicRect = pObj->GetLogicRect();
+            // Generate noRotate anchor if missing.
+            ScDrawObjData* pNoRotatedAnchor = GetNonRotatedObjData(pObj);
+            if (!pNoRotatedAnchor)
+            {
+                ScDrawObjData aNoRotateAnchor;
+                const tools::Rectangle aLogicRect(pObj->GetLogicRect());
+                GetCellAnchorFromPosition(aLogicRect, aNoRotateAnchor,
+                              *pDoc, pData->maStart.Tab());
+                aNoRotateAnchor.mbResizeWithCell = pData->mbResizeWithCell;
+                SetNonRotatedAnchor(*pObj, aNoRotateAnchor);
+            }
+            // Mirror object at vertical axis
+            Point aRef1( 0, 0 );
+            Point aRef2( 0, 1 );
+            if (bRecording)
+                AddCalcUndo( std::make_unique<SdrUndoGeoObj>( *pObj ) );
+            pObj->Mirror( aRef1, aRef2 );
+
+            // Adapt offsets in pNoRotatedAnchor so, that object will be moved 
to current position in
+            // save and reload.
+            const tools::Long nInverseShift = aOldSnapRect.Left() + 
aOldSnapRect.Right();
+            const Point aLogicLT = pObj->GetLogicRect().TopLeft();
+            const Point aMirroredLogicLT = aLogicLT + Point(nInverseShift, 0);
+            const Point aOffsetDiff = aMirroredLogicLT - 
aOldLogicRect.TopLeft();
+            // new Offsets
+            pNoRotatedAnchor->maStartOffset += aOffsetDiff;
+            pNoRotatedAnchor->maEndOffset += aOffsetDiff;
+        }
+        else // page anchored
+        {
+            Point aRef1( 0, 0 );
+            Point aRef2( 0, 1 );
+            if (bRecording)
+                AddCalcUndo( std::make_unique<SdrUndoGeoObj>( *pObj ) );
+            pObj->Mirror( aRef1, aRef2 );
+        }
     }
     else
     {
         //  Move instead of mirroring:
         //  New start position is negative of old end position
         //  -> move by sum of start and end position
-        tools::Rectangle aObjRect = pObj->GetLogicRect();
+        tools::Rectangle aObjRect = pObj->GetSnapRect();
         Size aMoveSize( -(aObjRect.Left() + aObjRect.Right()), 0 );
         if (bRecording)
             AddCalcUndo( std::make_unique<SdrUndoMoveObj>( *pObj, aMoveSize ) 
);
         pObj->Move( aMoveSize );
     }
+
+    // for cell anchored objects adapt rectangles in anchors
+    ScDrawObjData* pData = GetObjData(pObj);
+    if (pData)
+    {
+        pData->setShapeRect(GetDocument(), pObj->GetSnapRect(), 
pObj->IsVisible());
+        ScDrawObjData* pNoRotatedAnchor = GetNonRotatedObjData(pObj, true 
/*bCreate*/);
+        pNoRotatedAnchor->setShapeRect(GetDocument(), pObj->GetLogicRect(), 
pObj->IsVisible());
+    }
+}
+
+void ScDrawLayer::MoveRTL(SdrObject* pObj)
+{
+    tools::Rectangle aObjRect = pObj->GetSnapRect();
+    Size aMoveSize( -(aObjRect.Left() + aObjRect.Right()), 0 );
+    if (bRecording)
+        AddCalcUndo( std::make_unique<SdrUndoMoveObj>( *pObj, aMoveSize ) );
+    pObj->Move( aMoveSize );
+
+    // for cell anchored objects adapt rectangles in anchors
+    ScDrawObjData* pData = GetObjData(pObj);
+    if (pData)
+    {
+        pData->setShapeRect(GetDocument(), pObj->GetSnapRect(), 
pObj->IsVisible());
+        ScDrawObjData* pNoRotatedAnchor = GetNonRotatedObjData(pObj, true 
/*bCreate*/);
+        pNoRotatedAnchor->setShapeRect(GetDocument(), pObj->GetLogicRect(), 
pObj->IsVisible());
+    }
 }
 
 void ScDrawLayer::MirrorRectRTL( tools::Rectangle& rRect )
@@ -2167,7 +2271,7 @@ namespace
     }
 }
 
-void ScDrawLayer::SetVisualCellAnchored( SdrObject &rObj, const ScDrawObjData 
&rAnchor )
+void ScDrawLayer::SetNonRotatedAnchor(SdrObject& rObj, const ScDrawObjData& 
rAnchor)
 {
     ScDrawObjData* pAnchor = GetNonRotatedObjData( &rObj, true );
     pAnchor->maStart = rAnchor.maStart;
@@ -2235,19 +2339,29 @@ void ScDrawLayer::SetCellAnchoredFromPosition( 
SdrObject &rObj, const ScDocument
     else
         aObjRect2 = rObj.GetLogicRect();
 
-    ScDrawObjData aVisAnchor;
+    // Values in XML are so as if it is a LTR sheet. The object is shifted to 
negative page on loading
+    // so that the snap rectangle appears mirrored. For transformed objects 
the shifted logic rectangle
+    // is not the mirrored LTR rectangle. We calculate the mirrored LTR 
rectangle here.
+    if (rDoc.IsNegativePage(nTab))
+    {
+        const tools::Rectangle aSnapRect(rObj.GetSnapRect());
+        aObjRect2.Move(Size(-aSnapRect.Left() - aSnapRect.Right(), 0));
+        MirrorRectRTL(aObjRect2);
+    }
+
+    ScDrawObjData aNoRotatedAnchor;
     GetCellAnchorFromPosition(
         aObjRect2,
-        aVisAnchor,
+        aNoRotatedAnchor,
         rDoc,
-        nTab, false);
+        nTab);
 
-    aVisAnchor.mbResizeWithCell = bResizeWithCell;
-    SetVisualCellAnchored( rObj, aVisAnchor );
+    aNoRotatedAnchor.mbResizeWithCell = bResizeWithCell;
+    SetNonRotatedAnchor( rObj, aNoRotatedAnchor);
     // And update maShapeRect. It is used in adjustAnchoredPosition() in 
ScDrawView::Notify().
     if (ScDrawObjData* pAnchor = GetNonRotatedObjData(&rObj))
     {
-        pAnchor->setShapeRect(&rDoc, rObj.GetSnapRect());
+        pAnchor->setShapeRect(&rDoc, rObj.GetLogicRect());
     }
 }
 
diff --git a/sc/source/core/data/table2.cxx b/sc/source/core/data/table2.cxx
index 0ba9421d8265..d25e7ce7c7f4 100644
--- a/sc/source/core/data/table2.cxx
+++ b/sc/source/core/data/table2.cxx
@@ -3910,7 +3910,8 @@ void ScTable::GetUpperCellString(SCCOL nCol, SCROW nRow, 
OUString& rStr)
 
 // Calculate the size of the sheet and set the size on DrawPage
 
-void ScTable::SetDrawPageSize(bool bResetStreamValid, bool 
bUpdateNoteCaptionPos)
+void ScTable::SetDrawPageSize(bool bResetStreamValid, bool 
bUpdateNoteCaptionPos,
+                              ScObjectHandling eObjectHandling)
 {
     ScDrawLayer* pDrawLayer = rDocument.GetDrawLayer();
     if( pDrawLayer )
@@ -3926,7 +3927,8 @@ void ScTable::SetDrawPageSize(bool bResetStreamValid, 
bool bUpdateNoteCaptionPos
         if ( IsLayoutRTL() )        // IsNegativePage
             x = -x;
 
-        pDrawLayer->SetPageSize( static_cast<sal_uInt16>(nTab), Size( x, y ), 
bUpdateNoteCaptionPos );
+        pDrawLayer->SetPageSize(static_cast<sal_uInt16>(nTab), Size(x, y), 
bUpdateNoteCaptionPos,
+                                eObjectHandling);
     }
 
     // #i102616# actions that modify the draw page size count as sheet 
modification
diff --git a/sc/source/filter/xml/xmlexprt.cxx 
b/sc/source/filter/xml/xmlexprt.cxx
index d69fdd784ef7..a7a61365a08c 100644
--- a/sc/source/filter/xml/xmlexprt.cxx
+++ b/sc/source/filter/xml/xmlexprt.cxx
@@ -3476,7 +3476,10 @@ void ScXMLExport::WriteShapes(const ScMyCell& rMyCell)
     if( !(rMyCell.bHasShape && !rMyCell.aShapeList.empty() && pDoc) )
         return;
 
-    // Reference point
+    // Reference point to turn absolute coordinates in reference point + 
offset. That happens in most
+    // cases in XMLShapeExport::ImpExportNewTrans_DecomposeAndRefPoint, which 
gets the absolute
+    // coordinates as translation from matrix in property "Transformation". 
For cell anchored shapes
+    // the reference point is left-top (in LTR mode) of that cell, which 
contains the shape.
     tools::Rectangle aCellRectFull = pDoc->GetMMRect(
         rMyCell.maCellAddress.Col(), rMyCell.maCellAddress.Row(), 
rMyCell.maCellAddress.Col(),
         rMyCell.maCellAddress.Row(), rMyCell.maCellAddress.Tab(), false 
/*bHiddenAsZero*/);
@@ -3488,7 +3491,6 @@ void ScXMLExport::WriteShapes(const ScMyCell& rMyCell)
         aPoint.X = aCellRectFull.Left();
     aPoint.Y = aCellRectFull.Top();
 
-    // ToDo: Adapt the solutions for RTL sheets.
     for (const auto& rShape : rMyCell.aShapeList)
     {
         if (rShape.xShape.is())
@@ -3548,9 +3550,17 @@ void ScXMLExport::WriteShapes(const ScMyCell& rMyCell)
                 const tools::Rectangle aEndCellRect = pDoc->GetMMRect(
                     aSnapEndAddress.Col(), aSnapEndAddress.Row(), 
aSnapEndAddress.Col(),
                     aSnapEndAddress.Row(), aSnapEndAddress.Tab(), false 
/*bHiddenAsZero*/);
-                aRectFull.SetLeft(aStartCellRect.Left() + 
aSnapStartOffset.X());
+                if (bNegativePage)
+                {
+                    aRectFull.SetLeft(aEndCellRect.Right() - 
aSnapEndOffset.X());
+                    aRectFull.SetRight(aStartCellRect.Right() - 
aSnapStartOffset.X());
+                }
+                else
+                {
+                    aRectFull.SetLeft(aStartCellRect.Left() + 
aSnapStartOffset.X());
+                    aRectFull.SetRight(aEndCellRect.Left() + 
aSnapEndOffset.X());
+                }
                 aRectFull.SetTop(aStartCellRect.Top() + aSnapStartOffset.Y());
-                aRectFull.SetRight(aEndCellRect.Left() + aSnapEndOffset.X());
                 aRectFull.SetBottom(aEndCellRect.Top() + aSnapEndOffset.Y());
                 aRectReduced = pObjData->getShapeRect();
                 if(abs(aRectFull.getWidth() - aRectReduced.getWidth()) > 1
@@ -3583,25 +3593,31 @@ void ScXMLExport::WriteShapes(const ScMyCell& rMyCell)
                 AddAttribute(XML_NAMESPACE_TABLE, XML_END_Y, 
sBuffer.makeStringAndClear());
             }
 
-            // The general method 
XMLShapeExport::ImpExportNewTrans_DecomposeAndRefPoint calculates
-            // offset = translate - refPoint. But in case of a horizontal 
mirrored, 'resize with cell'
-            // anchored custom shape, translate has wrong values. So we use 
refPoint = translate
-            // - startOffset which removes translate and sets startOffset 
directly.
-            // FixMe: Why is translate wrong?
-            if (rShape.bResizeWithCell && pObj && pObj->GetObjIdentifier() == 
OBJ_CUSTOMSHAPE
-                && static_cast<SdrObjCustomShape*>(pObj)->IsMirroredX())
+            // Correct above calculated reference point for some cases:
+            // a) For a RTL-sheet translate from matrix is not suitable, 
because the shape
+            // from xml (which is always LTR) is not mirrored to negative page 
but shifted.
+            // b) In case of horizontal mirrored, 'resize with cell' anchored 
custom shape, translate
+            // has wrong values. FixMe: Why is translate wrong?
+            // c) Measure lines do not use transformation matrix but use start 
and end point directly.
+            ScDrawObjData* pNRObjData = nullptr;
+            if (pObj && bNegativePage
+                && rShape.xShape->getShapeType() == 
"com.sun.star.drawing.MeasureShape")
             {
-                ScDrawObjData* pNRObjData = 
ScDrawLayer::GetNonRotatedObjData(pObj);
-                if (pNRObjData)
-                {
-                    aPoint.X = rShape.xShape->getPosition().X - 
pNRObjData->maStartOffset.X();
-                    aPoint.Y = rShape.xShape->getPosition().Y - 
pNRObjData->maStartOffset.Y();
-                }
+                // invers of shift when import
+                tools::Rectangle aSnapRect = pObj->GetSnapRect();
+                aPoint.X = aSnapRect.Left() + aSnapRect.Right() - aPoint.X;
+            }
+            else if (pObj && (pNRObjData = 
ScDrawLayer::GetNonRotatedObjData(pObj))
+                     && ((rShape.bResizeWithCell && pObj->GetObjIdentifier() 
== OBJ_CUSTOMSHAPE
+                          && 
static_cast<SdrObjCustomShape*>(pObj)->IsMirroredX())
+                         || bNegativePage))
+            {
+                //In these cases we set reference Point = matrix translate - 
startOffset.
+                awt::Point aMatrixTranslate = rShape.xShape->getPosition();
+                aPoint.X = aMatrixTranslate.X - pNRObjData->maStartOffset.X();
+                aPoint.Y = aMatrixTranslate.Y - pNRObjData->maStartOffset.Y();
             }
 
-            if (bNegativePage)
-                aPoint.X = 2 * rShape.xShape->getPosition().X + 
rShape.xShape->getSize().Width
-                           - aPoint.X;
             ExportShape(rShape.xShape, &aPoint);
 
             // Restore object geometry
@@ -3625,11 +3641,23 @@ void ScXMLExport::WriteTableShapes()
         {
             if (pDoc->IsNegativePage(static_cast<SCTAB>(nCurrentTable)))
             {
-                awt::Point aPoint(rxShape->getPosition());
-                awt::Size aSize(rxShape->getSize());
-                aPoint.X += aPoint.X + aSize.Width;
-                aPoint.Y = 0;
-                ExportShape(rxShape, &aPoint);
+                // RTL-mirroring refers to snap rectangle, not to logic 
rectangle, therefore cannot use
+                // getPosition() and getSize(), but need property "FrameRect" 
from rxShape or
+                // GetSnapRect() from associated SdrObject.
+                uno::Reference<beans::XPropertySet> xShapeProp(rxShape, 
uno::UNO_QUERY);
+                awt::Rectangle aFrameRect;
+                if (xShapeProp.is() && 
(xShapeProp->getPropertyValue("FrameRect") >>= aFrameRect))
+                {
+                    // file format uses shape in LTR mode. newLeft = - 
oldRight = - (oldLeft + width).
+                    // newTranslate = oldTranslate - refPoint, oldTranslate 
from transformation matrix,
+                    // calculated in XMLShapeExport::exportShape common for 
all modules.
+                    // oldTranslate.X = oldLeft ==> refPoint.X = 2 * oldLeft + 
width
+                    awt::Point aRefPoint;
+                    aRefPoint.X = 2 * aFrameRect.X + aFrameRect.Width - 1;
+                    aRefPoint.Y = 0;
+                    ExportShape(rxShape, &aRefPoint);
+                }
+                // else should not happen
             }
             else
                 ExportShape(rxShape, nullptr);
diff --git a/sc/source/ui/docshell/docfunc.cxx 
b/sc/source/ui/docshell/docfunc.cxx
index 42ac96e8eea3..2949e92390f1 100644
--- a/sc/source/ui/docshell/docfunc.cxx
+++ b/sc/source/ui/docshell/docfunc.cxx
@@ -3465,7 +3465,7 @@ bool ScDocFunc::SetLayoutRTL( SCTAB nTab, bool bRTL )
 
     ScDocShellModificator aModificator( rDocShell );
 
-    rDoc.SetLayoutRTL( nTab, bRTL );
+    rDoc.SetLayoutRTL( nTab, bRTL, ScObjectHandling::MirrorRTLMode);
 
     if (bUndo)
     {
diff --git a/sc/source/ui/undo/undotab.cxx b/sc/source/ui/undo/undotab.cxx
index 4118b1bcbd5d..85c2708367e4 100644
--- a/sc/source/ui/undo/undotab.cxx
+++ b/sc/source/ui/undo/undotab.cxx
@@ -1509,7 +1509,7 @@ void ScUndoLayoutRTL::DoChange( bool bNew )
     pDocShell->SetInUndo( true );
 
     ScDocument& rDoc = pDocShell->GetDocument();
-    rDoc.SetLayoutRTL( nTab, bNew );
+    rDoc.SetLayoutRTL(nTab, bNew, ScObjectHandling::MirrorRTLMode);
 
     ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
     if (pViewShell)
_______________________________________________
Libreoffice-commits mailing list
libreoffice-comm...@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits

Reply via email to