From cb8b20ab3aa3f790d4979385874cdd4e2a87221b Mon Sep 17 00:00:00 2001 From: Miklos Vajna Date: Wed, 25 Oct 2017 17:48:32 +0200 Subject: tdf#113445 sw: avoid hitting loop control with a dozen of in-table sections The bugdoc has an (outer) table containing a single cell, which has an (inner) table with 12 cells, all content is inside sections, one section / cell. This relatively simple setup can already hit the loop control in lcl_RecalcRow(), as the SwLayNotify dtor always does invalidation in an async way, so the loop control's counter is incremented after each and every table cell. Instead of increasing the max tolerance in lcl_RecalcRow() (one can easily construct a document where the bug is still there even if the max is set to 100 instead of the current 10 iterations), just calculate the lower synchronously. Change-Id: Ifbffe13e5f2f237e1578bdd3e17d4d8b7c34806d Reviewed-on: https://gerrit.libreoffice.org/43848 Reviewed-by: Miklos Vajna Tested-by: Jenkins --- sw/qa/extras/uiwriter/data/tdf113445.fodt | 348 ++++++++++++++++++++++++++++++ sw/qa/extras/uiwriter/uiwriter.cxx | 37 ++++ sw/source/core/layout/sectfrm.cxx | 15 +- sw/source/core/layout/tabfrm.cxx | 16 +- 4 files changed, 405 insertions(+), 11 deletions(-) create mode 100644 sw/qa/extras/uiwriter/data/tdf113445.fodt diff --git a/sw/qa/extras/uiwriter/data/tdf113445.fodt b/sw/qa/extras/uiwriter/data/tdf113445.fodt new file mode 100644 index 000000000000..b6c3de4bd516 --- /dev/null +++ b/sw/qa/extras/uiwriter/data/tdf113445.fodt @@ -0,0 +1,348 @@ + + + + LibreOfficeDev/6.0.0.0.alpha1$Linux_X86_64 LibreOffice_project/54a0f24d1650637efb4557c0f72a9978bc9acc96 + 2014-11-10T09:45:40.73 + 2017-10-02T14:36:23 + 4 + PT1.570S + + + + + 0 + 0 + 45563 + 12305 + true + false + + + view2 + 4069 + 901 + 0 + 0 + 45561 + 12303 + 0 + 0 + false + 100 + false + false + + + + + false + true + true + true + true + 0 + true + + false + false + false + false + false + false + false + false + false + false + false + false + false + true + false + true + true + false + false + false + false + + false + false + false + true + false + false + + false + false + false + false + true + 353015 + false + true + true + false + true + true + false + true + 0 + false + true + high-resolution + false + false + false + true + true + true + writer-data-source-ooxml + true + false + false + true + false + false + false + + false + false + 104774 + false + 1 + true + false + false + 0 + false + false + + + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Table2:A1 + + + Table2:B1 + + + Table2:C1 + + + Table2:D1 + + + + + Table2:A2 + + + Table2:B2 + + + Table2:C2 + + + Table2:D2 + + + + + + Table2:A3 + + + + + Table2:B3 + + + + + Table2:C3 + + + + + Table2:D3 + + + + + + + Table2:A4 + + + + + Table2:B4 + + + + + Table2:C4 + + + + + Table2:D4 + + + + + + + Table2:A5 + + + + + Table2:B5 + + + + + Table2:C5 + + + + + Table2:D5 + + + + + + + + + + + + diff --git a/sw/qa/extras/uiwriter/uiwriter.cxx b/sw/qa/extras/uiwriter/uiwriter.cxx index fc372f646561..f77f603658e0 100644 --- a/sw/qa/extras/uiwriter/uiwriter.cxx +++ b/sw/qa/extras/uiwriter/uiwriter.cxx @@ -276,6 +276,7 @@ public: void testTdf112741(); void testTdf112860(); void testTdf113287(); + void testTdf113445(); #endif void testLinesInSectionInTable(); void testParagraphOfTextRange(); @@ -440,6 +441,7 @@ public: CPPUNIT_TEST(testTdf112741); CPPUNIT_TEST(testTdf112860); CPPUNIT_TEST(testTdf113287); + CPPUNIT_TEST(testTdf113445); #endif CPPUNIT_TEST(testLinesInSectionInTable); CPPUNIT_TEST(testParagraphOfTextRange); @@ -5342,6 +5344,41 @@ void SwUiWriterTest::testTdf113287() CPPUNIT_ASSERT_GREATER(nCellTop, nSectionTop); } +void SwUiWriterTest::testTdf113445() +{ + // Force multiple-page view. + SwDoc* pDoc = createDoc("tdf113445.fodt"); + SwDocShell* pDocShell = pDoc->GetDocShell(); + SwView* pView = pDocShell->GetView(); + pView->SetViewLayout(/*nColumns=*/2, /*bBookMode=*/false); + calcLayout(); + + xmlDocPtr pXmlDoc = parseLayoutDump(); + assertXPath(pXmlDoc, "//page", 2); + sal_uInt32 nPage1Left = getXPath(pXmlDoc, "//page[1]/infos/bounds", "left").toUInt32(); + sal_uInt32 nPage2Left = getXPath(pXmlDoc, "//page[2]/infos/bounds", "left").toUInt32(); + // Make sure that page 2 is on the right hand side of page 1, not below it. + CPPUNIT_ASSERT_GREATER(nPage1Left, nPage2Left); + + // Insert a new paragaph at the start of the document. + SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell(); + pWrtShell->SttDoc(); + pWrtShell->SplitNode(); + discardDumpedLayout(); + pXmlDoc = parseLayoutDump(); + + // Make sure that Table2:C5 and Table2:D5 has its section frame inside the cell frame. + sal_uInt32 nCell3Top = getXPath(pXmlDoc, "//page[2]/body/tab/row/cell/tab/row[4]/cell[3]/infos/bounds", "top").toUInt32(); + sal_uInt32 nSection3Top = getXPath(pXmlDoc, "//page[2]/body/tab/row/cell/tab/row[4]/cell[3]/section/infos/bounds", "top").toUInt32(); + CPPUNIT_ASSERT_GREATER(nCell3Top, nSection3Top); + sal_uInt32 nCell4Top = getXPath(pXmlDoc, "//page[2]/body/tab/row/cell/tab/row[4]/cell[4]/infos/bounds", "top").toUInt32(); + sal_uInt32 nSection4Top = getXPath(pXmlDoc, "//page[2]/body/tab/row/cell/tab/row[4]/cell[4]/section/infos/bounds", "top").toUInt32(); + CPPUNIT_ASSERT_GREATER(nCell4Top, nSection4Top); + // Also check if the two cells in the same row have the same top position. + // This was 4818, expected only 1672. + CPPUNIT_ASSERT_EQUAL(nCell3Top, nCell4Top); +} + void SwUiWriterTest::testTableInSectionInTable() { // The document has a table, containing a section, containing a nested diff --git a/sw/source/core/layout/sectfrm.cxx b/sw/source/core/layout/sectfrm.cxx index 3dd775fd87a8..ff091c12327b 100644 --- a/sw/source/core/layout/sectfrm.cxx +++ b/sw/source/core/layout/sectfrm.cxx @@ -708,7 +708,7 @@ void SwSectionFrame::MoveContentAndDelete( SwSectionFrame* pDel, bool bSave ) } } -void SwSectionFrame::MakeAll(vcl::RenderContext* /*pRenderContext*/) +void SwSectionFrame::MakeAll(vcl::RenderContext* pRenderContext) { if ( IsJoinLocked() || IsColLocked() || StackHack::IsLocked() || StackHack::Count() > 50 ) return; @@ -775,6 +775,19 @@ void SwSectionFrame::MakeAll(vcl::RenderContext* /*pRenderContext*/) mbValidSize = false; SwLayoutFrame::MakeAll(getRootFrame()->GetCurrShell()->GetOut()); + + if (IsInTab()) + { + // In case the section is in a table, then calculate the lower right + // now. Just setting the valid size flag of the lower to false may not + // be enough, as lcl_RecalcRow() can call + // SwFrame::ValidateThisAndAllLowers(), and then we don't attempt + // calculating the proper position of the lower. + SwFrame* pLower = Lower(); + if (pLower && !pLower->GetValidPosFlag()) + pLower->Calc(pRenderContext); + } + UnlockJoin(); if( m_pSection && IsSuperfluous() ) DelEmpty( false ); diff --git a/sw/source/core/layout/tabfrm.cxx b/sw/source/core/layout/tabfrm.cxx index 7bbaa6ddd127..c840c62649ea 100644 --- a/sw/source/core/layout/tabfrm.cxx +++ b/sw/source/core/layout/tabfrm.cxx @@ -1560,11 +1560,9 @@ static void lcl_RecalcRow( SwRowFrame& rRow, long nBottom ) { if ( ++nLoopControlRuns_2 > nLoopControlMax ) { -#if OSL_DEBUG_LEVEL > 1 - OSL_ENSURE( 0 != nLoopControlStage_2, "LoopControl_2 in lcl_RecalcRow: Stage 1!" ); - OSL_ENSURE( 1 != nLoopControlStage_2, "LoopControl_2 in lcl_RecalcRow: Stage 2!!" ); - OSL_ENSURE( 2 > nLoopControlStage_2, "LoopControl_2 in lcl_RecalcRow: Stage 3!!!" ); -#endif + SAL_WARN_IF(nLoopControlStage_2 == 0, "sw.layout", "LoopControl_2 in lcl_RecalcRow: Stage 1!"); + SAL_WARN_IF(nLoopControlStage_2 == 1, "sw.layout", "LoopControl_2 in lcl_RecalcRow: Stage 2!!"); + SAL_WARN_IF(nLoopControlStage_2 >= 2, "sw.layout", "LoopControl_2 in lcl_RecalcRow: Stage 3!!!"); rRow.ValidateThisAndAllLowers( nLoopControlStage_2++ ); nLoopControlRuns_2 = 0; if( nLoopControlStage_2 > 2 ) @@ -1608,11 +1606,9 @@ static void lcl_RecalcRow( SwRowFrame& rRow, long nBottom ) { if ( ++nLoopControlRuns_1 > nLoopControlMax ) { -#if OSL_DEBUG_LEVEL > 1 - OSL_ENSURE( 0 != nLoopControlStage_1, "LoopControl_1 in lcl_RecalcRow: Stage 1!" ); - OSL_ENSURE( 1 != nLoopControlStage_1, "LoopControl_1 in lcl_RecalcRow: Stage 2!!" ); - OSL_ENSURE( 2 > nLoopControlStage_1, "LoopControl_1 in lcl_RecalcRow: Stage 3!!!" ); -#endif + SAL_WARN_IF(nLoopControlStage_1 == 0, "sw.layout", "LoopControl_1 in lcl_RecalcRow: Stage 1!"); + SAL_WARN_IF(nLoopControlStage_1 == 1, "sw.layout", "LoopControl_1 in lcl_RecalcRow: Stage 2!!"); + SAL_WARN_IF(nLoopControlStage_1 >= 2, "sw.layout", "LoopControl_1 in lcl_RecalcRow: Stage 3!!!"); rRow.ValidateThisAndAllLowers( nLoopControlStage_1++ ); nLoopControlRuns_1 = 0; if( nLoopControlStage_1 > 2 ) -- cgit v1.2.3