sw/qa/extras/ooxmlexport/data/tdf147892.fodt | 25 ++++++++++++++++++++++ sw/qa/extras/ooxmlexport/ooxmlexport12.cxx | 10 +++++++++ sw/source/filter/ww8/docxattributeoutput.cxx | 30 ++++++++++++++------------- sw/source/filter/ww8/docxattributeoutput.hxx | 4 +-- 4 files changed, 53 insertions(+), 16 deletions(-)
New commits: commit 4c05f5b45ce8449adee81aeac355fae652b97786 Author: László Németh <nem...@numbertext.org> AuthorDate: Fri Feb 10 13:43:40 2023 +0100 Commit: László Németh <nem...@numbertext.org> CommitDate: Thu Mar 30 13:37:18 2023 +0000 tdf#147892 DOCX: fix corrupt export at para marker revision history OOXML export of tracked deletion of tracked paragraph insertion resulted invalid document.xml, because change tracking history of paragraph markers isn't supported by OOXML. Export the tracked deletion of the last run of paragraphs without history (tracked insertion). This way w:p/w:pPr/w:rPr contains only w:del or w:ins, not both of them (with broken tag order). Note: it's possible to optimize the fix to keep the change tracking history of the characters of the last run of the paragraph, except the paragraph marker. Regression from commit eeee19b3fcf8b0374c361c7f6c285fd5c89b5a2f "tdf#142387 DOCX track changes: export w:del in w:ins". Minimal unit test document was created by Miklós Vajna. Change-Id: I425f4d63c8c6ac29ccd807c1574748c7b9b39e80 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/146782 Tested-by: László Németh <nem...@numbertext.org> Reviewed-by: László Németh <nem...@numbertext.org> (cherry-picked from commit 382892341a63e400f221e1a533fd5a5d6b4d9d70) Conflicts: sw/source/filter/ww8/docxattributeoutput.cxx Change-Id: I0e29195512d8786ac5f6a145ed88a9261f1c456e Reviewed-on: https://gerrit.libreoffice.org/c/core/+/149763 Reviewed-by: Stéphane Guillou <stephane.guil...@libreoffice.org> Tested-by: Jenkins Reviewed-by: László Németh <nem...@numbertext.org> Tested-by: László Németh <nem...@numbertext.org> diff --git a/sw/qa/extras/ooxmlexport/data/tdf147892.fodt b/sw/qa/extras/ooxmlexport/data/tdf147892.fodt new file mode 100644 index 000000000000..bb3ffc324dc1 --- /dev/null +++ b/sw/qa/extras/ooxmlexport/data/tdf147892.fodt @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8"?> +<office:document xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" office:version="1.3" office:mimetype="application/vnd.oasis.opendocument.text"> + <office:body> + <office:text> + <text:tracked-changes text:track-changes="false"> + <text:changed-region xml:id="ct12345678" text:id="ct12345678"> + <text:deletion> + <office:change-info> + <dc:creator>Bob</dc:creator> + <dc:date>2023-01-02T00:00:00</dc:date> + </office:change-info> + </text:deletion> + <text:insertion> + <office:change-info> + <dc:creator>Alice</dc:creator> + <dc:date>2023-01-01T00:00:00</dc:date> + </office:change-info> + </text:insertion> + </text:changed-region> + </text:tracked-changes> + <text:p><text:change-start text:change-id="ct12345678"/></text:p> + <text:p><text:change-end text:change-id="ct12345678"/></text:p> + </office:text> + </office:body> +</office:document> diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport12.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport12.cxx index f831fd3ad61e..25a9932101ee 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport12.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport12.cxx @@ -2023,6 +2023,16 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf142387) assertXPathContent(pXmlDoc, "/w:document/w:body/w:p/w:ins/w:del/w:r/w:delText", "inserts "); } +CPPUNIT_TEST_FIXTURE(Test, testTdf147892) +{ + loadAndSave("tdf147892.fodt"); + xmlDocUniquePtr pXmlDoc = parseExport("word/document.xml"); + // w:del in w:ins is exported correctly + // (both w:del and w:ins were exported for para marker) + assertXPath(pXmlDoc, "/w:document/w:body/w:p[1]/w:pPr/w:rPr/w:del", 1); + assertXPath(pXmlDoc, "/w:document/w:body/w:p[1]/w:pPr/w:rPr/w:ins", 0); +} + DECLARE_OOXMLEXPORT_TEST(testTdf123054, "tdf123054.docx") { CPPUNIT_ASSERT_EQUAL(OUString("No Spacing"), diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx b/sw/source/filter/ww8/docxattributeoutput.cxx index 70c21933ebdd..b3866fbeca4d 100644 --- a/sw/source/filter/ww8/docxattributeoutput.cxx +++ b/sw/source/filter/ww8/docxattributeoutput.cxx @@ -1466,13 +1466,13 @@ void DocxAttributeOutput::EndParagraphProperties(const SfxItemSet& rParagraphMar if ( pRedlineParagraphMarkerDeleted ) { - StartRedline( pRedlineParagraphMarkerDeleted ); - EndRedline( pRedlineParagraphMarkerDeleted ); + StartRedline( pRedlineParagraphMarkerDeleted, /*bLastRun=*/true ); + EndRedline( pRedlineParagraphMarkerDeleted, /*bLastRun=*/true ); } if ( pRedlineParagraphMarkerInserted ) { - StartRedline( pRedlineParagraphMarkerInserted ); - EndRedline( pRedlineParagraphMarkerInserted ); + StartRedline( pRedlineParagraphMarkerInserted, /*bLastRun=*/true ); + EndRedline( pRedlineParagraphMarkerInserted, /*bLastRun=*/true ); } // mergeTopMarks() after paragraph mark properties child elements. @@ -1575,7 +1575,7 @@ void DocxAttributeOutput::StartRun( const SwRedlineData* pRedlineData, sal_Int32 m_pSerializer->mark(Tag_StartRun_3); // let's call it "postponed text" } -void DocxAttributeOutput::EndRun(const SwTextNode* pNode, sal_Int32 nPos, bool /*bLastRun*/) +void DocxAttributeOutput::EndRun(const SwTextNode* pNode, sal_Int32 nPos, bool bLastRun) { int nFieldsInPrevHyperlink = m_nFieldsInHyperlink; // Reset m_nFieldsInHyperlink if a new hyperlink is about to start @@ -1665,9 +1665,9 @@ void DocxAttributeOutput::EndRun(const SwTextNode* pNode, sal_Int32 nPos, bool / // InputField with extra grabbag params - it is sdt field (pIt->eType == ww::eFILLIN && static_cast<const SwInputField*>(pIt->pField.get())->getGrabBagParams().hasElements()))) { - StartRedline( m_pRedlineData ); + StartRedline( m_pRedlineData, bLastRun ); StartField_Impl( pNode, nPos, *pIt, true ); - EndRedline( m_pRedlineData ); + EndRedline( m_pRedlineData, bLastRun ); if (m_startedHyperlink) ++m_nFieldsInHyperlink; @@ -1738,7 +1738,7 @@ void DocxAttributeOutput::EndRun(const SwTextNode* pNode, sal_Int32 nPos, bool / WriteContentControlStart(); // if there is some redlining in the document, output it - StartRedline( m_pRedlineData ); + StartRedline( m_pRedlineData, bLastRun ); // XML_r node should be surrounded with bookmark-begin and bookmark-end nodes if it has bookmarks. // The same is applied for permission ranges. @@ -1802,7 +1802,7 @@ void DocxAttributeOutput::EndRun(const SwTextNode* pNode, sal_Int32 nPos, bool / // if there is some redlining in the document, output it // (except in the case of fields with multiple runs) - EndRedline( m_pRedlineData ); + EndRedline( m_pRedlineData, bLastRun ); // enclose in a sdt block, if necessary: if one is already started, then don't do it for now // (so on export sdt blocks are never nested ATM) @@ -1912,7 +1912,7 @@ void DocxAttributeOutput::EndRun(const SwTextNode* pNode, sal_Int32 nPos, bool / if ( m_pRedlineData ) { - EndRedline( m_pRedlineData ); + EndRedline( m_pRedlineData, bLastRun ); m_pRedlineData = nullptr; } @@ -3778,13 +3778,14 @@ void DocxAttributeOutput::Redline( const SwRedlineData* pRedlineData) // The difference between 'Redline' and 'StartRedline'+'EndRedline' is that: // 'Redline' is used for tracked changes of formatting information of a run like Bold, Underline. (the '<w:rPrChange>' is inside the 'run' node) // 'StartRedline' is used to output tracked changes of run insertion and deletion (the run is inside the '<w:ins>' node) -void DocxAttributeOutput::StartRedline( const SwRedlineData * pRedlineData ) +void DocxAttributeOutput::StartRedline( const SwRedlineData * pRedlineData, bool bLastRun ) { if ( !pRedlineData ) return; // write out stack of this redline recursively (first the oldest) - StartRedline( pRedlineData->Next() ); + if ( !bLastRun ) + StartRedline( pRedlineData->Next(), false ); OString aId( OString::number( m_nRedlineId++ ) ); @@ -3829,7 +3830,7 @@ void DocxAttributeOutput::StartRedline( const SwRedlineData * pRedlineData ) } } -void DocxAttributeOutput::EndRedline( const SwRedlineData * pRedlineData ) +void DocxAttributeOutput::EndRedline( const SwRedlineData * pRedlineData, bool bLastRun ) { if ( !pRedlineData || m_bWritingField ) return; @@ -3855,7 +3856,8 @@ void DocxAttributeOutput::EndRedline( const SwRedlineData * pRedlineData ) } // write out stack of this redline recursively (first the newest) - EndRedline( pRedlineData->Next() ); + if ( !bLastRun ) + EndRedline( pRedlineData->Next(), false ); } void DocxAttributeOutput::FormatDrop( const SwTextNode& /*rNode*/, const SwFormatDrop& /*rSwFormatDrop*/, sal_uInt16 /*nStyle*/, ww8::WW8TableNodeInfo::Pointer_t /*pTextNodeInfo*/, ww8::WW8TableNodeInfoInner::Pointer_t ) diff --git a/sw/source/filter/ww8/docxattributeoutput.hxx b/sw/source/filter/ww8/docxattributeoutput.hxx index 09c6f8079e9d..d2a5ccdc7895 100644 --- a/sw/source/filter/ww8/docxattributeoutput.hxx +++ b/sw/source/filter/ww8/docxattributeoutput.hxx @@ -228,12 +228,12 @@ public: /// /// Start of the tag that encloses the run, fills the info according to /// the value of pRedlineData. - void StartRedline( const SwRedlineData * pRedlineData ); + void StartRedline( const SwRedlineData * pRedlineData, bool bLastRun ); /// Output redlining. /// /// End of the tag that encloses the run. - void EndRedline( const SwRedlineData * pRedlineData ); + void EndRedline( const SwRedlineData * pRedlineData, bool bLastRun ); virtual void SetStateOfFlyFrame( FlyProcessingState nStateOfFlyFrame ) override; virtual void SetAnchorIsLinkedToNode( bool bAnchorLinkedToNode ) override;