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();