sw/qa/extras/layout/data/tox-update-wrong-pages.odt |binary
 sw/qa/extras/layout/layout.cxx                      |   34 ++++++++++++++++++++
 sw/source/core/inc/frmtool.hxx                      |    1 
 sw/source/core/layout/flowfrm.cxx                   |   20 +++++++++++
 sw/source/core/layout/sectfrm.cxx                   |    3 +
 5 files changed, 57 insertions(+), 1 deletion(-)

New commits:
commit 425a252c3cc5e5a79a533965026dd4af6b8df739
Author:     Michael Stahl <michael.st...@allotropia.de>
AuthorDate: Fri May 12 17:45:45 2023 +0200
Commit:     Thorsten Behrens <thorsten.behr...@allotropia.de>
CommitDate: Tue Jun 27 11:28:49 2023 +0200

    tdf#155324 sw: layout: try not to MoveFwd onto a page created by page break
    
    There is a ToX that is updated; it has about 4 pages worth of entries.
    
    When the old entries are deleted, 2 of the pages become empty, and since
    commit b9ef71476fd70bc13f50ebe80390e0730d1b7afb these pages are deleted.
    
    While layouting the new entries, these are moved onto the page following
    the ToX, which starts with a page break and contains lots of footnotes.
    
    Now the footnotes reduce the space on the page available for the ToX
    entries, and thus after CalcLayout() there are 5 ToX pages instead of 4.
    
    Then the page numbers are inserted into the entries, and another layout
    action deletes one of the ToX pages; now all the page numbers are too
    large by 1.
    
    Some ideas to fix this:
    1) ignore a footnote when formatting a frame that is before the
       footnote anchor frame; similar to commit
       c79bf7865bff4e88cc201357370d8faeef8e6ad9
    2) invalidate the last content on the page when moving forward the
       footnote container, similar to commit
       eb85de8e6b61fb3fcb6c03ae0145f7fe5478bccf; this doesn't look easy to
       do because as it turns out the footnote container is moved in
       SwLayoutFrame::Cut() 5 function calls inside MoveFwd() while the frame
       on which MoveFwd() is called is still on the page, so would probably
       somehow need to be detected in MoveFwd() itself?
    3) don't move frames forward onto a page that was created by a page
       break - instead create a new frame.
    
    Let's try 3) for now, only in SwFrame::GetNextSctLeaf().
    
    (regression from commit b9ef71476fd70bc13f50ebe80390e0730d1b7afb)
    
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/151711
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>
    (cherry picked from commit 325fe7ab507fd8f2ca17a3db32181edf30169525)
    
    tdf#155324 sw: add unit test
    
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/151876
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>
    (cherry picked from commit 247738a9afeeb2f0644fa0307b7023fe115fae83)
    
    Change-Id: I641f586799a5ddb4e2a6ff8e9de784e422ecc214
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/151889
    Tested-by: Jenkins
    Reviewed-by: Thorsten Behrens <thorsten.behr...@allotropia.de>

diff --git a/sw/qa/extras/layout/data/tox-update-wrong-pages.odt 
b/sw/qa/extras/layout/data/tox-update-wrong-pages.odt
new file mode 100644
index 000000000000..40ceb7ac4bd2
Binary files /dev/null and 
b/sw/qa/extras/layout/data/tox-update-wrong-pages.odt differ
diff --git a/sw/qa/extras/layout/layout.cxx b/sw/qa/extras/layout/layout.cxx
index b4101e9f033e..59db7359bafe 100644
--- a/sw/qa/extras/layout/layout.cxx
+++ b/sw/qa/extras/layout/layout.cxx
@@ -5092,6 +5092,40 @@ CPPUNIT_TEST_FIXTURE(SwLayoutWriter, 
testTdf54465_ColumnsWithFootnoteDoNotOccupy
     assertXPath(pXmlDoc, "/root/page", 1);
 }
 
+CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf155324)
+{
+    createSwDoc("tox-update-wrong-pages.odt");
+
+    dispatchCommand(mxComponent, ".uno:UpdateAllIndexes", {});
+
+    xmlDocUniquePtr pXmlDoc = parseLayoutDump();
+
+    // the problem was that the first entry was on page 7, 2nd on page 9 etc.
+    assertXPath(pXmlDoc,
+                
"/root/page[1]/body/section[2]/txt[1]/SwParaPortion/SwLineLayout/SwLinePortion[1]",
+                "portion", "Foo");
+    assertXPath(pXmlDoc,
+                
"/root/page[1]/body/section[2]/txt[1]/SwParaPortion/SwLineLayout/SwLinePortion[2]",
+                "portion", "5");
+    assertXPath(pXmlDoc,
+                
"/root/page[1]/body/section[2]/txt[2]/SwParaPortion/SwLineLayout/SwLinePortion[1]",
+                "portion", "bar");
+    assertXPath(pXmlDoc,
+                
"/root/page[1]/body/section[2]/txt[2]/SwParaPortion/SwLineLayout/SwLinePortion[2]",
+                "portion", "7");
+    assertXPath(pXmlDoc,
+                
"/root/page[1]/body/section[2]/txt[3]/SwParaPortion/SwLineLayout/SwLinePortion[1]",
+                "portion", "Three");
+    assertXPath(pXmlDoc,
+                
"/root/page[1]/body/section[2]/txt[3]/SwParaPortion/SwLineLayout/SwLinePortion[2]",
+                "portion", "7");
+
+    // check first content page has the footnotes
+    assertXPath(pXmlDoc, 
"/root/page[5]/body/txt[1]/SwParaPortion/SwLineLayout", "portion", "Foo");
+    assertXPath(pXmlDoc, "/root/page[4]/ftncont", 0);
+    assertXPath(pXmlDoc, "/root/page[5]/ftncont/ftn", 5);
+}
+
 CPPUNIT_PLUGIN_IMPLEMENT();
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/inc/frmtool.hxx b/sw/source/core/inc/frmtool.hxx
index 0aaa4d2c05c3..5cabab690b61 100644
--- a/sw/source/core/inc/frmtool.hxx
+++ b/sw/source/core/inc/frmtool.hxx
@@ -158,6 +158,7 @@ SwTwips CalcRowRstHeight( SwLayoutFrame *pRow );
 tools::Long CalcHeightWithFlys( const SwFrame *pFrame );
 
 namespace sw {
+    bool HasPageBreakBefore(SwPageFrame const& rPage);
     bool IsRightPageByNumber(SwRootFrame const& rLayout, sal_uInt16 nPageNum);
     class FlyCreationSuppressor
     {
diff --git a/sw/source/core/layout/flowfrm.cxx 
b/sw/source/core/layout/flowfrm.cxx
index 370ad84b88ff..1b9ecf1cf03c 100644
--- a/sw/source/core/layout/flowfrm.cxx
+++ b/sw/source/core/layout/flowfrm.cxx
@@ -880,6 +880,26 @@ SwLayoutFrame *SwFrame::GetLeaf( MakePageType eMakePage, 
bool bFwd )
     return bFwd ? GetNextLeaf( eMakePage ) : GetPrevLeaf();
 }
 
+namespace sw {
+
+bool HasPageBreakBefore(SwPageFrame const& rPage)
+{
+    SwFrame const* pFlow(rPage.FindFirstBodyContent());
+    if (!pFlow)
+    {
+        return false;
+    }
+    while (pFlow->GetUpper()->IsInTab())
+    {
+        pFlow = pFlow->GetUpper()->FindTabFrame();
+    }
+    return pFlow->GetPageDescItem().GetPageDesc()
+        || pFlow->GetBreakItem().GetBreak() == SvxBreak::PageBefore
+        || pFlow->GetBreakItem().GetBreak() == SvxBreak::PageBoth;
+};
+
+} // namespace sw
+
 bool SwFrame::WrongPageDesc( SwPageFrame* pNew )
 {
     // Now it's getting a bit complicated:
diff --git a/sw/source/core/layout/sectfrm.cxx 
b/sw/source/core/layout/sectfrm.cxx
index b9249de5c340..b6890aec917b 100644
--- a/sw/source/core/layout/sectfrm.cxx
+++ b/sw/source/core/layout/sectfrm.cxx
@@ -1756,7 +1756,8 @@ SwLayoutFrame *SwFrame::GetNextSctLeaf( MakePageType 
eMakePage )
             // case pLayLeaf points to our section's cell's follow, which is
             // fine to be on the same page. New page creation is handled when
             // creating / moving the cell frame.
-            if( WrongPageDesc( pNxtPg ) && !bLayLeafTableAllowed )
+            // It doesn't make sense to move to a page that starts with break?
+            if ((WrongPageDesc(pNxtPg) || HasPageBreakBefore(*pNxtPg)) && 
!bLayLeafTableAllowed)
             {
                 if( bWrongPage )
                     break; // there's a column between me and my right page

Reply via email to