/* -*- 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 #include #include #include #include #include #include #include #include #include #include namespace { /// Covers sw/source/core/layout/tabfrm.cxx fixes. class Test : public SwModelTestBase { public: Test() : SwModelTestBase("/sw/qa/core/layout/data/") { } }; 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"); // When laying out that document & parsing the left margin of the table: SwTwips nTablePrintLeft = parseDump("//tab/infos/prtBounds"_ostr, "left"_ostr).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(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(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(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(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(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(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(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(3), pDoc->GetTableFrameFormats()->GetFormatCount()); CPPUNIT_ASSERT_EQUAL(static_cast(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. pWrtShell->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: */