sw/CppunitTest_sw_core_layout.mk | 1 sw/qa/core/layout/data/split-table-border.odt |binary sw/qa/core/layout/paintfrm.cxx | 71 +++++++++++++++++++++++ sw/source/core/layout/paintfrm.cxx | 80 ++++++++++++++++++++++++++ 4 files changed, 152 insertions(+)
New commits: commit 4650100548eae49978a40200313182ca7d2706f1 Author: Miklos Vajna <vmik...@collabora.com> AuthorDate: Fri Aug 18 11:21:25 2023 +0200 Commit: Caolán McNamara <caolan.mcnam...@collabora.com> CommitDate: Tue Aug 22 18:04:46 2023 +0200 Related: tdf#156351 sw floattable: fix missing top border in follow table The problem was that in case a table has a table border but no cell border, then the follow table was missing a top border in case the follow table had multiple rows. This was already working for single-row follow tables since 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: i#9860 Top border for tables, 2008-06-06). Fix the problem by checking for the case when the first row in a follow table has no own bottom border and then take that bottom border from the last row instead, if that has a bottom border. The reported case around the missing bottom border in the master table still needs work. (cherry picked from commit 53798fef2cc0b5b0b9706081a4af5ceca964a41b) Conflicts: sw/CppunitTest_sw_core_layout.mk sw/source/core/layout/paintfrm.cxx Change-Id: Ib418da99067a42efcf3bd0e2d6a9467797de619a Reviewed-on: https://gerrit.libreoffice.org/c/core/+/155885 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com> Tested-by: Caolán McNamara <caolan.mcnam...@collabora.com> Reviewed-by: Caolán McNamara <caolan.mcnam...@collabora.com> diff --git a/sw/CppunitTest_sw_core_layout.mk b/sw/CppunitTest_sw_core_layout.mk index 1a7aeb649887..f360033d3378 100644 --- a/sw/CppunitTest_sw_core_layout.mk +++ b/sw/CppunitTest_sw_core_layout.mk @@ -16,6 +16,7 @@ $(eval $(call gb_CppunitTest_use_common_precompiled_header,sw_core_layout)) $(eval $(call gb_CppunitTest_add_exception_objects,sw_core_layout, \ sw/qa/core/layout/flycnt \ sw/qa/core/layout/layout \ + sw/qa/core/layout/paintfrm \ )) $(eval $(call gb_CppunitTest_use_libraries,sw_core_layout, \ diff --git a/sw/qa/core/layout/data/split-table-border.odt b/sw/qa/core/layout/data/split-table-border.odt new file mode 100644 index 000000000000..743d54bd38c5 Binary files /dev/null and b/sw/qa/core/layout/data/split-table-border.odt differ diff --git a/sw/qa/core/layout/paintfrm.cxx b/sw/qa/core/layout/paintfrm.cxx new file mode 100644 index 000000000000..15b9df6a4fb4 --- /dev/null +++ b/sw/qa/core/layout/paintfrm.cxx @@ -0,0 +1,71 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <swmodeltestbase.hxx> + +#include <o3tl/string_view.hxx> + +#include <docsh.hxx> +#include <unotxdoc.hxx> + +namespace +{ +/// Covers sw/source/core/layout/paintfrm.cxx fixes. +class Test : public SwModelTestBase +{ +public: + Test() + : SwModelTestBase("/sw/qa/core/layout/data/") + { + } +}; + +CPPUNIT_TEST_FIXTURE(Test, testSplitTableBorder) +{ + // Given a document with a split table, table borders are defined, but cell borders are not: + createSwDoc("split-table-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 follow table has a top border: + MetafileXmlDump aDumper; + xmlDocUniquePtr pXmlDoc = dumpAndParse(aDumper, *xMetaFile); + xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, "//polyline[@style='solid']/point"); + xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval; + int nHorizontalBorders = 0; + // Count 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; + } + + ++nHorizontalBorders; + } + xmlXPathFreeObject(pXmlObj); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 3 + // - Actual : 2 + // i.e. the top border in the follow table was missing. + CPPUNIT_ASSERT_EQUAL(3, nHorizontalBorders); +} +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/layout/paintfrm.cxx b/sw/source/core/layout/paintfrm.cxx index 405f3888d3eb..211a539b8c8f 100644 --- a/sw/source/core/layout/paintfrm.cxx +++ b/sw/source/core/layout/paintfrm.cxx @@ -2389,6 +2389,12 @@ class SwTabFramePainter void Insert( SwLineEntry&, bool bHori ); void Insert(const SwFrame& rFrame, const SvxBoxItem& rBoxItem, const SwRect &rPaintArea); + + /// Inserts top border at the top of a follow table. + void InsertFollowTopBorder(const SwFrame& rFrame, const SvxBoxItem& rBoxItem, + bool bWordTableCell, SwTwips nTop, SwTwips nLeft, SwTwips nRight, + bool bTopIsOuter); + void HandleFrame(const SwLayoutFrame& rFrame, const SwRect& rPaintArea); void FindStylesForLine( Point&, Point&, @@ -2824,6 +2830,78 @@ static bool lcl_IsFirstRowInFollowTableWithoutRepeatedHeadlines( && rBoxItem.GetBottom()); } +void SwTabFramePainter::InsertFollowTopBorder(const SwFrame& rFrame, const SvxBoxItem& rBoxItem, + bool bWordTableCell, SwTwips nTop, SwTwips nLeft, + SwTwips nRight, bool bTopIsOuter) +{ + // Figure out which cell to copy. + int nCol = 0; + const SwFrame* pCell = &rFrame; + while (pCell) + { + if (!pCell->GetPrev()) + { + break; + } + + ++nCol; + pCell = pCell->GetPrev(); + } + + auto pThisRow = dynamic_cast<const SwRowFrame*>(rFrame.GetUpper()); + if (!pThisRow || pThisRow->GetUpper() != &mrTabFrame) + { + return; + } + + if (!mrTabFrame.IsFollow() || mrTabFrame.GetTable()->GetRowsToRepeat()) + { + return; + } + + if (pThisRow->GetPrev() || rBoxItem.GetTop() || rBoxItem.GetBottom()) + { + return; + } + + // This is then a first row in a follow table, without repeated headlines. + auto pLastRow = dynamic_cast<const SwRowFrame*>(mrTabFrame.GetLastLower()); + if (!pLastRow && pLastRow == pThisRow) + { + return; + } + + const SwFrame* pLastCell = pLastRow->GetLower(); + for (int i = 0; i < nCol; ++i) + { + if (!pLastCell) + { + break; + } + + pLastCell = pLastCell->GetNext(); + } + if (!pLastCell) + { + return; + } + + SwBorderAttrAccess aAccess(SwFrame::GetCache(), pLastCell); + const SwBorderAttrs& rAttrs = *aAccess.Get(); + const SvxBoxItem& rLastBoxItem = rAttrs.GetBox(); + if (!rLastBoxItem.GetBottom()) + { + return; + } + + // The matching (same column) row in the last row has a bottom border for us. + svx::frame::Style aFollowB(rLastBoxItem.GetBottom(), 1.0); + aFollowB.SetWordTableCell(bWordTableCell); + SwLineEntry aFollowTop(nTop, nLeft, nRight, bTopIsOuter, aFollowB); + aFollowB.SetRefMode(svx::frame::RefMode::Begin); + Insert(aFollowTop, true); +} + void SwTabFramePainter::Insert(const SwFrame& rFrame, const SvxBoxItem& rBoxItem, const SwRect& rPaintArea) { // build 4 line entries for the 4 borders: @@ -2910,6 +2988,8 @@ void SwTabFramePainter::Insert(const SwFrame& rFrame, const SvxBoxItem& rBoxItem Insert( aRight, false ); Insert( aTop, true ); Insert( aBottom, true ); + + InsertFollowTopBorder(rFrame, rBoxItem, bWordTableCell, nTop, nLeft, nRight, bTopIsOuter); } void SwTabFramePainter::Insert( SwLineEntry& rNew, bool bHori )