From 8e3fa597679a6402bd6d74e2ec25631ae686c423 Mon Sep 17 00:00:00 2001 From: Mike Kaganski Date: Tue, 19 Nov 2019 22:41:52 +0300 Subject: tdf#128889: don't write "page break after" into w:pPr MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This produced invalid OOXML, which Word considers as "page before", and LibreOffice ignores when re-importing. Make sure to write it as *trailing* w:r with w:br, as Word also does when imports ODT with this atribute, and saves as DOCX. Change-Id: Ifc4f45d65d4455ecb5cd62aed1ef6a03375c8aa4 Reviewed-on: https://gerrit.libreoffice.org/83232 Tested-by: Jenkins Reviewed-by: Mike Kaganski (cherry picked from commit b0e7e494b6bc69d3833c0a6c256ff8106a4a24cb) Reviewed-on: https://gerrit.libreoffice.org/83334 Reviewed-by: Xisco FaulĂ­ --- sw/qa/extras/ooxmlexport/data/tdf128889.fodt | 15 +++++++++++++++ sw/qa/extras/ooxmlexport/ooxmlexport14.cxx | 11 +++++++++++ sw/source/filter/ww8/attributeoutputbase.hxx | 3 ++- sw/source/filter/ww8/docxattributeoutput.cxx | 21 +++++++++++++++++---- sw/source/filter/ww8/docxattributeoutput.hxx | 6 +++++- sw/source/filter/ww8/docxexport.cxx | 4 ++-- sw/source/filter/ww8/rtfattributeoutput.cxx | 3 ++- sw/source/filter/ww8/rtfattributeoutput.hxx | 3 ++- sw/source/filter/ww8/rtfexport.cxx | 4 ++-- sw/source/filter/ww8/ww8atr.cxx | 8 ++++---- sw/source/filter/ww8/ww8attributeoutput.hxx | 2 +- 11 files changed, 63 insertions(+), 17 deletions(-) create mode 100644 sw/qa/extras/ooxmlexport/data/tdf128889.fodt diff --git a/sw/qa/extras/ooxmlexport/data/tdf128889.fodt b/sw/qa/extras/ooxmlexport/data/tdf128889.fodt new file mode 100644 index 000000000000..6dc1c4202696 --- /dev/null +++ b/sw/qa/extras/ooxmlexport/data/tdf128889.fodt @@ -0,0 +1,15 @@ + + + + + + + + + + + para1 + para2 + + + \ No newline at end of file diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport14.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport14.cxx index c8c95d1cd132..3e542dc72fcf 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport14.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport14.cxx @@ -168,6 +168,17 @@ DECLARE_OOXMLEXPORT_EXPORTONLY_TEST(testTdf128820, "tdf128820.fodt") "a:graphic/a:graphicData/wpg:wgp/wps:wsp"); } +DECLARE_OOXMLEXPORT_EXPORTONLY_TEST(testTdf128889, "tdf128889.fodt") +{ + xmlDocPtr pXml = parseExport("word/document.xml"); + CPPUNIT_ASSERT(pXml); + // There was an w:r (with w:br) as an invalid child of first paragraph's w:pPr + assertXPath(pXml, "/w:document/w:body/w:p[1]/w:pPr/w:r", 0); + assertXPath(pXml, "/w:document/w:body/w:p[1]/w:r", 2); + // Check that the break is in proper - last - position + assertXPath(pXml, "/w:document/w:body/w:p[1]/w:r[2]/w:br", "type", "page"); +} + CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/filter/ww8/attributeoutputbase.hxx b/sw/source/filter/ww8/attributeoutputbase.hxx index 74084f625590..70509ed47806 100644 --- a/sw/source/filter/ww8/attributeoutputbase.hxx +++ b/sw/source/filter/ww8/attributeoutputbase.hxx @@ -299,7 +299,8 @@ public: /// Write a section break /// msword::ColumnBreak or msword::PageBreak - virtual void SectionBreak( sal_uInt8 nC, const WW8_SepInfo* pSectionInfo = nullptr ) = 0; + /// bBreakAfter: the break must be scheduled for insertion in the end of current paragraph + virtual void SectionBreak( sal_uInt8 nC, bool bBreakAfter, const WW8_SepInfo* pSectionInfo = nullptr ) = 0; // preserve page vertical alignment virtual void TextVerticalAdjustment( const css::drawing::TextVerticalAdjust) {}; diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx b/sw/source/filter/ww8/docxattributeoutput.cxx index 3c2c614bf096..4f18582b0d7f 100644 --- a/sw/source/filter/ww8/docxattributeoutput.cxx +++ b/sw/source/filter/ww8/docxattributeoutput.cxx @@ -745,6 +745,13 @@ void DocxAttributeOutput::EndParagraph( ww8::WW8TableNodeInfoInner::Pointer_t pT m_bStartedCharSdt = false; } + if (m_bPageBreakAfter) + { + // tdf#128889 Trailing page break + SectionBreak(msword::PageBreak, false); + m_bPageBreakAfter = false; + } + m_pSerializer->endElementNS( XML_w, XML_p ); // on export sdt blocks are never nested ATM if( !m_bAnchorLinkedToNode && !m_bStartedParaSdt ) @@ -5981,7 +5988,7 @@ void DocxAttributeOutput::PageBreakBefore( bool bBreak ) FSNS( XML_w, XML_val ), "false" ); } -void DocxAttributeOutput::SectionBreak( sal_uInt8 nC, const WW8_SepInfo* pSectionInfo ) +void DocxAttributeOutput::SectionBreak( sal_uInt8 nC, bool bBreakAfter, const WW8_SepInfo* pSectionInfo ) { switch ( nC ) { @@ -6043,9 +6050,15 @@ void DocxAttributeOutput::SectionBreak( sal_uInt8 nC, const WW8_SepInfo* pSectio } else if ( m_bParagraphOpened ) { - m_pSerializer->startElementNS(XML_w, XML_r); - m_pSerializer->singleElementNS(XML_w, XML_br, FSNS(XML_w, XML_type), "page"); - m_pSerializer->endElementNS( XML_w, XML_r ); + if (bBreakAfter) + // tdf#128889 + m_bPageBreakAfter = true; + else + { + m_pSerializer->startElementNS(XML_w, XML_r); + m_pSerializer->singleElementNS(XML_w, XML_br, FSNS(XML_w, XML_type), "page"); + m_pSerializer->endElementNS(XML_w, XML_r); + } } else m_bPostponedPageBreak = true; diff --git a/sw/source/filter/ww8/docxattributeoutput.hxx b/sw/source/filter/ww8/docxattributeoutput.hxx index 2a8a43a76a79..67561087ceb3 100644 --- a/sw/source/filter/ww8/docxattributeoutput.hxx +++ b/sw/source/filter/ww8/docxattributeoutput.hxx @@ -270,7 +270,8 @@ public: /// Write a section break /// msword::ColumnBreak or msword::PageBreak - virtual void SectionBreak( sal_uInt8 nC, const WW8_SepInfo* pSectionInfo = nullptr ) override; + /// bBreakAfter: the break must be scheduled for insertion in the end of current paragraph + virtual void SectionBreak( sal_uInt8 nC, bool bBreakAfter, const WW8_SepInfo* pSectionInfo = nullptr ) override; // preserve DOCX page vertical alignment virtual void TextVerticalAdjustment( const css::drawing::TextVerticalAdjust ) override; @@ -841,6 +842,9 @@ private: // beginning of the next paragraph bool m_bPostponedPageBreak; + // This paragraph must end with page break + bool m_bPageBreakAfter = false; + std::vector m_aFramesOfParagraph; std::set m_aFloatingTablesOfParagraph; sal_Int32 m_nTextFrameLevel; diff --git a/sw/source/filter/ww8/docxexport.cxx b/sw/source/filter/ww8/docxexport.cxx index c6226fd130ab..3e9c4bc5fd1b 100644 --- a/sw/source/filter/ww8/docxexport.cxx +++ b/sw/source/filter/ww8/docxexport.cxx @@ -547,7 +547,7 @@ ErrCode DocxExport::ExportDocument_Impl() void DocxExport::AppendSection( const SwPageDesc *pPageDesc, const SwSectionFormat* pFormat, sal_uLong nLnNum ) { - AttrOutput().SectionBreak( msword::PageBreak, m_pSections->CurrentSectionInfo() ); + AttrOutput().SectionBreak( msword::PageBreak, false, m_pSections->CurrentSectionInfo() ); m_pSections->AppendSection( pPageDesc, pFormat, nLnNum, m_pAttrOutput->IsFirstParagraph() ); } @@ -622,7 +622,7 @@ void DocxExport::PrepareNewPageDesc( const SfxItemSet* pSet, { // tell the attribute output that we are ready to write the section // break [has to be output inside paragraph properties] - AttrOutput().SectionBreak( msword::PageBreak, m_pSections->CurrentSectionInfo() ); + AttrOutput().SectionBreak( msword::PageBreak, false, m_pSections->CurrentSectionInfo() ); const SwSectionFormat* pFormat = GetSectionFormat( rNd ); const sal_uLong nLnNm = GetSectionLineNo( pSet, rNd ); diff --git a/sw/source/filter/ww8/rtfattributeoutput.cxx b/sw/source/filter/ww8/rtfattributeoutput.cxx index 67622810d0db..6a04e707a706 100644 --- a/sw/source/filter/ww8/rtfattributeoutput.cxx +++ b/sw/source/filter/ww8/rtfattributeoutput.cxx @@ -1200,7 +1200,8 @@ void RtfAttributeOutput::PageBreakBefore(bool bBreak) } } -void RtfAttributeOutput::SectionBreak(sal_uInt8 nC, const WW8_SepInfo* pSectionInfo) +void RtfAttributeOutput::SectionBreak(sal_uInt8 nC, bool /*bBreakAfter*/, + const WW8_SepInfo* pSectionInfo) { switch (nC) { diff --git a/sw/source/filter/ww8/rtfattributeoutput.hxx b/sw/source/filter/ww8/rtfattributeoutput.hxx index fe0d093ae0a3..4ea8b3845bcd 100644 --- a/sw/source/filter/ww8/rtfattributeoutput.hxx +++ b/sw/source/filter/ww8/rtfattributeoutput.hxx @@ -165,7 +165,8 @@ public: /// Write a section break /// msword::ColumnBreak or msword::PageBreak - void SectionBreak(sal_uInt8 nC, const WW8_SepInfo* pSectionInfo = nullptr) override; + void SectionBreak(sal_uInt8 nC, bool bBreakAfter, + const WW8_SepInfo* pSectionInfo = nullptr) override; /// Start of the section properties. void StartSection() override; diff --git a/sw/source/filter/ww8/rtfexport.cxx b/sw/source/filter/ww8/rtfexport.cxx index 787833bbac71..f29268032ed0 100644 --- a/sw/source/filter/ww8/rtfexport.cxx +++ b/sw/source/filter/ww8/rtfexport.cxx @@ -970,7 +970,7 @@ void RtfExport::PrepareNewPageDesc(const SfxItemSet* pSet, const SwNode& rNd, // Don't insert a page break, when we're changing page style just because the next page has to be a different one. if (!m_pAttrOutput->GetPrevPageDesc() || m_pAttrOutput->GetPrevPageDesc()->GetFollow() != pNewPgDesc) - AttrOutput().SectionBreak(msword::PageBreak, m_pSections->CurrentSectionInfo()); + AttrOutput().SectionBreak(msword::PageBreak, false, m_pSections->CurrentSectionInfo()); } bool RtfExport::DisallowInheritingOutlineNumbering(const SwFormat& rFormat) @@ -1026,7 +1026,7 @@ void RtfExport::AppendSection(const SwPageDesc* pPageDesc, const SwSectionFormat sal_uLong nLnNum) { m_pSections->AppendSection(pPageDesc, pFormat, nLnNum); - AttrOutput().SectionBreak(msword::PageBreak, m_pSections->CurrentSectionInfo()); + AttrOutput().SectionBreak(msword::PageBreak, false, m_pSections->CurrentSectionInfo()); } RtfExport::RtfExport(RtfExportFilter* pFilter, SwDoc* pDocument, diff --git a/sw/source/filter/ww8/ww8atr.cxx b/sw/source/filter/ww8/ww8atr.cxx index b72a0246bf21..f4525e09b663 100644 --- a/sw/source/filter/ww8/ww8atr.cxx +++ b/sw/source/filter/ww8/ww8atr.cxx @@ -2191,7 +2191,7 @@ void AttributeOutputBase::StartTOX( const SwSection& rSect ) SwSection *pParent = rSect.GetParent(); WW8_SepInfo rInfo(&GetExport( ).m_pDoc->GetPageDesc(0), pParent ? pParent->GetFormat() : nullptr, 0/*nRstLnNum*/); - GetExport( ).AttrOutput().SectionBreak( msword::PageBreak, &rInfo ); + GetExport( ).AttrOutput().SectionBreak( msword::PageBreak, false, &rInfo ); } sStr += "\\c \"" + OUString::number( nCol ) + "\""; @@ -2499,7 +2499,7 @@ void AttributeOutputBase::EndTOX( const SwSection& rSect,bool bCareEnd ) if ( 0 < nCol ) { WW8_SepInfo rInfo( &GetExport( ).m_pDoc->GetPageDesc( 0 ), rSect.GetFormat(), 0/*nRstLnNum*/ ); - GetExport( ).AttrOutput().SectionBreak( msword::PageBreak, &rInfo ); + GetExport( ).AttrOutput().SectionBreak( msword::PageBreak, false, &rInfo ); } } } @@ -3880,13 +3880,13 @@ void AttributeOutputBase::FormatBreak( const SvxFormatBreakItem& rBreak ) } if ( !bFollowPageDescWritten ) { - SectionBreak( nC ); + SectionBreak(nC, !bBefore); } } } } -void WW8AttributeOutput::SectionBreak( sal_uInt8 nC, const WW8_SepInfo* /*pSectionInfo*/ ) +void WW8AttributeOutput::SectionBreak( sal_uInt8 nC, bool /*bBreakAfter*/, const WW8_SepInfo* /*pSectionInfo*/ ) { m_rWW8Export.ReplaceCr( nC ); } diff --git a/sw/source/filter/ww8/ww8attributeoutput.hxx b/sw/source/filter/ww8/ww8attributeoutput.hxx index 35d8db7dfa5e..7e3f2a31ff20 100644 --- a/sw/source/filter/ww8/ww8attributeoutput.hxx +++ b/sw/source/filter/ww8/ww8attributeoutput.hxx @@ -147,7 +147,7 @@ public: /// Write a section break /// msword::ColumnBreak or msword::PageBreak - virtual void SectionBreak( sal_uInt8 nC, const WW8_SepInfo* pSectionInfo = nullptr ) override; + virtual void SectionBreak( sal_uInt8 nC, bool bBreakAfter, const WW8_SepInfo* pSectionInfo = nullptr ) override; // preserve DOC page vertical alignment virtual void TextVerticalAdjustment( const css::drawing::TextVerticalAdjust ) override; -- cgit