sw/qa/extras/rtfexport/data/tdf121493.rtf          |   21 +++++
 sw/qa/extras/rtfexport/rtfexport8.cxx              |   46 ++++++++++++
 sw/source/writerfilter/rtftok/rtfdispatchvalue.cxx |   79 +++++++++++++--------
 3 files changed, 118 insertions(+), 28 deletions(-)

New commits:
commit a06689b1711e1f200afd4a4492341f337ba99082
Author:     Mike Kaganski <[email protected]>
AuthorDate: Sun Jun 22 02:49:05 2025 +0500
Commit:     Mike Kaganski <[email protected]>
CommitDate: Sun Jun 22 09:11:31 2025 +0200

    tdf#121493: handle  rleftN after     
    I took an easy path, and just fixed the possible pre-existing value
    when        rleftN is handled. But the proper fix would be to avoid the
    cell widths calculations altogether, until  ow is handled. At that
    point, all information is already gathered.
    
    Search for the first instance of LN_CT_TblGridBase_gridCol, that is
    not -1 (the special value inserted in 
RTFDocumentImpl::resetTableRowProperties,
    and used in DomainMapperTableManager::sprm); and if found, correct
    it by the calculated TRLeft value.
    When there was no previous     
    Change-Id: Ie6cf64d594e166abb1ed3e939207101d96f75c63
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/186790
    Tested-by: Jenkins
    Reviewed-by: Mike Kaganski <[email protected]>

diff --git a/sw/qa/extras/rtfexport/data/tdf121493.rtf 
b/sw/qa/extras/rtfexport/data/tdf121493.rtf
new file mode 100644
index 000000000000..79f115430deb
--- /dev/null
+++ b/sw/qa/extras/rtfexport/data/tdf121493.rtf
@@ -0,0 +1,21 @@
+{ tf1
+{      rowd+aaa
++bbb
++ ow}
+\par
+{      rowd    rleft1000+aaa
++bbb
++ ow}
+\par
+{      rowd    rleft0+aaa
++bbb
++ ow}}
\ No newline at end of file
diff --git a/sw/qa/extras/rtfexport/rtfexport8.cxx 
b/sw/qa/extras/rtfexport/rtfexport8.cxx
index f255fbde2a20..5675cf61910b 100644
--- a/sw/qa/extras/rtfexport/rtfexport8.cxx
+++ b/sw/qa/extras/rtfexport/rtfexport8.cxx
@@ -12,6 +12,7 @@
 #include <com/sun/star/awt/FontWeight.hpp>
 #include <com/sun/star/awt/Gradient2.hpp>
 #include <com/sun/star/drawing/FillStyle.hpp>
+#include <com/sun/star/table/XTableColumns.hpp>
 #include <com/sun/star/text/GraphicCrop.hpp>
 #include <com/sun/star/text/XFootnote.hpp>
 #include <com/sun/star/text/XFootnotesSupplier.hpp>
@@ -749,6 +750,51 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf155835)
     }
 }
 
+CPPUNIT_TEST_FIXTURE(Test, testTdf121493)
+{
+    // Given a document with three tables, having different order of a row's 
cellxN and trleftN:
+    createSwDoc("tdf121493.rtf");
+    {
+        xmlDocUniquePtr pLayout = parseLayoutDump();
+        // 1st table, having +        assertXPath(pLayout, "//tab[1]['pass 
1']/infos/prtBounds", "left", u"1000");
+        assertXPath(pLayout, "//tab[1]['pass 1']/row/cell[1]/infos/bounds", 
"width", u"7000");
+        assertXPath(pLayout, "//tab[1]['pass 1']/row/cell[2]/infos/bounds", 
"width", u"1000");
+        // 2nd table, having   rleft1000+        assertXPath(pLayout, 
"//tab[2]['pass 1']/infos/prtBounds", "left", u"1000");
+        assertXPath(pLayout, "//tab[2]['pass 1']/row/cell[1]/infos/bounds", 
"width", u"7000");
+        assertXPath(pLayout, "//tab[2]['pass 1']/row/cell[2]/infos/bounds", 
"width", u"1000");
+        // 3rd table, having   rleft0+        assertXPath(pLayout, 
"//tab[3]['pass 1']/infos/prtBounds", "left", u"0");
+        assertXPath(pLayout, "//tab[3]['pass 1']/row/cell[1]/infos/bounds", 
"width", u"8000");
+        assertXPath(pLayout, "//tab[3]['pass 1']/row/cell[2]/infos/bounds", 
"width", u"1000");
+    }
+    // Check export, too
+    saveAndReload(mpFilter);
+    {
+        xmlDocUniquePtr pLayout = parseLayoutDump();
+        // Rounding (or maybe off-by-one?) errors sadly hit the test
+        // 1st table
+        assertXPath(pLayout, "//tab[1]['pass 2']/infos/prtBounds", "left", 
u"1000");
+        OUString width = getXPath(pLayout, "//tab[1]['pass 
2']/row/cell[1]/infos/bounds", "width");
+        CPPUNIT_ASSERT_DOUBLES_EQUAL(7000, width.toInt32(), 1);
+        width = getXPath(pLayout, "//tab[1]['pass 
2']/row/cell[2]/infos/bounds", "width");
+        CPPUNIT_ASSERT_DOUBLES_EQUAL(1000, width.toInt32(), 1);
+        // 2nd table
+        assertXPath(pLayout, "//tab[2]['pass 2']/infos/prtBounds", "left", 
u"1000");
+        width = getXPath(pLayout, "//tab[2]['pass 
2']/row/cell[1]/infos/bounds", "width");
+        CPPUNIT_ASSERT_DOUBLES_EQUAL(7000, width.toInt32(), 1);
+        width = getXPath(pLayout, "//tab[2]['pass 
2']/row/cell[2]/infos/bounds", "width");
+        CPPUNIT_ASSERT_DOUBLES_EQUAL(1000, width.toInt32(), 1);
+        // 3rd table
+        assertXPath(pLayout, "//tab[3]['pass 2']/infos/prtBounds", "left", 
u"0");
+        width = getXPath(pLayout, "//tab[3]['pass 
2']/row/cell[1]/infos/bounds", "width");
+        CPPUNIT_ASSERT_DOUBLES_EQUAL(8000, width.toInt32(), 1);
+        width = getXPath(pLayout, "//tab[3]['pass 
2']/row/cell[2]/infos/bounds", "width");
+        CPPUNIT_ASSERT_DOUBLES_EQUAL(1000, width.toInt32(), 1);
+    }
+}
+
 } // end of anonymous namespace
 CPPUNIT_PLUGIN_IMPLEMENT();
 
diff --git a/sw/source/writerfilter/rtftok/rtfdispatchvalue.cxx 
b/sw/source/writerfilter/rtftok/rtfdispatchvalue.cxx
index d89c3420017a..a5999fbcde25 100644
--- a/sw/source/writerfilter/rtftok/rtfdispatchvalue.cxx
+++ b/sw/source/writerfilter/rtftok/rtfdispatchvalue.cxx
@@ -386,6 +386,32 @@ bool RTFDocumentImpl::dispatchFrameValue(RTFKeyword 
nKeyword, int nParam)
     return false;
 }
 
+static int GetCellWidth(int thisCellX, int prevCellX, RTFSprms& tableRowSprms)
+{
+    thisCellX -= prevCellX;
+    if (thisCellX == 0 && prevCellX > 0)
+    {
+        // If width of cell is 0, BUT there is a value for +        // 
possible width. But if +        // try to resolve this.
+
+        // sw/source/filter/inc/wrtswtbl.hxx, minimal possible width of cells.
+        const int COL_DFLT_WIDTH = 41;
+        thisCellX = COL_DFLT_WIDTH;
+    }
+    // If there is a negative left margin, then the first cellx is relative to 
that.
+    if (prevCellX == 0)
+    {
+        if (RTFValue::Pointer_t pTblInd = 
tableRowSprms.find(NS_ooxml::LN_CT_TblPrBase_tblInd))
+        {
+            RTFValue::Pointer_t pWidth = 
pTblInd->getAttributes().find(NS_ooxml::LN_CT_TblWidth_w);
+            if (pWidth && pWidth->getInt() < 0)
+                thisCellX = -1 * (pWidth->getInt() - prevCellX);
+        }
+    }
+    return thisCellX;
+}
+
 bool RTFDocumentImpl::dispatchTableValue(RTFKeyword nKeyword, int nParam)
 {
     int nSprm = 0;
@@ -399,30 +425,7 @@ bool RTFDocumentImpl::dispatchTableValue(RTFKeyword 
nKeyword, int nParam)
                 (Destination::NESTEDTABLEPROPERTIES == 
m_aStates.top().getDestination())
                     ? m_nNestedCurrentCellX
                     : m_nTopLevelCurrentCellX);
-            int nCellX = nParam - rCurrentCellX;
-
-            if (!nCellX && nParam > 0)
-            {
-                // If width of cell is 0, BUT there is a value for -           
     // possible width. But if -                // try to resolve this.
-
-                // sw/source/filter/inc/wrtswtbl.hxx, minimal possible width 
of cells.
-                const int COL_DFLT_WIDTH = 41;
-                nCellX = COL_DFLT_WIDTH;
-            }
-
-            // If there is a negative left margin, then the first cellx is 
relative to that.
-            RTFValue::Pointer_t pTblInd
-                = 
m_aStates.top().getTableRowSprms().find(NS_ooxml::LN_CT_TblPrBase_tblInd);
-            if (rCurrentCellX == 0 && pTblInd)
-            {
-                RTFValue::Pointer_t pWidth
-                    = 
pTblInd->getAttributes().find(NS_ooxml::LN_CT_TblWidth_w);
-                if (pWidth && pWidth->getInt() < 0)
-                    nCellX = -1 * (pWidth->getInt() - nParam);
-            }
-
+            int nCellX = GetCellWidth(nParam, rCurrentCellX, 
m_aStates.top().getTableRowSprms());
             rCurrentCellX = nParam;
             auto pXValue = new RTFValue(nCellX);
             
m_aStates.top().getTableRowSprms().set(NS_ooxml::LN_CT_TblGridBase_gridCol, 
pXValue,
@@ -512,11 +515,31 @@ bool RTFDocumentImpl::dispatchTableValue(RTFKeyword 
nKeyword, int nParam)
                                       .find(NS_ooxml::LN_CT_TblWidth_w)
                                       ->getInt();
                 }
-                rCurrentTRLeft = nParam;
             }
-            else
-                rCurrentTRLeft = rCurrentCellX = nParam;
-
+            rCurrentTRLeft = nParam;
+            // Correct the first cellX, if already pushed before these.
+            // FIXME: this whole convoluted processing of CELLX, TRLEFT, 
TBLIND should be replaced
+            // with simple pushing of the respective values as is; and all 
that should eventually
+            // be processed in RTFKeyword::ROW handler 
(RTFDocumentImpl::dispatchSymbol), where all
+            // information would already be available. There we could know the 
table indent, row
+            // left offset, all right cell boundaries; and could calculate 
correct widths (likely
+            // in prepareProperties call).
+            bool hadCellX = false;
+            for (auto & [ id, pValue ] : m_aStates.top().getTableRowSprms())
+            {
+                if (id == NS_ooxml::LN_CT_TblGridBase_gridCol)
+                {
+                    if (int val = pValue->getInt(); val != -1)
+                    {
+                        val = GetCellWidth(val, nParam, 
m_aStates.top().getTableRowSprms());
+                        pValue = new RTFValue(val);
+                        hadCellX = true;
+                        break;
+                    }
+                }
+            }
+            if (!hadCellX)
+                rCurrentCellX = rCurrentTRLeft;
             putNestedAttribute(m_aStates.top().getTableRowSprms(), 
NS_ooxml::LN_CT_TblPrBase_tblInd,
                                +NS_ooxml::LN_CT_TblWidth_w, new 
RTFValue(nParam));
             return true;

Reply via email to