writerfilter/qa/cppunittests/dmapper/DomainMapper_Impl.cxx | 23 ++++++++++ writerfilter/qa/cppunittests/dmapper/data/clearing-break-sect-end.docx |binary writerfilter/source/dmapper/DomainMapper.cxx | 4 - writerfilter/source/dmapper/DomainMapper_Impl.cxx | 5 ++ writerfilter/source/dmapper/DomainMapper_Impl.hxx | 3 + 5 files changed, 33 insertions(+), 2 deletions(-)
New commits: commit f1338ba7de2ab1abf98283f977605a9d1053b82d Author: Miklos Vajna <vmik...@collabora.com> AuthorDate: Fri May 31 09:00:18 2024 +0200 Commit: Caolán McNamara <caolan.mcnam...@collabora.com> CommitDate: Mon Jun 3 16:08:02 2024 +0200 tdf#161318 sw clearing break: fix this at section end Regression from commit 19bca24486315cc35f873486e6a2dd18394d0614 (tdf#126287: docx import: use defered linebreak, 2022-02-07), the bugdoc has a single paragraph in the first section, containing a clearing break, which is lost. This leads to overlapping text as the text is shifted up. Seems the intention was to avoid a line break at the very end of the document, as that can lead to an empty page with "next page" section breaks, with non-clearing line breaks. Fix the problem by only doing this for non-clearing line breaks: that keeps the old use-case working, but the new, clearing line break then shifts down the text, so no text overlap happens. Switching from appendTextPortion() to HandleLineBreak() helps because HandleLineBreak() does exactly appendTextPortion(" ") in the non-clearing case, but knows about the stream stack's line break clear status. (cherry picked from commit e00479404af5058b982c447e485af995d552e372) Conflicts: writerfilter/qa/cppunittests/dmapper/data/clearing-break-sect-end.docx writerfilter/source/dmapper/DomainMapper.cxx Change-Id: I38868eeeac55e20e86b668e9baf7e0d6a4976608 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/168361 Reviewed-by: Caolán McNamara <caolan.mcnam...@collabora.com> Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com> diff --git a/writerfilter/qa/cppunittests/dmapper/DomainMapper_Impl.cxx b/writerfilter/qa/cppunittests/dmapper/DomainMapper_Impl.cxx index 16aa5cbfb2df..d2388505d71d 100644 --- a/writerfilter/qa/cppunittests/dmapper/DomainMapper_Impl.cxx +++ b/writerfilter/qa/cppunittests/dmapper/DomainMapper_Impl.cxx @@ -411,6 +411,29 @@ CPPUNIT_TEST_FIXTURE(Test, testRedlinedShapeThenSdt) CPPUNIT_ASSERT_EQUAL(u"ContentControl"_ustr, xPortion->getPropertyValue("TextPortionType").get<OUString>()); } + +CPPUNIT_TEST_FIXTURE(Test, testClearingBreakSectEnd) +{ + // Given a file with a single-paragraph section, ends with a clearing break: + // When importing that document: + loadFromFile(u"clearing-break-sect-end.docx"); + + // Then make sure the clearing break is not lost before a cont sect break: + uno::Reference<text::XTextDocument> xTextDocument(mxComponent, uno::UNO_QUERY); + uno::Reference<container::XEnumerationAccess> xParaEnumAccess(xTextDocument->getText(), + uno::UNO_QUERY); + uno::Reference<container::XEnumeration> xParaEnum = xParaEnumAccess->createEnumeration(); + uno::Reference<container::XEnumerationAccess> xPortionEnumAccess(xParaEnum->nextElement(), + uno::UNO_QUERY); + uno::Reference<container::XEnumeration> xPortionEnum = xPortionEnumAccess->createEnumeration(); + uno::Reference<beans::XPropertySet> xPortion(xPortionEnum->nextElement(), uno::UNO_QUERY); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: LineBreak + // - Actual : Text + // i.e. the clearing break at sect end was lost, leading to text overlap. + CPPUNIT_ASSERT_EQUAL(u"LineBreak"_ustr, + xPortion->getPropertyValue("TextPortionType").get<OUString>()); +} } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerfilter/qa/cppunittests/dmapper/data/clearing-break-sect-end.docx b/writerfilter/qa/cppunittests/dmapper/data/clearing-break-sect-end.docx new file mode 100644 index 000000000000..5052b2dd1649 Binary files /dev/null and b/writerfilter/qa/cppunittests/dmapper/data/clearing-break-sect-end.docx differ diff --git a/writerfilter/source/dmapper/DomainMapper.cxx b/writerfilter/source/dmapper/DomainMapper.cxx index bfca0214a017..d206fa0b140f 100644 --- a/writerfilter/source/dmapper/DomainMapper.cxx +++ b/writerfilter/source/dmapper/DomainMapper.cxx @@ -4354,13 +4354,13 @@ void DomainMapper::lcl_utext(const sal_Unicode *const data_, size_t len) else if (len == 1 && sText[0] == ' ') { // Clear "last" one linebreak at end of section - if (m_pImpl->GetIsLastParagraphInSection() && m_pImpl->isBreakDeferred(LINE_BREAK)) + if (m_pImpl->GetIsLastParagraphInSection() && m_pImpl->isBreakDeferred(LINE_BREAK) && !m_pImpl->HasLineBreakClear()) m_pImpl->clearDeferredBreak(LINE_BREAK); // And emit all other linebreaks while (m_pImpl->isBreakDeferred(LINE_BREAK)) { m_pImpl->clearDeferredBreak(LINE_BREAK); - m_pImpl->appendTextPortion(" ", m_pImpl->GetTopContext()); + m_pImpl->HandleLineBreak(m_pImpl->GetTopContext()); } } else if (len == 1 && sText[0] == ' ' ) diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.cxx b/writerfilter/source/dmapper/DomainMapper_Impl.cxx index 4c5dff02fcf7..b0f0f3bc9cd9 100644 --- a/writerfilter/source/dmapper/DomainMapper_Impl.cxx +++ b/writerfilter/source/dmapper/DomainMapper_Impl.cxx @@ -5150,6 +5150,11 @@ void DomainMapper_Impl::HandleLineBreakClear(sal_Int32 nClear) } } +bool DomainMapper_Impl::HasLineBreakClear() const +{ + return m_oLineBreakClear.has_value(); +} + void DomainMapper_Impl::HandleLineBreak(const PropertyMapPtr& pPropertyMap) { if (!m_oLineBreakClear.has_value()) diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.hxx b/writerfilter/source/dmapper/DomainMapper_Impl.hxx index 23fdc4d79b11..af75015d83dc 100644 --- a/writerfilter/source/dmapper/DomainMapper_Impl.hxx +++ b/writerfilter/source/dmapper/DomainMapper_Impl.hxx @@ -1233,6 +1233,9 @@ public: /// Handles <w:br w:clear="...">. void HandleLineBreakClear(sal_Int32 nClear); + /// Checks if we have a pending <w:br w:clear="...">. + bool HasLineBreakClear() const; + /// Handles <w:br>. void HandleLineBreak(const PropertyMapPtr& pPropertyMap);