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 81a108770233825557c2dae5776d7417be017fb8
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Thu Jun 8 08:09:12 2023 +0200
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Thu Jun 8 12:55:01 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.
    
    Change-Id: I6e9693847beaec5d9bbf9f8a5699795579c3ff71
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/152726
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>
    Tested-by: Jenkins

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 f321a01c3aa5..30a12adc7af7 100644
--- a/sw/qa/core/text/text.cxx
+++ b/sw/qa/core/text/text.cxx
@@ -42,6 +42,7 @@
 #include <ndtxt.hxx>
 #include <txatbase.hxx>
 #include <textcontentcontrol.hxx>
+#include <pagefrm.hxx>
 
 /// Covers sw/source/core/text/ fixes.
 class SwCoreTextTest : public SwModelTestBase
@@ -1281,6 +1282,33 @@ CPPUNIT_TEST_FIXTURE(SwCoreTextTest, 
testTdf41652NBSPWidth)
                            nSectionAfterNBSPX_optionEnabled_justified);
 }
 
+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 d58b97e9d3e4..40cc0ef0bfac 100644
--- a/sw/source/core/inc/txtfrm.hxx
+++ b/sw/source/core/inc/txtfrm.hxx
@@ -528,6 +528,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 bc0231e67307..6b1cccc647b5 100644
--- a/sw/source/core/layout/frmtool.cxx
+++ b/sw/source/core/layout/frmtool.cxx
@@ -3357,8 +3357,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 d5928c3e77e1..d3fa1b71318f 100644
--- a/sw/source/core/text/itrform2.cxx
+++ b/sw/source/core/text/itrform2.cxx
@@ -2725,6 +2725,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 99ef21dd684c..37ad6edd9eff 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>
@@ -2776,6 +2778,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 cb5105763e73..c080a42248a8 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