sw/qa/extras/ooxmlexport/data/tdf166510_sectPr_bottomSpacing.docx |binary sw/qa/extras/ooxmlexport/ooxmlexport25.cxx | 11 ++++ sw/source/writerfilter/dmapper/DomainMapper.cxx | 3 + sw/source/writerfilter/dmapper/DomainMapper_Impl.cxx | 23 ++++++++++ sw/source/writerfilter/dmapper/DomainMapper_Impl.hxx | 3 + 5 files changed, 40 insertions(+)
New commits: commit 23e28e35d18bf9ee0d9a9f72117480971ca437ce Author: Justin Luth <jl...@mail.com> AuthorDate: Fri May 16 11:43:06 2025 -0400 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Mon May 19 08:49:23 2025 +0200 tdf#166510 writerfilter: move empty sectPr bottom margin to prev para This is follow-up to my 25.2.3 commit for tdf#165047: sw mso-compat layout: always consolidate top margin The problem here was not the consolidation itself, but the fact that the paragraph after the section page break needs to consolidate based on the below spacing of the sectPr paragraph and we simply deleted that info along with the empty sectPr. The result was that consolidation was working with the wrong number. Since the bottom margin of the previous paragraph has no impact on the empty sectPr, we can simply transfer the sectPr's spacing to the previous paragraph, which of course now becomes the last paragraph before the page break. Slightly unexpected were some examples where no spacing was identified for the sectPr context. The unit test includes this complication... make CppunitTest_sw_ooxmlexport25 \ CPPUNIT_TEST_NAME=testTdf166510_sectPr_bottomSpacing Change-Id: I9bcae239480035b02653ec93a37f6bf05d135d8f Reviewed-on: https://gerrit.libreoffice.org/c/core/+/185424 Reviewed-by: Justin Luth <jl...@mail.com> Tested-by: Jenkins (cherry picked from commit 5ff1fd13f1879105ecc0541c55f30cea32ae54f4) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/185430 Reviewed-by: Miklos Vajna <vmik...@collabora.com> diff --git a/sw/qa/extras/ooxmlexport/data/tdf166510_sectPr_bottomSpacing.docx b/sw/qa/extras/ooxmlexport/data/tdf166510_sectPr_bottomSpacing.docx new file mode 100644 index 000000000000..620335bde7d5 Binary files /dev/null and b/sw/qa/extras/ooxmlexport/data/tdf166510_sectPr_bottomSpacing.docx differ diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport25.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport25.cxx index cf48755a7765..2b2976aefac5 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport25.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport25.cxx @@ -43,6 +43,17 @@ DECLARE_OOXMLEXPORT_TEST(testTdf166544_noTopMargin_fields, "tdf166544_noTopMargi CPPUNIT_ASSERT_EQUAL(sal_Int32(269), nHeight); } +DECLARE_OOXMLEXPORT_TEST(testTdf166510_sectPr_bottomSpacing, "tdf166510_sectPr_bottomSpacing.docx") +{ + // given with a sectPr with different bottom spacing (undefined in this case - i.e. zero) + auto pXmlDoc = parseLayoutDump(); + + // The last paragraph (sectPr) has 0 below spacing, so no reduction of page 2's 200pt top margin + sal_Int32 nHeight = getXPath(pXmlDoc, "//page[2]//body/txt/infos/bounds", "height").toInt32(); + // Without the fix, the text height (showing no top margin at all) was 253 + CPPUNIT_ASSERT_EQUAL(sal_Int32(4253), nHeight); +} + } // end of anonymous namespace CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/sw/source/writerfilter/dmapper/DomainMapper.cxx b/sw/source/writerfilter/dmapper/DomainMapper.cxx index b2c4eeec8dc6..01415e209783 100644 --- a/sw/source/writerfilter/dmapper/DomainMapper.cxx +++ b/sw/source/writerfilter/dmapper/DomainMapper.cxx @@ -4592,6 +4592,9 @@ void DomainMapper::lcl_utext(const sal_Unicode *const data_, size_t len) && !m_pImpl->HasTopAnchoredObjects() && !m_pImpl->IsParaWithInlineObject()); + if (bRemove && !m_pImpl->GetRemoveThisPara()) + m_pImpl->handleSectPrBeforeRemoval(); + const bool bNoNumbering = bRemove || (!m_pImpl->GetParaChanged() && m_pImpl->GetParaSectpr() && bSingleParagraph); PropertyMapPtr xContext = bNoNumbering ? m_pImpl->GetTopContextOfType(CONTEXT_PARAGRAPH) : PropertyMapPtr(); if (xContext) diff --git a/sw/source/writerfilter/dmapper/DomainMapper_Impl.cxx b/sw/source/writerfilter/dmapper/DomainMapper_Impl.cxx index 743b9bdcf8a5..0eba41c7c43b 100644 --- a/sw/source/writerfilter/dmapper/DomainMapper_Impl.cxx +++ b/sw/source/writerfilter/dmapper/DomainMapper_Impl.cxx @@ -10181,6 +10181,29 @@ bool DomainMapper_Impl::handlePreviousParagraphBorderInBetween() const return true; } +void DomainMapper_Impl::handleSectPrBeforeRemoval() +{ + PropertyMapPtr pSectPrContext = GetTopContextOfType(CONTEXT_PARAGRAPH); + if (!pSectPrContext) + return; + + // transfer below-spacing to previous paragraph - needed to layout above-spacing after pageBreak + if (!m_StreamStateStack.top().xPreviousParagraph.is()) + return; + + uno::Any aBelowSpacing = GetAnyProperty(PROP_PARA_BOTTOM_MARGIN, pSectPrContext); + if (!aBelowSpacing.hasValue()) + aBelowSpacing <<= sal_Int32(0); + + std::optional<uno::Any> oPrevBelowSpacing; + OUString sProp(getPropertyName(PROP_PARA_BOTTOM_MARGIN)); + if (m_StreamStateStack.top().xPreviousParagraph->getPropertySetInfo()->hasPropertyByName(sProp)) + oPrevBelowSpacing = m_StreamStateStack.top().xPreviousParagraph->getPropertyValue(sProp); + + if (!oPrevBelowSpacing.has_value() || aBelowSpacing != *oPrevBelowSpacing) + m_StreamStateStack.top().xPreviousParagraph->setPropertyValue(sProp, aBelowSpacing); +} + OUString DomainMapper_Impl::getFontNameForTheme(const Id id) { auto const& pHandler = getThemeHandler(); diff --git a/sw/source/writerfilter/dmapper/DomainMapper_Impl.hxx b/sw/source/writerfilter/dmapper/DomainMapper_Impl.hxx index 9d5274d7ed62..96a840b1a414 100644 --- a/sw/source/writerfilter/dmapper/DomainMapper_Impl.hxx +++ b/sw/source/writerfilter/dmapper/DomainMapper_Impl.hxx @@ -1247,6 +1247,9 @@ public: /// Check if previous paragraph has borders in between and do the border magic to it if so bool handlePreviousParagraphBorderInBetween() const; + /// An empty SectPr paragraph is not kept in LO. Do some adjustments before it gets deleted. + void handleSectPrBeforeRemoval(); + /// Handle redline text portions in a frame, footnotes and redlines: /// store their data, and create them after frame creation or footnote/endnote copying bool m_bIsActualParagraphFramed;