sw/qa/core/layout/data/inline-endnote-and-footnote.doc |binary
 sw/qa/core/layout/ftnfrm.cxx                           |   21 +++++++
 sw/source/core/layout/flowfrm.cxx                      |   37 ++++++++++++-
 sw/source/core/layout/ftnfrm.cxx                       |   45 ++++++++++-------
 sw/source/core/text/txtftn.cxx                         |   10 ---
 5 files changed, 83 insertions(+), 30 deletions(-)

New commits:
commit 6885dcd7ec7b82a946d8344bfc27a3e88eecc44a
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Tue May 14 08:28:33 2024 +0200
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Tue May 14 12:08:31 2024 +0200

    tdf#160984 sw continuous endnotes: switch to a section-based layout
    
    The original layout added in commit
    4814e8caa5f06c4fe438dfd7d7315e4a2410ea18 (tdf#124601 sw: add
    ContinuousEndnotes layout compat option, 2019-09-30) puts endnotes to
    the footnote container on the last page, which fixes the page count but
    the endnote position is wrong: should be after the body text, not at the
    bottom of the page.
    
    Now that we can have an endnote section (with one or more section frames
    at a layout level), we have a container that can span over multiple
    pages, is at the end of the document and is inline.
    
    Fix the bad position by:
    
    1) Reverting the layout changes from the old approach, which gives us a
       bad position for the endnote.
    
    2) Creating an endnote section frame on demand in
       SwFootnoteBossFrame::AppendFootnote().
    
    3) Moving part of the endnote to a next page works out of the box, but
       moving part of the endnote to a previous page needs explicit handling
       in SwFlowFrame::MoveBwd(), similar to how SwFrame::GetPrevSctLeaf()
       does this in the simple section case. This needs explicit handling,
       because the body frame of the endnote section is empty, all content goes
       to its endnote container.
    
    Note that this just reimplements the compat flag, but its enablement
    (only for DOC import, only for <= 2 endnotes) stays unchanged for now.
    
    Change-Id: I8b271895aeff378418aed8705fe6b99a69232bd2
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/167616
    Tested-by: Jenkins
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>

diff --git a/sw/qa/core/layout/data/inline-endnote-and-footnote.doc 
b/sw/qa/core/layout/data/inline-endnote-and-footnote.doc
new file mode 100644
index 000000000000..39c5636e1e12
Binary files /dev/null and 
b/sw/qa/core/layout/data/inline-endnote-and-footnote.doc differ
diff --git a/sw/qa/core/layout/ftnfrm.cxx b/sw/qa/core/layout/ftnfrm.cxx
index 4c874202da3f..71fd3fd67150 100644
--- a/sw/qa/core/layout/ftnfrm.cxx
+++ b/sw/qa/core/layout/ftnfrm.cxx
@@ -63,4 +63,25 @@ CPPUNIT_TEST_FIXTURE(Test, testFlySplitFootnoteLayout)
     CPPUNIT_ASSERT(pPage->FindFootnoteCont());
 }
 
+CPPUNIT_TEST_FIXTURE(Test, testInlineEndnoteAndFootnote)
+{
+    // Given a DOC file with an endnote and then a footnote:
+    createSwDoc("inline-endnote-and-footnote.doc");
+
+    // When laying out that document:
+    xmlDocUniquePtr pXmlDoc = parseLayoutDump();
+
+    // Then make sure the footnote is below the endnote:
+    // Without the accompanying fix in place, this test would have failed with:
+    // - xpath should match exactly 1 node
+    // i.e. the endnote was also in the footnote container, not at the end of 
the body text.
+    sal_Int32 nEndnoteTop
+        = 
parseDump("/root/page/body/section/column/ftncont/ftn/infos/bounds"_ostr, 
"top"_ostr)
+              .toInt32();
+    sal_Int32 nFootnoteTop
+        = parseDump("/root/page/ftncont/ftn/infos/bounds"_ostr, 
"top"_ostr).toInt32();
+    // Endnote at the end of body text, footnote at page bottom.
+    CPPUNIT_ASSERT_LESS(nFootnoteTop, nEndnoteTop);
+}
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/layout/flowfrm.cxx 
b/sw/source/core/layout/flowfrm.cxx
index 37fd20b323d7..1cb5cf7bf47a 100644
--- a/sw/source/core/layout/flowfrm.cxx
+++ b/sw/source/core/layout/flowfrm.cxx
@@ -2257,18 +2257,47 @@ bool SwFlowFrame::MoveBwd( bool &rbReformat )
         const bool bEndnote = pFootnote->GetAttr()->GetFootnote().IsEndNote();
         const IDocumentSettingAccess& rSettings
             = pFootnote->GetAttrSet()->GetDoc()->getIDocumentSettingAccess();
-        if( bEndnote && pFootnote->IsInSct() )
+        bool bContEndnotes = 
rSettings.get(DocumentSettingId::CONTINUOUS_ENDNOTES);
+        if( bEndnote && pFootnote->IsInSct() && !bContEndnotes)
         {
             SwSectionFrame* pSect = pFootnote->FindSctFrame();
             if( pSect->IsEndnAtEnd() )
                 // Endnotes at the end of the section.
                 pRef = pSect->FindLastContent( SwFindMode::LastCnt );
         }
-        else if (bEndnote && 
rSettings.get(DocumentSettingId::CONTINUOUS_ENDNOTES))
+        else if (bEndnote && bContEndnotes)
         {
             // Endnotes at the end of the document.
-            SwPageFrame* pPage = m_rThis.getRootFrame()->GetLastPage();
-            pRef = pPage->FindLastBodyContent();
+            SwSectionFrame* pSect = pFootnote->FindSctFrame();
+            if (!pSect->GetPrev() && !pSect->FindMaster())
+            {
+                // The section is at the top of the page, and is not a follow 
of a master section.
+                // See if there is a previous body frame.
+                SwLayoutFrame* pPrev = pSect->GetPrevLayoutLeaf();
+                if (pPrev && pPrev->IsBodyFrame())
+                {
+                    // There is, then see if that's on a different page.
+                    SwPageFrame* pSectPage = pSect->FindPageFrame();
+                    SwPageFrame* pPage = pPrev->FindPageFrame();
+                    if (pPage != pSectPage)
+                    {
+                        // It is, then create a new section frame at the end 
of that previous body
+                        // frame.
+                        auto pNew = new SwSectionFrame(*pSect, 
/*bMaster=*/true);
+                        pNew->InsertBehind(pPage->FindBodyCont(), 
pPage->FindLastBodyContent());
+                        pNew->Init();
+                        SwFrame* pLower = pNew->GetLower();
+                        if (pLower->IsColumnFrame())
+                        {
+                            pRef = pLower;
+                        }
+                    }
+                }
+            }
+            else
+            {
+                pRef = pFootnote->FindFootnoteBossFrame();
+            }
         }
         if( !pRef )
             // Endnotes on a separate page.
diff --git a/sw/source/core/layout/ftnfrm.cxx b/sw/source/core/layout/ftnfrm.cxx
index 0fd430ccc31d..e03519ed3040 100644
--- a/sw/source/core/layout/ftnfrm.cxx
+++ b/sw/source/core/layout/ftnfrm.cxx
@@ -768,26 +768,18 @@ SwLayoutFrame *SwFrame::GetPrevFootnoteLeaf( MakePageType 
eMakeFootnote )
         SwFrame* pTmpRef = nullptr;
         const IDocumentSettingAccess& rSettings
             = pFootnote->GetAttrSet()->GetDoc()->getIDocumentSettingAccess();
-        if( bEndn && pFootnote->IsInSct() )
+        bool bContEndnotes = 
rSettings.get(DocumentSettingId::CONTINUOUS_ENDNOTES);
+        if( bEndn && pFootnote->IsInSct() && !bContEndnotes)
         {
             SwSectionFrame* pSect = pFootnote->FindSctFrame();
             if( pSect->IsEndnAtEnd() )
                 // Endnotes at the end of the section.
                 pTmpRef = pSect->FindLastContent( SwFindMode::LastCnt );
         }
-        else if (bEndn && 
rSettings.get(DocumentSettingId::CONTINUOUS_ENDNOTES))
+        else if (bEndn && bContEndnotes)
         {
             // Endnotes at the end of the document.
-            SwPageFrame* pPage = getRootFrame()->GetLastPage();
-            assert(pPage);
-            SwFrame* pPrevPage = pPage->GetPrev();
-            if (pPrevPage)
-            {
-                // Have a last but one page, use that since we try to get a 
preceding frame.
-                assert(pPrevPage->IsPageFrame());
-                pPage = static_cast<SwPageFrame*>(pPrevPage);
-            }
-            pTmpRef = pPage->FindLastBodyContent();
+            pTmpRef = pFootnote->FindFootnoteBossFrame();
         }
         if( !pTmpRef )
             // Endnotes on a separate page.
@@ -1581,8 +1573,28 @@ void SwFootnoteBossFrame::AppendFootnote( SwContentFrame 
*pRef, SwTextFootnote *
         else if (rSettings.get(DocumentSettingId::CONTINUOUS_ENDNOTES))
         {
             // Endnotes at the end of the document.
-            pBoss = getRootFrame()->GetLastPage();
-            pPage = pBoss->FindPageFrame();
+            // Find the first page that hosts an endnote section.
+            SwSectionFrame* pEndnoteSection = pPage->GetEndNoteSection();
+            while (pPage->GetNext() && !pEndnoteSection)
+            {
+                pPage = pPage->GetNext()->DynCastPageFrame();
+                pEndnoteSection = pPage->GetEndNoteSection();
+            }
+            // If there are no endnotes sections yet, create one at the end of 
the document.
+            if (!pEndnoteSection)
+            {
+                SwSection* pSwSection = 
pDoc->GetEndNoteInfo().GetSwSection(*pDoc);
+                pEndnoteSection = new SwSectionFrame(*pSwSection, pPage);
+                pEndnoteSection->InsertBehind(pPage->FindBodyCont(), 
pPage->FindLastBodyContent());
+                pEndnoteSection->Init();
+                pEndnoteSection->SetEndNoteSection(true);
+            }
+
+            SwFrame* pColumnFrame = pEndnoteSection->GetLower();
+            if (pColumnFrame->IsColumnFrame())
+            {
+                pBoss = static_cast<SwColumnFrame*>(pColumnFrame);
+            }
         }
         else
         {
@@ -1931,10 +1943,7 @@ void SwFootnoteBossFrame::CollectFootnotes_( const 
SwContentFrame*   _pRef,
         bool bCollectFoundFootnote = false;
         // Ignore endnotes which are on a separate endnote page.
         bool bEndNote = _pFootnote->GetAttr()->GetFootnote().IsEndNote();
-        const IDocumentSettingAccess& rSettings
-            = _pFootnote->GetAttrSet()->GetDoc()->getIDocumentSettingAccess();
-        bool bContinuousEndnotes = 
rSettings.get(DocumentSettingId::CONTINUOUS_ENDNOTES);
-        if (_pFootnote->GetRef() == _pRef && (!bEndNote || 
bContinuousEndnotes))
+        if (_pFootnote->GetRef() == _pRef && !bEndNote)
         {
             if (_pRefFootnoteBossFrame)
             {
diff --git a/sw/source/core/text/txtftn.cxx b/sw/source/core/text/txtftn.cxx
index 35bb31f76a4c..bb21b6ab0f29 100644
--- a/sw/source/core/text/txtftn.cxx
+++ b/sw/source/core/text/txtftn.cxx
@@ -598,8 +598,6 @@ void SwTextFrame::ConnectFootnote( SwTextFootnote 
*pFootnote, const SwTwips nDea
     mbFootnote = true;
     mbInFootnoteConnect = true; // Just reset!
     // See if pFootnote is an endnote on a separate endnote page.
-    const IDocumentSettingAccess& rSettings = 
GetDoc().getIDocumentSettingAccess();
-    const bool bContinuousEndnotes = 
rSettings.get(DocumentSettingId::CONTINUOUS_ENDNOTES);
     const bool bEnd = pFootnote->GetFootnote().IsEndNote();
 
     // We want to store this value, because it is needed as a fallback
@@ -630,15 +628,11 @@ void SwTextFrame::ConnectFootnote( SwTextFootnote 
*pFootnote, const SwTwips nDea
 
     if( bDocEnd )
     {
-        if ((pSect || bContinuousEndnotes) && pSrcFrame)
+        if (pSect && pSrcFrame)
         {
             SwFootnoteFrame *pFootnoteFrame = 
SwFootnoteBossFrame::FindFootnote( pSrcFrame, pFootnote );
-            if (pFootnoteFrame && (pFootnoteFrame->IsInSct() || 
bContinuousEndnotes))
+            if (pFootnoteFrame && pFootnoteFrame->IsInSct())
             {
-                // We either have a foot/endnote that goes to the end of the 
section or are in Word
-                // compatibility mode where endnotes go to the end of the 
document.  Handle both
-                // cases by removing the footnote here, then later appending 
them to the correct
-                // last page of the document or section.
                 pBoss->RemoveFootnote( pSrcFrame, pFootnote );
                 pSrcFrame = nullptr;
             }

Reply via email to