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 1d833123014274a182ea42e92ca21e4ece736389 Author: Miklos Vajna <[email protected]> AuthorDate: Wed Oct 22 09:28:56 2025 +0200 Commit: Miklos Vajna <[email protected]> CommitDate: Wed Oct 22 13:52:28 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/+/192834 Reviewed-by: Miklos Vajna <[email protected]> Tested-by: Jenkins 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 384e2e3852e8..b4fcc0cd7c3b 100644 --- a/sw/source/writerfilter/dmapper/DomainMapper.cxx +++ b/sw/source/writerfilter/dmapper/DomainMapper.cxx @@ -1592,6 +1592,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. @@ -2748,21 +2793,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 0cc866205735..f63f474951bc 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);
