sw/qa/core/text/data/floattable-overlap.docx |binary
 sw/qa/core/text/text.cxx                     |   28 +++++++++++++++++++++++++++
 sw/source/core/inc/txtfrm.hxx                |    3 ++
 sw/source/core/layout/frmtool.cxx            |   11 ++++++++++
 sw/source/core/text/itrform2.cxx             |   13 ++++++++++++
 sw/source/core/text/porlay.cxx               |   28 +++++++++++++++++++++++++++
 sw/source/core/text/txtfly.cxx               |    6 +++++
 7 files changed, 89 insertions(+)

New commits:
commit b5013320d9da133e4b7b39c0a7589072657f10f0
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Thu Jun 8 08:09:12 2023 +0200
Commit:     Caolán McNamara <caolan.mcnam...@collabora.com>
CommitDate: Tue Jun 13 11:15:26 2023 +0200

    sw floattable, compat mode: handle lower margin of anchor for fly intersect
    
    The bugdoc has 2 floating tables and they were overlapping in Writer,
    but not in Word.
    
    What seems to happen is that the document has a floating table, followed
    by an empty paragraph, and in case that empty paragraph goes above the
    floating table, then we overlap, but if it goes below the floating
    table, then the next paragraph will start below the empty paragraph, so
    no overlap will happen. This is possible in Word, because in "Word 2010"
    compat mode it has 327 twips vertical space above the first floating
    table (set by its positioning attribute), and in case the empty
    paragraph has a font size of 11pt (220 twips) + 200 twips of lower
    margin (inherited from the default paragraph style), then this 420 twips
    of space doesn't fit. Note that for new documents Word ("Word 2013"
    mode) does the same as Writer and ignores the lower spacing when
    intersecting lines with flys.
    
    Fix the problem by introducing a new
    SwTextFrame::GetLowerMarginForFlyIntersect() that gives us the lower
    spacing if 1) this is Word 2010 compat mode 2) this text frame has no
    fly portions / multiple lines yet and 3) this paragraph is empty. Then
    use this function at 3 places where we used to intersect with the
    absolute print area of the frame, and extend these places with the lower
    spacing.
    
    This could be extended in the future for non-empty paragraphs as well,
    but the bugdoc works without that, and the change is invasive enough, so
    better to limit the scope.
    
    (cherry picked from commit 81a108770233825557c2dae5776d7417be017fb8)
    
    Change-Id: I6e9693847beaec5d9bbf9f8a5699795579c3ff71
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/152795
    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-overlap.docx 
b/sw/qa/core/text/data/floattable-overlap.docx
new file mode 100644
index 000000000000..cc0dbd077f00
Binary files /dev/null and b/sw/qa/core/text/data/floattable-overlap.docx differ
diff --git a/sw/qa/core/text/text.cxx b/sw/qa/core/text/text.cxx
index 0ddc9a0885d8..544a17d3b8c0 100644
--- a/sw/qa/core/text/text.cxx
+++ b/sw/qa/core/text/text.cxx
@@ -39,6 +39,7 @@
 #include <ndtxt.hxx>
 #include <txatbase.hxx>
 #include <textcontentcontrol.hxx>
+#include <pagefrm.hxx>
 
 /// Covers sw/source/core/text/ fixes.
 class SwCoreTextTest : public SwModelTestBase
@@ -936,6 +937,33 @@ CPPUNIT_TEST_FIXTURE(SwCoreTextTest, 
testNumberPortionNoformat)
         getXPath(pXmlDoc, "//SwParaPortion/SwLineLayout/SwFieldPortion", 
"font-color"));
 }
 
+CPPUNIT_TEST_FIXTURE(SwCoreTextTest, testFloattableOverlap)
+{
+    // Given a document with 2 floating tables, not overlapping in Word's 
"Word 2010" compat mode,
+    // because the first empty paragraph is below the first floating table:
+    createSwDoc("floattable-overlap.docx");
+
+    // When laying out that document:
+    calcLayout();
+
+    // Then make sure they don't overlap in Writer, either:
+    SwDoc* pDoc = getSwDoc();
+    SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
+    auto pPage1 = dynamic_cast<SwPageFrame*>(pLayout->Lower());
+    CPPUNIT_ASSERT(pPage1);
+    CPPUNIT_ASSERT(pPage1->GetSortedObjs());
+    const SwSortedObjs& rPage1Objs = *pPage1->GetSortedObjs();
+    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), rPage1Objs.size());
+    SwAnchoredObject* pPage1Obj1 = rPage1Objs[0];
+    const SwRect& rRect1 = pPage1Obj1->GetObjRectWithSpaces();
+    SwAnchoredObject* pPage1Obj2 = rPage1Objs[1];
+    const SwRect& rRect2 = pPage1Obj2->GetObjRectWithSpaces();
+    // Without the accompanying fix in place, this test would have failed, the 
empty paragraph,
+    // which is after the floating table in the document model went above the 
floating table in the
+    // layout, which resulted in an overlap.
+    CPPUNIT_ASSERT(!rRect1.Overlaps(rRect2));
+}
+
 CPPUNIT_PLUGIN_IMPLEMENT();
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/inc/txtfrm.hxx b/sw/source/core/inc/txtfrm.hxx
index 942867882626..3c6dae427815 100644
--- a/sw/source/core/inc/txtfrm.hxx
+++ b/sw/source/core/inc/txtfrm.hxx
@@ -523,6 +523,9 @@ public:
     // the offset will be returned.
     SwTwips HangingMargin() const;
 
+    /// Get the amount of lower margin of this frame we need to consider for 
fly portion purposes.
+    SwTwips GetLowerMarginForFlyIntersect() const;
+
     // Locking
     bool IsLocked()      const { return mbLocked;     }
 
diff --git a/sw/source/core/layout/frmtool.cxx 
b/sw/source/core/layout/frmtool.cxx
index f477400aea49..6995ac638674 100644
--- a/sw/source/core/layout/frmtool.cxx
+++ b/sw/source/core/layout/frmtool.cxx
@@ -3342,8 +3342,19 @@ static void lcl_NotifyContent( const SdrObject *pThis, 
SwContentFrame *pCnt,
     if ( !pCnt->IsTextFrame() )
         return;
 
+    auto pTextFrame = static_cast<SwTextFrame*>(pCnt);
     SwRect aCntPrt( pCnt->getFramePrintArea() );
     aCntPrt.Pos() += pCnt->getFrameArea().Pos();
+
+    if (eHint == PrepareHint::FlyFrameArrive)
+    {
+        SwTwips nLower = pTextFrame->GetLowerMarginForFlyIntersect();
+        if (nLower > 0)
+        {
+            aCntPrt.AddBottom(nLower);
+        }
+    }
+
     if ( eHint == PrepareHint::FlyFrameAttributesChanged )
     {
         // #i35640# - use given rectangle <rRect> instead
diff --git a/sw/source/core/text/itrform2.cxx b/sw/source/core/text/itrform2.cxx
index 56d40b88ec25..352ecb8d169a 100644
--- a/sw/source/core/text/itrform2.cxx
+++ b/sw/source/core/text/itrform2.cxx
@@ -2706,6 +2706,19 @@ void SwTextFormatter::CalcFlyWidth( SwTextFormatInfo 
&rInf )
         if( nUpper > 0 && nTop >= nUpper  )
             aLine.SubTop( nUpper );
     }
+
+    if (IsFirstTextLine())
+    {
+        // Check if a compatibility mode requires considering also the lower 
margin of this text
+        // frame, intersections with this additional space should lead to 
shifting the paragraph
+        // marker down.
+        SwTwips nLower = m_pFrame->GetLowerMarginForFlyIntersect();
+        if (nLower > 0)
+        {
+            aLine.AddBottom(nLower);
+        }
+    }
+
     SwRect aLineVert( aLine );
     if ( m_pFrame->IsRightToLeft() )
         m_pFrame->SwitchLTRtoRTL( aLineVert );
diff --git a/sw/source/core/text/porlay.cxx b/sw/source/core/text/porlay.cxx
index 5dda6c2ac0e2..95b7ab141830 100644
--- a/sw/source/core/text/porlay.cxx
+++ b/sw/source/core/text/porlay.cxx
@@ -64,7 +64,9 @@
 #include <docsh.hxx>
 #include <unobookmark.hxx>
 #include <unocrsrhelper.hxx>
+#include <frmatr.hxx>
 #include <vcl/kernarray.hxx>
+#include <editeng/ulspitem.hxx>
 #include <com/sun/star/rdf/Statement.hpp>
 #include <com/sun/star/rdf/URI.hpp>
 #include <com/sun/star/rdf/URIs.hpp>
@@ -2742,6 +2744,32 @@ SwTwips SwTextFrame::HangingMargin() const
     return nRet;
 }
 
+SwTwips SwTextFrame::GetLowerMarginForFlyIntersect() const
+{
+    const IDocumentSettingAccess& rIDSA = GetDoc().getIDocumentSettingAccess();
+    if (!rIDSA.get(DocumentSettingId::TAB_OVER_MARGIN))
+    {
+        // Word >= 2013 style or Writer style: lower margin is ignored when 
determining the text
+        // frame height.
+        return 0;
+    }
+
+    const SwAttrSet* pAttrSet = GetTextNodeForParaProps()->GetpSwAttrSet();
+    if (!pAttrSet)
+    {
+        return 0;
+    }
+
+    // If it has multiple lines, then probably it already has the needed fly 
portion.
+    // Limit this to empty paragraphs for now.
+    if ((GetPara() && GetPara()->GetNext()) || !GetText().isEmpty())
+    {
+        return 0;
+    }
+
+    return pAttrSet->GetULSpace().GetLower();
+}
+
 void SwScriptInfo::selectHiddenTextProperty(const SwTextNode& rNode,
     MultiSelection & rHiddenMulti,
     std::vector<std::pair<sw::mark::IBookmark const*, MarkKind>> *const 
pBookmarks)
diff --git a/sw/source/core/text/txtfly.cxx b/sw/source/core/text/txtfly.cxx
index 2c7f5aeadb4f..64b8991875ab 100644
--- a/sw/source/core/text/txtfly.cxx
+++ b/sw/source/core/text/txtfly.cxx
@@ -414,6 +414,12 @@ bool SwTextFly::IsAnyObj( const SwRect &rRect ) const
     {
         aRect = SwRect(m_pCurrFrame->getFrameArea().Pos() + 
m_pCurrFrame->getFramePrintArea().Pos(),
                         m_pCurrFrame->getFramePrintArea().SSize());
+
+        SwTwips nLower = m_pCurrFrame->GetLowerMarginForFlyIntersect();
+        if (nLower > 0)
+        {
+            aRect.AddBottom(nLower);
+        }
     }
 
     const SwSortedObjs *pSorted = m_pPage->GetSortedObjs();

Reply via email to