sw/qa/core/layout/data/split-table-merged-border.odt |binary
 sw/qa/core/layout/paintfrm.cxx                       |   49 +++++++++++++++++++
 sw/source/core/layout/paintfrm.cxx                   |   24 +++++----
 3 files changed, 63 insertions(+), 10 deletions(-)

New commits:
commit 7a1b3f58080b301929269c0b4a5310851a0ee2bb
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Wed Nov 15 08:24:39 2023 +0100
Commit:     Xisco Fauli <xiscofa...@libreoffice.org>
CommitDate: Thu Nov 30 10:25:18 2023 +0100

    tdf#157911 sw floattable: fix inconsistent inferred bottom border on split
    
    The bugdoc has a split table between page 1 and page 2. The last row of
    page 1 has a half bottom border: it starts on the left of the table,
    but finishes earlier than the right of the table. This is since commit
    08aea5526c75ff4c5385e960bd940f10ffa19cd5 (tdf#156351 sw floattable: fix
    missing bottom border in master table, 2023-08-21).
    
    The trouble is that Writer table borders are really at a cell-level (and
    not at row or table level), the current partial border happens because
    the first row has merged cells and the last row on page 1 doesn't have
    merged cells, so the layout can't do a 1:1 mapping between the first row
    and last row cells. It's also far from clear if the fixed result should
    be no bottom border or a table-width bottom border:
    
    - Word documents can have cell-level borders (where no inferred border
      is wanted) and table-level borders (where inferred borders are
      wanted), see the tdf#156351 bugdoc for a case where such inferring is
      wanted
    
    - In case only cell-level borders are defined, then Word doesn't do such
      inferring
    
    Fix the problem by always inferring such borders, because:
    
    - Writer already did this in some cases for a long time, see commit
      a4da71fb824f2d4ecc7c01f4deb2865ba52f5f4c (INTEGRATION: CWS fmebugs04
      (1.115.46); FILE MERGED 2008/05/13 13:56:19 fme 1.115.46.2: #i9860# Top
      border for tables - correction 2008/05/13 13:49:23 fme 1.115.46.1:
      #i9860# Top border for tables, 2008-06-06)
    
    - The Word UI creates table borders by default, so the majority of the
      DOCX documents also want this inferring
    
    An alternative could be to only do such inferring for Word documents
    with a compat flag, but that looks poor, given that Word doesn't always
    do such inferring itself, either.
    
    Change-Id: I052e4591e99d066c3109e8ab8b590e97c8aebd36
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/159429
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>
    Tested-by: Jenkins
    (cherry picked from commit 47d824dd167eb34b08e5aec7141d2d9e6e996b34)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/159588
    Reviewed-by: Xisco Fauli <xiscofa...@libreoffice.org>

diff --git a/sw/qa/core/layout/data/split-table-merged-border.odt 
b/sw/qa/core/layout/data/split-table-merged-border.odt
new file mode 100644
index 000000000000..122bfd473c7c
Binary files /dev/null and 
b/sw/qa/core/layout/data/split-table-merged-border.odt differ
diff --git a/sw/qa/core/layout/paintfrm.cxx b/sw/qa/core/layout/paintfrm.cxx
index ad09405fe3fb..baa858020acf 100644
--- a/sw/qa/core/layout/paintfrm.cxx
+++ b/sw/qa/core/layout/paintfrm.cxx
@@ -109,6 +109,55 @@ CPPUNIT_TEST_FIXTURE(Test, testRTLBorderMerge)
     // i.e. the 2nd and 5th vertical border was missing.
     CPPUNIT_ASSERT_EQUAL(6, nVerticalBorders);
 }
+
+CPPUNIT_TEST_FIXTURE(Test, testSplitTableMergedBorder)
+{
+    // Given a document with a split table, first row in frame 1 has merged 
cells:
+    createSwDoc("split-table-merged-border.odt");
+    SwXTextDocument* pTextDoc = 
dynamic_cast<SwXTextDocument*>(mxComponent.get());
+    SwDocShell* pShell = pTextDoc->GetDocShell();
+
+    // When rendering that document:
+    std::shared_ptr<GDIMetaFile> xMetaFile = pShell->GetPreviewMetaFile();
+
+    // Then make sure that the master table has a bottom border with the 
correct widths:
+    MetafileXmlDump aDumper;
+    xmlDocUniquePtr pXmlDoc = dumpAndParse(aDumper, *xMetaFile);
+    xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, 
"//polyline[@style='solid']/point");
+    xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
+    std::set<int> aHorizontalBorderStarts;
+    std::set<int> aHorizontalBorderEnds;
+    // Collect the horizontal borders:
+    for (int i = 0; i < xmlXPathNodeSetGetLength(pXmlNodes); i += 2)
+    {
+        xmlNodePtr pStart = pXmlNodes->nodeTab[i];
+        xmlNodePtr pEnd = pXmlNodes->nodeTab[i + 1];
+        xmlChar* pStartY = xmlGetProp(pStart, BAD_CAST("y"));
+        xmlChar* pEndY = xmlGetProp(pEnd, BAD_CAST("y"));
+        sal_Int32 nStartY = o3tl::toInt32(reinterpret_cast<char 
const*>(pStartY));
+        sal_Int32 nEndY = o3tl::toInt32(reinterpret_cast<char const*>(pEndY));
+        if (nStartY != nEndY)
+        {
+            // Vertical border.
+            continue;
+        }
+
+        xmlChar* pStartX = xmlGetProp(pStart, BAD_CAST("x"));
+        xmlChar* pEndX = xmlGetProp(pEnd, BAD_CAST("x"));
+        sal_Int32 nStartX = o3tl::toInt32(reinterpret_cast<char 
const*>(pStartX));
+        sal_Int32 nEndX = o3tl::toInt32(reinterpret_cast<char const*>(pEndX));
+        aHorizontalBorderStarts.insert(nStartX);
+        aHorizontalBorderEnds.insert(nEndX);
+    }
+    xmlXPathFreeObject(pXmlObj);
+    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), 
aHorizontalBorderStarts.size());
+    // Without the accompanying fix in place, this test would have failed with:
+    // - Expected: 2
+    // - Actual  : 3
+    // i.e. the frame 1 bottom border ended sooner than expected, resulting in 
a buggy, partial
+    // bottom border.
+    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), aHorizontalBorderEnds.size());
+}
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/layout/paintfrm.cxx 
b/sw/source/core/layout/paintfrm.cxx
index 8242a99634f2..a23d86d1181c 100644
--- a/sw/source/core/layout/paintfrm.cxx
+++ b/sw/source/core/layout/paintfrm.cxx
@@ -2902,19 +2902,21 @@ void SwTabFramePainter::InsertFollowTopBorder(const 
SwFrame& rFrame, const SvxBo
     }
 
     const SwFrame* pLastCell = pLastRow->GetLower();
+    if (!pLastCell)
+    {
+        return;
+    }
+
     for (int i = 0; i < nCol; ++i)
     {
-        if (!pLastCell)
+        if (!pLastCell->GetNext())
         {
+            // Reference row has merged cells, work with the last possible one.
             break;
         }
 
         pLastCell = pLastCell->GetNext();
     }
-    if (!pLastCell)
-    {
-        return;
-    }
 
     SwBorderAttrAccess aAccess(SwFrame::GetCache(), pLastCell);
     const SwBorderAttrs& rAttrs = *aAccess.Get();
@@ -2975,19 +2977,21 @@ void SwTabFramePainter::InsertMasterBottomBorder(const 
SwFrame& rFrame, const Sv
     }
 
     const SwFrame* pFirstCell = pFirstRow->GetLower();
+    if (!pFirstCell)
+    {
+        return;
+    }
+
     for (int i = 0; i < nCol; ++i)
     {
-        if (!pFirstCell)
+        if (!pFirstCell->GetNext())
         {
+            // Reference row has merged cells, work with the last possible one.
             break;
         }
 
         pFirstCell = pFirstCell->GetNext();
     }
-    if (!pFirstCell)
-    {
-        return;
-    }
 
     SwBorderAttrAccess aAccess(SwFrame::GetCache(), pFirstCell);
     const SwBorderAttrs& rAttrs = *aAccess.Get();

Reply via email to