sw/qa/core/layout/calcmove.cxx | 6 - sw/qa/extras/ooxmlexport/data/tdf165047_consolidatedTopMargin.docx |binary sw/qa/extras/ooxmlexport/ooxmlexport22.cxx | 18 +++++ sw/source/core/layout/flowfrm.cxx | 33 ++++++++++ 4 files changed, 54 insertions(+), 3 deletions(-)
New commits: commit 395c4f07a61bf607f3283d7a75be93c95a3571d7 Author: Justin Luth <justin.l...@collabora.com> AuthorDate: Wed Apr 2 13:14:16 2025 -0400 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Thu Apr 3 09:00:10 2025 +0200 tdf#165047 sw mso-compat layout: always consolidate top margin This improves 25.8 commit ae7900dd42a65aaf60df6b21b9ad511496b209d9 tdf#164095 sw: fix missing top margin on paragraph after changing page style which was backported to 24.8.5. The problem is that you can't just simply apply the top margin. Even though it may be across a page break, or even in a different section, the already-applied, previous paragraph's bottom margin needs to be "removed" from this paragraph's top margin. make CppunitTest_sw_ooxmlexport22 \ CPPUNIT_TEST_NAME=testTdf165047_consolidatedTopMargin Change-Id: I1ca5a6173cc5ae5a06adaf38a3292f556a81a48d Reviewed-on: https://gerrit.libreoffice.org/c/core/+/183619 Tested-by: Jenkins Reviewed-by: Justin Luth <jl...@mail.com> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/183649 Reviewed-by: Miklos Vajna <vmik...@collabora.com> diff --git a/sw/qa/core/layout/calcmove.cxx b/sw/qa/core/layout/calcmove.cxx index 893d3fd89915..3606c70eb73e 100644 --- a/sw/qa/core/layout/calcmove.cxx +++ b/sw/qa/core/layout/calcmove.cxx @@ -96,10 +96,10 @@ CPPUNIT_TEST_FIXTURE(Test, testIgnoreTopMarginPageStyleChange) sal_Int32 nParaTopMargin = getXPath(pXmlDoc, "/root/page[3]/body/txt/infos/prtBounds", "top").toInt32(); // Without the accompanying fix in place, this test would have failed with: - // - Expected: 2000 + // - Expected: 1840 // - Actual : 0 - // i.e. the top margin was ignored, which is incorrect. - CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(2000), nParaTopMargin); + // i.e. the top margin (minus the previous bottom margin) was ignored, which is incorrect. + CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(1840), nParaTopMargin); } CPPUNIT_TEST_FIXTURE(Test, testHideWhitespaceGrowingLastPage) diff --git a/sw/qa/extras/ooxmlexport/data/tdf165047_consolidatedTopMargin.docx b/sw/qa/extras/ooxmlexport/data/tdf165047_consolidatedTopMargin.docx new file mode 100644 index 000000000000..7a44a2d14f5f Binary files /dev/null and b/sw/qa/extras/ooxmlexport/data/tdf165047_consolidatedTopMargin.docx differ diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport22.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport22.cxx index 34408dcc958b..e01e03f07028 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport22.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport22.cxx @@ -43,6 +43,24 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf165642_glossaryFootnote) parseExport(u"word/glossary/footnotes.xml"_ustr); } +CPPUNIT_TEST_FIXTURE(Test, testTdf165047_consolidatedTopMargin) +{ + // Given a two page document with a section page break + // which is preceded by a paragraph with a lot of lower spacing + // and followed by a paragraph with even more upper spacing... + loadAndSave("tdf165047_consolidatedTopMargin.docx"); + + // the upper spacing is mostly "absorbed" by the preceding lower spacing, and is barely noticed + CPPUNIT_ASSERT_EQUAL(2, getPages()); + + // When laying out that document: + xmlDocUniquePtr pXmlDoc = parseLayoutDump(); + // the effective top margin should be 60pt - 50pt = 10pt (0.36cm) after the page break + SwTwips nParaTopMargin + = getXPath(pXmlDoc, "/root/page[2]/body/section/infos/prtBounds", "top").toInt32(); + CPPUNIT_ASSERT_EQUAL(static_cast<SwTwips>(200), nParaTopMargin); +} + } // end of anonymous namespace CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/sw/source/core/layout/flowfrm.cxx b/sw/source/core/layout/flowfrm.cxx index a60e51962541..1a82925021ac 100644 --- a/sw/source/core/layout/flowfrm.cxx +++ b/sw/source/core/layout/flowfrm.cxx @@ -1536,6 +1536,37 @@ static bool lcl_getContextualSpacing(const SwFrame* pPrevFrame) return bRet; } +/// Implement top-of-the-page layout anomalies needed to match MS Word +static void lcl_PartiallyCollapseUpper(const SwFrame& rFrame, SwTwips& rUpper) +{ + const SwTextFrame* pTextFrame = rFrame.DynCastTextFrame(); + if (!pTextFrame || !rFrame.IsInDocBody() || rFrame.IsInTab() || rFrame.IsInFly()) + return; + + // re-used existing compat values to identify whether MSO-compatible layout is needed + const IDocumentSettingAccess& rIDSA = pTextFrame->GetDoc().getIDocumentSettingAccess(); + const bool bCompat15 = rIDSA.get(DocumentSettingId::TAB_OVER_SPACING); // MSO 2013+ + const bool bCompat14 = rIDSA.get(DocumentSettingId::TAB_OVER_MARGIN); // <= MSO 2010 + if (!bCompat15 && !bCompat14) + return; + + const SwContentFrame* pPrevPara = pTextFrame->FindPrevCnt(); + while (pPrevPara && pPrevPara->IsHiddenNow()) + pPrevPara = pPrevPara->FindPrevCnt(); + + // Anything related to tables is skipped simply to avoid potential disaster + if (!pPrevPara || pPrevPara->IsInTab()) + return; + + { + // MSO is also hyper-consistent about consolidating + // the lower-space from the previous paragraph + // with the upper spacing of this paragraph + const SwTwips nPrevLowerSpace + = pPrevPara->GetAttrSet()->GetULSpace().GetLower(); + rUpper = std::max<SwTwips>(rUpper - nPrevLowerSpace, 0); + } +} SwTwips SwFlowFrame::CalcUpperSpace( const SwBorderAttrs *pAttrs, const SwFrame* pPr, @@ -1709,6 +1740,8 @@ SwTwips SwFlowFrame::CalcUpperSpace( const SwBorderAttrs *pAttrs, { nUpper = 0; } + else + lcl_PartiallyCollapseUpper(*pOwn, nUpper); // possibly modifies nUpper } }