sw/qa/writerfilter/dmapper/DomainMapper.cxx                  |   30 ++++-
 sw/qa/writerfilter/dmapper/data/framepr-pagebreak-style.docx |binary
 sw/source/writerfilter/dmapper/DomainMapper.cxx              |   61 ++++++++---
 sw/source/writerfilter/dmapper/DomainMapper.hxx              |    1 
 4 files changed, 74 insertions(+), 18 deletions(-)

New commits:
commit f9d4bf220bda7fc4112f898ff26605be57a49577
Author:     Miklos Vajna <[email protected]>
AuthorDate: Wed Oct 22 09:28:56 2025 +0200
Commit:     Caolán McNamara <[email protected]>
CommitDate: Wed Oct 22 11:52:03 2025 +0200

    Related: tdf#168916 DOCX import: handle page break from style on framed para
    
    Open a subset of the bugdoc, it's of two pages in Word, it's one page in
    Writer.
    
    What happens is that the paragraph that's at the top of page 2 in Word
    has a <w:framePr> property on it, so it forms a text frame, but it also
    inherits a <w:pageBreakBefore> via using the Heading 1 style and Word
    layout then handles this 'page break before' request.
    
    Fix the problem by extending a previous fix in this area: commit
    f6f53f76e15f5eecc5b6ce56e471c53cebfea8ad (tdf#123636 writerfilter:
    handle deferred breaks on frames, 2019-04-30) already tried to handle
    this, but it covered only the case when the page break property was set
    directly. Now this is also found via a style.
    
    The actual bugdoc needs more fixes, but this way at least we attempt to
    split floating tables at places where the expected result of that split
    is known, while previously we tried to split at the wrong positions, due
    to the loss of the page break.
    
    Change-Id: Icc24fcdb05a4375583917eb97b63f4a19dc4bd17
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/192821
    Reviewed-by: Caolán McNamara <[email protected]>
    Tested-by: Jenkins CollaboraOffice <[email protected]>
    Tested-by: Caolán McNamara <[email protected]>

diff --git a/sw/qa/writerfilter/dmapper/DomainMapper.cxx 
b/sw/qa/writerfilter/dmapper/DomainMapper.cxx
index 3f6dbc0072fb..28b4858e7aa3 100644
--- a/sw/qa/writerfilter/dmapper/DomainMapper.cxx
+++ b/sw/qa/writerfilter/dmapper/DomainMapper.cxx
@@ -7,7 +7,7 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  */
 
-#include <test/unoapi_test.hxx>
+#include <swmodeltestbase.hxx>
 
 #include <com/sun/star/text/XTextDocument.hpp>
 #include <com/sun/star/beans/XPropertySet.hpp>
@@ -23,16 +23,21 @@
 #include <unotools/streamwrap.hxx>
 #include <comphelper/propertyvalue.hxx>
 
+#include <docsh.hxx>
+#include <IDocumentLayoutAccess.hxx>
+#include <rootfrm.hxx>
+#include <pagefrm.hxx>
+
 using namespace ::com::sun::star;
 
 namespace
 {
 /// Tests for sw/source/writerfilter/dmapper/DomainMapper.cxx.
-class Test : public UnoApiTest
+class Test : public SwModelTestBase
 {
 public:
     Test()
-        : UnoApiTest(u"/sw/qa/writerfilter/dmapper/data/"_ustr)
+        : SwModelTestBase(u"/sw/qa/writerfilter/dmapper/data/"_ustr)
     {
     }
 };
@@ -249,6 +254,25 @@ CPPUNIT_TEST_FIXTURE(Test, testRTFFontFamily)
     // i.e. the final result was a sans fallback instead of a serif fallback.
     CPPUNIT_ASSERT_EQUAL(awt::FontFamily::ROMAN, eFamily);
 }
+
+CPPUNIT_TEST_FIXTURE(Test, testFrameprPagebreakStyle)
+{
+    // Given a document with a heading 1 style that sets both framePr and 
pageBreakBefore:
+    // When loading that document:
+    createSwDoc("framepr-pagebreak-style.docx");
+
+    // Then make sure the page break request is not ignored:
+    SwDocShell* pDocShell = getSwDocShell();
+    SwDoc* pDoc = pDocShell->GetDoc();
+    IDocumentLayoutAccess& rIDLA = pDoc->getIDocumentLayoutAccess();
+    SwRootFrame* pLayout = rIDLA.GetCurrentLayout();
+    SwPageFrame* pLastPage = pLayout->GetLastPage();
+    // Without the accompanying fix in place, this test would have failed with:
+    // - Expected: 2
+    // - Actual  : 1
+    // i.e. the page break was lost, the document didn't have the correct page 
count.
+    CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(2), 
pLastPage->GetPhyPageNum());
+}
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/qa/writerfilter/dmapper/data/framepr-pagebreak-style.docx 
b/sw/qa/writerfilter/dmapper/data/framepr-pagebreak-style.docx
new file mode 100644
index 000000000000..a7c4118af54e
Binary files /dev/null and 
b/sw/qa/writerfilter/dmapper/data/framepr-pagebreak-style.docx differ
diff --git a/sw/source/writerfilter/dmapper/DomainMapper.cxx 
b/sw/source/writerfilter/dmapper/DomainMapper.cxx
index 050991aa2771..69f16550fde4 100644
--- a/sw/source/writerfilter/dmapper/DomainMapper.cxx
+++ b/sw/source/writerfilter/dmapper/DomainMapper.cxx
@@ -1425,6 +1425,51 @@ static bool ExchangeLeftRight(const PropertyMapPtr& 
rContext, DomainMapper_Impl&
     return bExchangeLeftRight;
 }
 
+// If there is a deferred page break applied to this framed paragraph,
+// create a dummy paragraph without extra properties,
+// so that the anchored frame will be on the correct page (similar to shapes).
+void DomainMapper::HandleFramedParagraphPageBreak(PropertyMapPtr pContext)
+{
+    bool bBreakTypeIsSet = pContext->isSet(PROP_BREAK_TYPE);
+    if (!bBreakTypeIsSet)
+    {
+        if (!pContext->isSet(PROP_PARA_STYLE_NAME))
+        {
+            return;
+        }
+
+        OUString sStyleName;
+        pContext->getProperty(PROP_PARA_STYLE_NAME)->second >>= sStyleName;
+        if (sStyleName.isEmpty() || !GetStyleSheetTable())
+        {
+            return;
+        }
+
+        StyleSheetEntryPtr pStyle
+            = 
GetStyleSheetTable()->FindStyleSheetByConvertedStyleName(sStyleName);
+        if (!pStyle || !pStyle->m_pProperties)
+        {
+            return;
+        }
+
+        bBreakTypeIsSet = pStyle->m_pProperties->isSet(PROP_BREAK_TYPE);
+    }
+    if (!bBreakTypeIsSet)
+    {
+        return;
+    }
+
+    pContext->Erase(PROP_BREAK_TYPE);
+
+    lcl_startParagraphGroup();
+    m_pImpl->GetTopContext()->Insert(PROP_BREAK_TYPE, 
uno::Any(style::BreakType_PAGE_BEFORE));
+    lcl_startCharacterGroup();
+    sal_Unicode const sBreak[] = { 0x0d };
+    lcl_utext(sBreak, 1);
+    lcl_endCharacterGroup();
+    lcl_endParagraphGroup();
+}
+
 void DomainMapper::sprmWithProps( Sprm& rSprm, const PropertyMapPtr& rContext )
 {
     // These SPRM's are not specific to any section, so it's expected that 
there is no context yet.
@@ -2581,21 +2626,7 @@ void DomainMapper::sprmWithProps( Sprm& rSprm, const 
PropertyMapPtr& rContext )
         PropertyMapPtr pContext = 
m_pImpl->GetTopContextOfType(CONTEXT_PARAGRAPH);
         if( pContext )
         {
-            // If there is a deferred page break applied to this framed 
paragraph,
-            // create a dummy paragraph without extra properties,
-            // so that the anchored frame will be on the correct page (similar 
to shapes).
-            if (pContext->isSet(PROP_BREAK_TYPE))
-            {
-                pContext->Erase(PROP_BREAK_TYPE);
-
-                lcl_startParagraphGroup();
-                m_pImpl->GetTopContext()->Insert(PROP_BREAK_TYPE, 
uno::Any(style::BreakType_PAGE_BEFORE));
-                lcl_startCharacterGroup();
-                sal_Unicode const sBreak[] = { 0x0d };
-                lcl_utext(sBreak, 1);
-                lcl_endCharacterGroup();
-                lcl_endParagraphGroup();
-            }
+            HandleFramedParagraphPageBreak(pContext);
 
             ParagraphPropertyMap* pParaContext = dynamic_cast< 
ParagraphPropertyMap* >( pContext.get() );
             if (pParaContext)
diff --git a/sw/source/writerfilter/dmapper/DomainMapper.hxx 
b/sw/source/writerfilter/dmapper/DomainMapper.hxx
index a431a8d876d4..2c52e7983c0f 100644
--- a/sw/source/writerfilter/dmapper/DomainMapper.hxx
+++ b/sw/source/writerfilter/dmapper/DomainMapper.hxx
@@ -186,6 +186,7 @@ private:
 
     static void handleUnderlineType(const Id nId, const 
::tools::SvRef<PropertyMap>& rContext);
     void handleParaJustification(const sal_Int32 nIntValue, const 
::tools::SvRef<PropertyMap>& rContext, const bool bExchangeLeftRight);
+    void HandleFramedParagraphPageBreak(PropertyMapPtr pContext);
     static bool getColorFromId(const Id, sal_Int32 &nColor);
     static sal_Int16 getEmphasisValue(const sal_Int32 nIntValue);
     static OUString getBracketStringFromEnum(const sal_Int32 nIntValue, const 
bool bIsPrefix = true);

Reply via email to