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

Reply via email to