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 <vmiklos@collabora.com>
Tested-by: Jenkins
(cherry picked from commit 47d824dd167eb34b08e5aec7141d2d9e6e996b34)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/159588
Reviewed-by: Xisco Fauli <xiscofauli@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 0000000..122bfd4
--- /dev/null
+++ b/sw/qa/core/layout/data/split-table-merged-border.odt
Binary files differ
diff --git a/sw/qa/core/layout/paintfrm.cxx b/sw/qa/core/layout/paintfrm.cxx
index ad09405..baa8580 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 8242a99..a23d86d 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();