262 lines
10 KiB
C++
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: */
|