sw/qa/core/text/data/floattable-anchor-height.docx |binary
 sw/qa/core/text/porrst.cxx                         |   37 +++++++++++++++++++++
 sw/source/core/text/porrst.cxx                     |   26 +++++++++++++-
 3 files changed, 61 insertions(+), 2 deletions(-)

New commits:
commit 591f03b8d8bc386eb9b8522a53e83780a99598c9
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Tue Oct 3 12:08:36 2023 +0200
Commit:     Caolán McNamara <caolan.mcnam...@collabora.com>
CommitDate: Wed Oct 4 12:09:31 2023 +0200

    tdf#126449 sw floattable: fix too small height of non-last anchors
    
    The bugdoc had an outer inline table, a middle inline table and an inner
    floating table. The floating table is expected to be on pages 2, 3 and
    4; actually it was only on page 2 and 3.
    
    This happened because the fly frame that should be on page 4 was on page
    3, leading to overlapping text. And that bad fly position seems to
    happen because the anchor frames just have a 1 line height (~269 twips
    instead of the fly height).
    
    Fix this similar to how "first paragraph only" wrapping works: increase
    the (anchor) text frame height, even if the contained lines would not
    require that amount of height.
    
    With this, finally the DOCX version of the bugdoc lays out reasonable
    (all 5 pages).
    
    (cherry picked from commit 695390b08799af34b393c81c834d615bea330d89)
    
    Change-Id: Ib08bf34be61eb2b4d8656887f83ac7fd17e3b252
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/157553
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com>
    Reviewed-by: Caolán McNamara <caolan.mcnam...@collabora.com>

diff --git a/sw/qa/core/text/data/floattable-anchor-height.docx 
b/sw/qa/core/text/data/floattable-anchor-height.docx
new file mode 100644
index 000000000000..3052f0daef73
Binary files /dev/null and b/sw/qa/core/text/data/floattable-anchor-height.docx 
differ
diff --git a/sw/qa/core/text/porrst.cxx b/sw/qa/core/text/porrst.cxx
index 1c343dc0d9f2..f2e14e7f7f31 100644
--- a/sw/qa/core/text/porrst.cxx
+++ b/sw/qa/core/text/porrst.cxx
@@ -18,6 +18,7 @@
 #include <pagefrm.hxx>
 #include <rootfrm.hxx>
 #include <txtfrm.hxx>
+#include <sortedobjs.hxx>
 
 namespace
 {
@@ -52,6 +53,42 @@ CPPUNIT_TEST_FIXTURE(Test, testFloattableLeftoverParaPortion)
     // also had some (duplicated) anchor text.
     CPPUNIT_ASSERT(!pPara2->GetPara());
 }
+
+CPPUNIT_TEST_FIXTURE(Test, testFloattableAnchorHeight)
+{
+#if !defined(MACOSX) // FIXME fails on macOS
+    // Given 3 tables, innermost table on pages 2-3-4:
+    createSwDoc("floattable-anchor-height.docx");
+
+    // When laying out the document:
+    calcLayout();
+
+    // Then make sure the flys are on the expected pages:
+    SwDoc* pDoc = getSwDoc();
+    SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
+    auto pPage1 = pLayout->Lower()->DynCastPageFrame();
+    CPPUNIT_ASSERT(pPage1);
+    CPPUNIT_ASSERT(!pPage1->GetSortedObjs());
+    auto pPage2 = pPage1->GetNext()->DynCastPageFrame();
+    CPPUNIT_ASSERT(pPage2);
+    SwSortedObjs* pPage2Objs = pPage2->GetSortedObjs();
+    CPPUNIT_ASSERT(pPage2Objs);
+    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), pPage2Objs->size());
+    auto pPage3 = pPage2->GetNext()->DynCastPageFrame();
+    CPPUNIT_ASSERT(pPage3);
+    SwSortedObjs* pPage3Objs = pPage3->GetSortedObjs();
+    CPPUNIT_ASSERT(pPage3Objs);
+    // Without the accompanying fix in place, this test would have failed with:
+    // - Expected: 1
+    // - Actual  : 2
+    // i.e. page 3 also had the fly frame of page 4 as well.
+    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), pPage3Objs->size());
+    auto pPage4 = pPage3->GetNext()->DynCastPageFrame();
+    SwSortedObjs* pPage4Objs = pPage4->GetSortedObjs();
+    CPPUNIT_ASSERT(pPage4Objs);
+    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), pPage4Objs->size());
+#endif
+}
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/text/porrst.cxx b/sw/source/core/text/porrst.cxx
index 9c04fc0458c6..4d43ad28995a 100644
--- a/sw/source/core/text/porrst.cxx
+++ b/sw/source/core/text/porrst.cxx
@@ -51,6 +51,8 @@
 #include <crsrsh.hxx>
 #include <swtypes.hxx>
 #include <strings.hrc>
+#include <flyfrms.hxx>
+#include <bodyfrm.hxx>
 
 SwTmpEndPortion::SwTmpEndPortion( const SwLinePortion &rPortion,
                 const FontLineStyle eUL,
@@ -412,7 +414,8 @@ bool SwTextFrame::FormatEmpty()
     // sw_redlinehide: just disable FormatEmpty optimisation for now
     // Split fly frames: non-last parts of the anchor want this optimization 
to clear the old
     // content.
-    bool bHasNonLastSplitFlyDrawObj = HasNonLastSplitFlyDrawObj();
+    SwFlyAtContentFrame* pNonLastSplitFlyDrawObj = HasNonLastSplitFlyDrawObj();
+    bool bHasNonLastSplitFlyDrawObj = pNonLastSplitFlyDrawObj != nullptr;
     if ((HasFollow() && !bHasNonLastSplitFlyDrawObj) || GetMergedPara() || 
(GetTextNodeFirst()->GetpSwpHints() && !bHasNonLastSplitFlyDrawObj) ||
         nullptr != GetTextNodeForParaProps()->GetNumRule() ||
         GetTextNodeFirst()->HasHiddenCharAttribute(true) ||
@@ -466,7 +469,26 @@ bool SwTextFrame::FormatEmpty()
     }
 
     SwRectFnSet aRectFnSet(this);
-    const SwTwips nChg = nHeight - aRectFnSet.GetHeight(getFramePrintArea());
+    SwTwips nChg = nHeight - aRectFnSet.GetHeight(getFramePrintArea());
+    const SwBodyFrame* pBody = FindBodyFrame();
+    if (pNonLastSplitFlyDrawObj && pBody)
+    {
+        // See if we need to increase the text frame height due to split flys. 
This is necessary for
+        // anchors of inner floating tables, where moving to a next page moves 
indirectly, so we
+        // want a correct text frame height.
+        SwTwips nFrameBottom = aRectFnSet.GetBottom(getFrameArea()) + nChg;
+        SwTwips nFlyBottom = 
aRectFnSet.GetBottom(pNonLastSplitFlyDrawObj->getFrameArea());
+        SwTwips nBodyBottom = aRectFnSet.GetBottom(pBody->getFrameArea());
+        if (nFlyBottom > nBodyBottom)
+        {
+            // This is the legacy case where flys may overlap with footer 
frames.
+            nFlyBottom = nBodyBottom;
+        }
+        if (pNonLastSplitFlyDrawObj->isFrameAreaPositionValid() && nFlyBottom 
> nFrameBottom)
+        {
+            nChg += (nFlyBottom - nFrameBottom);
+        }
+    }
 
     if( !nChg )
         SetUndersized( false );

Reply via email to