1
0
Fork 0
libreoffice/sw/qa/core/layout/tabfrm.cxx
Daniel Baumann 8e63e14cf6
Adding upstream version 4:25.2.3.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
2025-06-22 16:20:04 +02:00

262 lines
10 KiB
C++

/* -*- 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 <IDocumentLayoutAccess.hxx>
#include <rootfrm.hxx>
#include <pagefrm.hxx>
#include <tabfrm.hxx>
#include <sortedobjs.hxx>
#include <anchoredobject.hxx>
#include <flyfrm.hxx>
#include <flyfrms.hxx>
#include <docsh.hxx>
#include <wrtsh.hxx>
namespace
{
/// Covers sw/source/core/layout/tabfrm.cxx fixes.
class Test : public SwModelTestBase
{
public:
Test()
: SwModelTestBase(u"/sw/qa/core/layout/data/"_ustr)
{
}
};
CPPUNIT_TEST_FIXTURE(Test, testTablePrintAreaLeft)
{
// Given a document with a header containing an image, and also with an overlapping table:
createSwDoc("table-print-area-left.docx");
xmlDocUniquePtr pXmlDoc = parseLayoutDump();
// When laying out that document & parsing the left margin of the table:
SwTwips nTablePrintLeft = getXPath(pXmlDoc, "//tab/infos/prtBounds", "left").toInt32();
// Then make sure it has ~no left margin:
// Without the accompanying fix in place, this test would have failed with:
// - Expected: 5
// - Actual : 10646
// i.e. the table was shifted outside the page, was invisible.
CPPUNIT_ASSERT_EQUAL(static_cast<SwTwips>(5), nTablePrintLeft);
}
CPPUNIT_TEST_FIXTURE(Test, testTableMissingJoin)
{
// Given a document with a table on page 2:
// When laying out that document:
createSwDoc("table-missing-join.docx");
// Then make sure that the table fits page 2:
SwDoc* pDoc = getSwDoc();
SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
auto pPage1 = pLayout->Lower()->DynCastPageFrame();
CPPUNIT_ASSERT(pPage1);
auto pPage2 = pPage1->GetNext()->DynCastPageFrame();
CPPUNIT_ASSERT(pPage2);
SwFrame* pBody = pPage2->FindBodyCont();
auto pTab = pBody->GetLower()->DynCastTabFrame();
// Without the accompanying fix in place, this test would have failed, the table continued on
// page 3.
CPPUNIT_ASSERT(!pTab->HasFollow());
}
CPPUNIT_TEST_FIXTURE(Test, testSplitFlyInInlineTable)
{
// Outer inline table on pages 1 -> 2 -> 3, inner floating table on pages 2 -> 3:
// When laying out that document:
createSwDoc("floattable-in-inlinetable.docx");
// Then make sure that the outer table is not missing on page 3:
SwDoc* pDoc = getSwDoc();
SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
auto pPage1 = pLayout->Lower()->DynCastPageFrame();
CPPUNIT_ASSERT(pPage1);
{
SwFrame* pBody = pPage1->FindBodyCont();
auto pTab = pBody->GetLower()->DynCastTabFrame();
CPPUNIT_ASSERT(!pTab->GetPrecede());
CPPUNIT_ASSERT(pTab->GetFollow());
}
auto pPage2 = pPage1->GetNext()->DynCastPageFrame();
CPPUNIT_ASSERT(pPage2);
{
SwFrame* pBody = pPage2->FindBodyCont();
auto pTab = pBody->GetLower()->DynCastTabFrame();
CPPUNIT_ASSERT(pTab->GetPrecede());
// Without the accompanying fix in place, this test would have failed, the outer table was
// missing on page 3.
CPPUNIT_ASSERT(pTab->GetFollow());
}
auto pPage3 = pPage2->GetNext()->DynCastPageFrame();
CPPUNIT_ASSERT(pPage3);
{
SwFrame* pBody = pPage3->FindBodyCont();
auto pTab = pBody->GetLower()->DynCastTabFrame();
CPPUNIT_ASSERT(pTab->GetPrecede());
CPPUNIT_ASSERT(!pTab->GetFollow());
}
}
CPPUNIT_TEST_FIXTURE(Test, testSplitFlyNestedRowSpan)
{
// Given a document with nested floating tables and a row with rowspan cells at page boundary:
// When loading that document:
// Without the accompanying fix in place, this test would have resulted in a layout loop.
createSwDoc("floattable-nested-rowspan.docx");
// Then make sure the resulting page count matches Word:
CPPUNIT_ASSERT_EQUAL(6, getPages());
}
CPPUNIT_TEST_FIXTURE(Test, testSplitFlyTableJoin)
{
// Given a document with a multi-page floating table:
// When loading this document:
createSwDoc("floattable-table-join.docx");
// Then make sure this document doesn't crash the layout and has a floating table split on 4
// pages:
SwDoc* pDoc = getSwDoc();
SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
auto pPage1 = pLayout->Lower()->DynCastPageFrame();
CPPUNIT_ASSERT(pPage1);
CPPUNIT_ASSERT(pPage1->GetSortedObjs());
{
SwSortedObjs& rPageObjs = *pPage1->GetSortedObjs();
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rPageObjs.size());
auto pFly = rPageObjs[0]->DynCastFlyFrame()->DynCastFlyAtContentFrame();
CPPUNIT_ASSERT(pFly);
// Start of the chain.
CPPUNIT_ASSERT(!pFly->GetPrecede());
CPPUNIT_ASSERT(pFly->HasFollow());
}
auto pPage2 = pPage1->GetNext()->DynCastPageFrame();
CPPUNIT_ASSERT(pPage2);
CPPUNIT_ASSERT(pPage2->GetSortedObjs());
{
SwSortedObjs& rPageObjs = *pPage2->GetSortedObjs();
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rPageObjs.size());
auto pFly = rPageObjs[0]->DynCastFlyFrame()->DynCastFlyAtContentFrame();
CPPUNIT_ASSERT(pFly);
CPPUNIT_ASSERT(pFly->GetPrecede());
CPPUNIT_ASSERT(pFly->HasFollow());
}
auto pPage3 = pPage2->GetNext()->DynCastPageFrame();
CPPUNIT_ASSERT(pPage3);
CPPUNIT_ASSERT(pPage3->GetSortedObjs());
{
SwSortedObjs& rPageObjs = *pPage3->GetSortedObjs();
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rPageObjs.size());
auto pFly = rPageObjs[0]->DynCastFlyFrame()->DynCastFlyAtContentFrame();
CPPUNIT_ASSERT(pFly);
CPPUNIT_ASSERT(pFly->GetPrecede());
CPPUNIT_ASSERT(pFly->HasFollow());
}
auto pPage4 = pPage3->GetNext()->DynCastPageFrame();
CPPUNIT_ASSERT(pPage4);
CPPUNIT_ASSERT(pPage4->GetSortedObjs());
SwSortedObjs& rPageObjs = *pPage4->GetSortedObjs();
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rPageObjs.size());
auto pFly = rPageObjs[0]->DynCastFlyFrame()->DynCastFlyAtContentFrame();
CPPUNIT_ASSERT(pFly);
// End of the chain.
CPPUNIT_ASSERT(pFly->GetPrecede());
CPPUNIT_ASSERT(!pFly->HasFollow());
}
CPPUNIT_TEST_FIXTURE(Test, testSplitFlyWrappedByTable)
{
// Given a document with a floating table, wrapped by an inline table:
// When laying out the document:
createSwDoc("floattable-wrapped-by-table.docx");
// Then make sure the inline table wraps around the floating table:
SwDoc* pDoc = getSwDoc();
SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
auto pPage = pLayout->Lower()->DynCastPageFrame();
CPPUNIT_ASSERT(pPage);
// Get the top of the inline table, ignoring margins:
CPPUNIT_ASSERT(pPage->GetSortedObjs());
SwSortedObjs& rPageObjs = *pPage->GetSortedObjs();
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rPageObjs.size());
auto pFly = rPageObjs[0]->DynCastFlyFrame()->DynCastFlyAtContentFrame();
CPPUNIT_ASSERT(pFly);
// Get the bottom of the floating table, ignoring margins:
SwTwips nFloatingBottom = pFly->getFrameArea().Top() + pFly->getFramePrintArea().Height();
SwFrame* pBody = pPage->FindBodyCont();
auto pTab = pBody->GetLower()->GetNext()->DynCastTabFrame();
SwTwips nInlineTop = pTab->getFrameArea().Top() + pTab->getFramePrintArea().Top();
// Make sure the inline table is on the right of the floating one, not below it:
// Without the accompanying fix in place, this test would have failed with:
// - Expected less than: 7287
// - Actual : 7287
// i.e. the inline table was under the floating one, not on the right of it.
CPPUNIT_ASSERT_LESS(nFloatingBottom, nInlineTop);
}
CPPUNIT_TEST_FIXTURE(Test, testInlineTableThenSplitFly)
{
// Given a document with a floating table ("right") and an inline table ("left"):
// When laying out the document:
createSwDoc("floattable-not-wrapped-by-table.docx");
// Then make sure the inline table is on the left (small negative offset):
SwDoc* pDoc = getSwDoc();
SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
auto pPage = pLayout->Lower()->DynCastPageFrame();
CPPUNIT_ASSERT(pPage);
SwFrame* pBody = pPage->FindBodyCont();
auto pTab = pBody->GetLower()->GetNext()->DynCastTabFrame();
SwTwips nInlineLeft = pTab->getFramePrintArea().Left();
// Without the accompanying fix in place, this test would have failed with:
// - Expected less than: 0
// - Actual : 6958
// i.e. "left" was on the right, its horizontal margin was not a small negative value but a
// large positive one.
CPPUNIT_ASSERT_LESS(static_cast<SwTwips>(0), nInlineLeft);
}
CPPUNIT_TEST_FIXTURE(Test, testSplitFlyWrappedByTableNested)
{
// Given a document with 3 tables, one inline toplevel and two inner ones (one inline, one
// floating):
// When laying out that document:
// Without the accompanying fix in place, this test would have failed here with a layout loop.
createSwDoc("floattable-wrapped-by-table-nested.docx");
// Than make sure we have 3 tables, but only one of them is floating:
SwDoc* pDoc = getSwDoc();
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(3), pDoc->GetTableFrameFormats()->GetFormatCount());
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), pDoc->GetSpzFrameFormats()->GetFormatCount());
}
CPPUNIT_TEST_FIXTURE(Test, testSplitFlyHeader)
{
// Given a document with 8 pages: a first page ending in a manual page break, then a multi-page
// floating table on pages 2..8:
createSwDoc("floattable-header.docx");
CPPUNIT_ASSERT_EQUAL(8, getPages());
// When creating a new paragraph at doc start:
SwDocShell* pDocShell = getSwDocShell();
SwWrtShell* pWrtShell = pDocShell->GetWrtShell();
pWrtShell->SttEndDoc(/*bStt=*/true);
pWrtShell->SplitNode();
// Without the accompanying fix in place, this test would have crashed here.
calcLayout();
// Then make sure we get one more page, since the first page is now 2 pages:
CPPUNIT_ASSERT_EQUAL(9, getPages());
}
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */