sw/qa/extras/ooxmlexport/data/tdf153964_topMarginAfterBreak14.docx |binary sw/qa/extras/ooxmlexport/data/tdf153964_topMarginAfterBreak15.docx |binary sw/qa/extras/ooxmlexport/ooxmlexport18.cxx | 101 +++++++++- writerfilter/source/dmapper/DomainMapper.cxx | 62 ++++++ 4 files changed, 156 insertions(+), 7 deletions(-)
New commits: commit e099d21f540a0018687064953832163815549b2e Author: Justin Luth <justin.l...@collabora.com> AuthorDate: Tue Mar 7 07:43:14 2023 -0500 Commit: Justin Luth <jl...@mail.com> CommitDate: Wed Mar 8 23:34:15 2023 +0000 tdf#153964 writerfilter compat15: top margin after break split The problem was that the top margin was being applied to the new paragraph after the split. This is absolutely attrocious in MS Word before 2013. If I am going to be in error, I want to error on the side of being compliant with compat15, since all other versions of MS Word are now unsupported. I think I have the logic of it mostly figured out. In compat15, the top margin never applies after the break. In compat14, if the paragraph properties are not applied to a run before the break, then they can be applied after the break. make CppunitTest_sw_ooxmlexport18 \ CPPUNIT_TEST_NAME=testTdf153964_topMarginAfterBreak14 make CppunitTest_sw_ooxmlexport18 \ CPPUNIT_TEST_NAME=testTdf153964_topMarginAfterBreak15 Change-Id: I8816b391e898cfea58c2e0dbf01c881f87bbc4c4 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/148451 Tested-by: Justin Luth <jl...@mail.com> Reviewed-by: Justin Luth <jl...@mail.com> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/148476 diff --git a/sw/qa/extras/ooxmlexport/data/tdf153964_topMarginAfterBreak14.docx b/sw/qa/extras/ooxmlexport/data/tdf153964_topMarginAfterBreak14.docx new file mode 100644 index 000000000000..6c57bcfdc8ef Binary files /dev/null and b/sw/qa/extras/ooxmlexport/data/tdf153964_topMarginAfterBreak14.docx differ diff --git a/sw/qa/extras/ooxmlexport/data/tdf153964_topMarginAfterBreak15.docx b/sw/qa/extras/ooxmlexport/data/tdf153964_topMarginAfterBreak15.docx new file mode 100644 index 000000000000..e4d5c45ed034 Binary files /dev/null and b/sw/qa/extras/ooxmlexport/data/tdf153964_topMarginAfterBreak15.docx differ diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport18.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport18.cxx index 02d229f08f11..fc3ca2f99bf8 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport18.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport18.cxx @@ -87,12 +87,6 @@ DECLARE_OOXMLEXPORT_TEST(testTdf153526_commentInNumbering, "tdf153526_commentInN CPPUNIT_ASSERT_EQUAL(13, getParagraphs()); } -DECLARE_OOXMLEXPORT_TEST(testTdf153613_sdtAfterPgBreak, "tdf153613_sdtAfterPgBreak.docx") -{ - // the page break was missing. Before the fix this was 1 page - CPPUNIT_ASSERT_EQUAL(2, getPages()); -} - CPPUNIT_TEST_FIXTURE(Test, testTdf153592_columnBreaks) { loadAndSave("tdf153592_columnBreaks.docx"); @@ -159,6 +153,101 @@ DECLARE_OOXMLEXPORT_TEST(testTdf153613_textboxAfterPgBreak2, "tdf153613_textboxA assertXPathContent(pLayout, "//page[2]/body/txt", "There should be no prior carriage return."); } +DECLARE_OOXMLEXPORT_TEST(testTdf153613_sdtAfterPgBreak, "tdf153613_sdtAfterPgBreak.docx") +{ + CPPUNIT_ASSERT_EQUAL(2, getPages()); +} + +DECLARE_OOXMLEXPORT_TEST(testTdf153964_topMarginAfterBreak14, "tdf153964_topMarginAfterBreak14.docx") +{ + //The top margin should only apply once in a split paragraph. + //In this compat14 (Windows 2010) version, it applies after the break if no prior visible run. + uno::Reference<beans::XPropertySet> xPara(getParagraph(2, "a w:br at the start of the document. Does it use 60 point top margin?"), uno::UNO_QUERY); + //CPPUNIT_ASSERT_EQUAL(sal_Int32(2117), getProperty<sal_Int32>(xPara, "ParaTopMargin")); + + xPara.set(getParagraph(3, u"60 pt spacing before"), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(sal_Int32(2117), getProperty<sal_Int32>(xPara, "ParaTopMargin")); + CPPUNIT_ASSERT_EQUAL(Color(0xfbe4d5), getProperty<Color>(xPara, "ParaBackColor")); + + // The top margin was applied to paragraph 3, so it shouldn't apply here + xPara.set(getParagraph(4, u"column break1"), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty<sal_Int32>(xPara, "ParaTopMargin")); + //CPPUNIT_ASSERT_EQUAL(Color(0xfbe4d5), getProperty<Color>(xPara, "ParaBackColor")); + + xPara.set(getParagraph(5, u"60 pt followed by page break"), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(sal_Int32(2117), getProperty<sal_Int32>(xPara, "ParaTopMargin")); + CPPUNIT_ASSERT_EQUAL(Color(0xdeeaf6), getProperty<Color>(xPara, "ParaBackColor")); + + // The top margin was applied to paragraph 5, so it shouldn't apply here + xPara.set(getParagraph(6, u"page break1"), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty<sal_Int32>(xPara, "ParaTopMargin")); + CPPUNIT_ASSERT_EQUAL(Color(0xdeeaf6), getProperty<Color>(xPara, "ParaBackColor")); + + // The top margin was not applied yet, so with compat14 it should apply here. + xPara.set(getParagraph(7, u"column break2"), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(sal_Int32(2117), getProperty<sal_Int32>(xPara, "ParaTopMargin")); + CPPUNIT_ASSERT_EQUAL(Color(0xe2efd9), getProperty<Color>(xPara, "ParaBackColor")); + + // In an odd twist, the w:br was actually at the end of the previous w:p, so in that case + // we ignore the top margin definition this time. + xPara.set(getParagraph(9, u"page break2"), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty<sal_Int32>(xPara, "ParaTopMargin")); + + // The top margin was not applied before the column break, so with compat14 it should apply here + xPara.set(getParagraph(10, u""), uno::UNO_QUERY); // after column break + CPPUNIT_ASSERT_EQUAL(sal_Int32(2117), getProperty<sal_Int32>(xPara, "ParaTopMargin")); + //CPPUNIT_ASSERT_EQUAL(Color(0xfff2cc), getProperty<Color>(xPara, "ParaBackColor")); + + // In an odd twist, the w:br was actually at the end of the previous w:p, so in that case + // we ignore the top margin definition this time. + xPara.set(getParagraph(12, u""), uno::UNO_QUERY); // after page break + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty<sal_Int32>(xPara, "ParaTopMargin")); +} + +DECLARE_OOXMLEXPORT_TEST(testTdf153964_topMarginAfterBreak15, "tdf153964_topMarginAfterBreak15.docx") +{ + //The top margin should only apply once (at most) in a split paragraph. + //In this compat15 (Windows 2013) version, it never applies after the break. + uno::Reference<beans::XPropertySet> xPara(getParagraph(2, "a w:br at the start of the document. Does it use 60 point top margin?"), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty<sal_Int32>(xPara, "ParaTopMargin")); + + xPara.set(getParagraph(3, u"60 pt spacing before"), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(sal_Int32(2117), getProperty<sal_Int32>(xPara, "ParaTopMargin")); + CPPUNIT_ASSERT_EQUAL(Color(0xfbe4d5), getProperty<Color>(xPara, "ParaBackColor")); + + // The top margin was applied to paragraph 3, so it shouldn't apply here + xPara.set(getParagraph(4, u"column break1"), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty<sal_Int32>(xPara, "ParaTopMargin")); + //CPPUNIT_ASSERT_EQUAL(Color(0xfbe4d5), getProperty<Color>(xPara, "ParaBackColor")); + + xPara.set(getParagraph(5, u"60 pt followed by page break"), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(sal_Int32(2117), getProperty<sal_Int32>(xPara, "ParaTopMargin")); + CPPUNIT_ASSERT_EQUAL(Color(0xdeeaf6), getProperty<Color>(xPara, "ParaBackColor")); + + // The top margin was applied to paragraph 5, so it shouldn't apply here + xPara.set(getParagraph(6, u"page break1"), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty<sal_Int32>(xPara, "ParaTopMargin")); + CPPUNIT_ASSERT_EQUAL(Color(0xdeeaf6), getProperty<Color>(xPara, "ParaBackColor")); + + // The top margin was not applied to paragraph 6, and with compat15 it shouldn't apply here. + xPara.set(getParagraph(7, u"column break2"), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty<sal_Int32>(xPara, "ParaTopMargin")); + CPPUNIT_ASSERT_EQUAL(Color(0xe2efd9), getProperty<Color>(xPara, "ParaBackColor")); + + // The top margin not was applied to paragraph 8, and with compat15 it shouldn't apply here. + xPara.set(getParagraph(9, u"page break2"), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty<sal_Int32>(xPara, "ParaTopMargin")); + + // The top margin was not applied to paragraph 9, and with compat15 it shouldn't apply here. + xPara.set(getParagraph(10, u""), uno::UNO_QUERY); // after column break + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty<sal_Int32>(xPara, "ParaTopMargin")); + //CPPUNIT_ASSERT_EQUAL(Color(0xfff2cc), getProperty<Color>(xPara, "ParaBackColor")); + + // The top margin was not applied to paragraph 11, and with compat15 it shouldn't apply here. + xPara.set(getParagraph(12, u""), uno::UNO_QUERY); // after page break + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty<sal_Int32>(xPara, "ParaTopMargin")); +} + CPPUNIT_TEST_FIXTURE(Test, testTdf149551_mongolianVert) { // Given a docx document with a shape with vert="mongolianVert". diff --git a/writerfilter/source/dmapper/DomainMapper.cxx b/writerfilter/source/dmapper/DomainMapper.cxx index 799d1f5d2a68..2ef39d8117d0 100644 --- a/writerfilter/source/dmapper/DomainMapper.cxx +++ b/writerfilter/source/dmapper/DomainMapper.cxx @@ -1106,6 +1106,14 @@ void DomainMapper::lcl_attribute(Id nName, Value & val) finishParagraph(); lcl_startParagraphGroup(); } + else // IsFirstRun + { + if (GetSettingsTable()->GetWordCompatibilityMode() > 14) + { + pContext->Insert(PROP_PARA_TOP_MARGIN, uno::Any(sal_uInt32(0))); + } + } + pContext->Insert(PROP_BREAK_TYPE, uno::Any(style::BreakType_PAGE_BEFORE)); m_pImpl->clearDeferredBreaks(); } @@ -1118,6 +1126,14 @@ void DomainMapper::lcl_attribute(Id nName, Value & val) finishParagraph(); lcl_startParagraphGroup(); } + else // IsFirstRun + { + if (GetSettingsTable()->GetWordCompatibilityMode() > 14) + { + pContext->Insert(PROP_PARA_TOP_MARGIN, uno::Any(sal_uInt32(0))); + } + } + pContext->Insert(PROP_BREAK_TYPE, uno::Any(style::BreakType_COLUMN_BEFORE)); m_pImpl->clearDeferredBreaks(); } @@ -3541,13 +3557,29 @@ void DomainMapper::lcl_startParagraphGroup() if (!m_pImpl->IsInShape() && !m_pImpl->IsInComments()) { const OUString& sDefaultParaStyle = m_pImpl->GetDefaultParaStyleName(); + auto pContext = static_cast<ParagraphPropertyMap*>(m_pImpl->GetTopContext().get()); m_pImpl->GetTopContext()->Insert( PROP_PARA_STYLE_NAME, uno::Any( sDefaultParaStyle ) ); m_pImpl->SetCurrentParaStyleName( sDefaultParaStyle ); if (m_pImpl->isBreakDeferred(PAGE_BREAK)) + { m_pImpl->GetTopContext()->Insert(PROP_BREAK_TYPE, uno::Any(style::BreakType_PAGE_BEFORE)); + + // With a w:br at the start of a paragraph, compat14 apparently doesn't apply. + // It works to insert a zero margin before importing paragraph properties because + // TopMargin typically imports without overwrite any existing value. Very handy. + pContext->Insert(PROP_PARA_TOP_MARGIN, uno::Any(sal_uInt32(0))); + } else if (m_pImpl->isBreakDeferred(COLUMN_BREAK)) + { m_pImpl->GetTopContext()->Insert(PROP_BREAK_TYPE, uno::Any(style::BreakType_COLUMN_BEFORE)); + + if (GetSettingsTable()->GetWordCompatibilityMode() > 14) + { + pContext->Insert(PROP_PARA_TOP_MARGIN, uno::Any(sal_uInt32(0))); + } + } + mbWasShapeInPara = false; } @@ -4115,7 +4147,13 @@ void DomainMapper::lcl_utext(const sal_uInt8 * data_, size_t len) finishParagraph(); lcl_startParagraphGroup(); } - + else // IsFirstRun + { + if (GetSettingsTable()->GetWordCompatibilityMode() > 14) + { + pContext->Insert(PROP_PARA_TOP_MARGIN, uno::Any(sal_uInt32(0))); + } + } pContext->Insert(PROP_BREAK_TYPE, uno::Any(style::BreakType_PAGE_BEFORE)); m_pImpl->clearDeferredBreaks(); @@ -4129,6 +4167,13 @@ void DomainMapper::lcl_utext(const sal_uInt8 * data_, size_t len) finishParagraph(); lcl_startParagraphGroup(); } + else // IsFirstRun + { + if (GetSettingsTable()->GetWordCompatibilityMode() > 14) + { + pContext->Insert(PROP_PARA_TOP_MARGIN, uno::Any(sal_uInt32(0))); + } + } pContext->Insert(PROP_BREAK_TYPE, uno::Any(style::BreakType_COLUMN_BEFORE)); m_pImpl->clearDeferredBreaks(); @@ -4191,6 +4236,7 @@ void DomainMapper::lcl_utext(const sal_uInt8 * data_, size_t len) PropertyMapPtr pContext = m_pImpl->GetTopContext(); if (!m_pImpl->GetFootnoteContext() && !m_pImpl->IsInShape() && !m_pImpl->IsInComments()) { + auto pPara = static_cast<ParagraphPropertyMap*>(m_pImpl->GetTopContextOfType(CONTEXT_PARAGRAPH).get()); if (m_pImpl->isBreakDeferred(PAGE_BREAK)) { /* If PAGEBREAK appears in first paragraph of the section or @@ -4203,6 +4249,13 @@ void DomainMapper::lcl_utext(const sal_uInt8 * data_, size_t len) finishParagraph(); lcl_startParagraphGroup(); } + else // IsFirstRun + { + if (GetSettingsTable()->GetWordCompatibilityMode() > 14) + { + pPara->Insert(PROP_PARA_TOP_MARGIN, uno::Any(sal_uInt32(0)), true); + } + } m_pImpl->GetTopContext()->Insert(PROP_BREAK_TYPE, uno::Any(style::BreakType_PAGE_BEFORE)); } else if (m_pImpl->isBreakDeferred(COLUMN_BREAK)) @@ -4214,6 +4267,13 @@ void DomainMapper::lcl_utext(const sal_uInt8 * data_, size_t len) finishParagraph(); lcl_startParagraphGroup(); } + else // IsFirstRun + { + if (GetSettingsTable()->GetWordCompatibilityMode() > 14) + { + pPara->Insert(PROP_PARA_TOP_MARGIN, uno::Any(sal_uInt32(0))); + } + } m_pImpl->GetTopContext()->Insert(PROP_BREAK_TYPE, uno::Any(style::BreakType_COLUMN_BEFORE)); } m_pImpl->clearDeferredBreaks();