sw/qa/extras/ooxmlexport/data/tdf147892.fodt |   25 ++++++++++++++++++++++
 sw/qa/extras/ooxmlexport/ooxmlexport11.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 f91e083e2565f07a6ebd2f2c0aa69bbacb4cfd19
Author:     László Németh <nem...@numbertext.org>
AuthorDate: Fri Feb 10 13:43:40 2023 +0100
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Wed Feb 15 07:12:53 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)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/146795
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>
    (cherry picked from commit 4eb34d281260d7c9b6f2268ca1fa439655238a55)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/147022
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com>
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>

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/ooxmlexport11.cxx 
b/sw/qa/extras/ooxmlexport/ooxmlexport11.cxx
index 8ffd2a9e5673..f62571ff57fc 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport11.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport11.cxx
@@ -1572,6 +1572,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 2ade8669d251..a70bee00967a 100644
--- a/sw/source/filter/ww8/docxattributeoutput.cxx
+++ b/sw/source/filter/ww8/docxattributeoutput.cxx
@@ -1507,13 +1507,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.
@@ -1618,7 +1618,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, 
sal_Int32 nLen, bool /*bLastRun*/)
+void DocxAttributeOutput::EndRun(const SwTextNode* pNode, sal_Int32 nPos, 
sal_Int32 nLen, bool bLastRun)
 {
     int nFieldsInPrevHyperlink = m_nFieldsInHyperlink;
     // Reset m_nFieldsInHyperlink if a new hyperlink is about to start
@@ -1702,9 +1702,9 @@ void DocxAttributeOutput::EndRun(const SwTextNode* pNode, 
sal_Int32 nPos, sal_In
             // 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;
@@ -1773,7 +1773,7 @@ void DocxAttributeOutput::EndRun(const SwTextNode* pNode, 
sal_Int32 nPos, sal_In
     }
 
     // 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.
@@ -1858,7 +1858,7 @@ void DocxAttributeOutput::EndRun(const SwTextNode* pNode, 
sal_Int32 nPos, sal_In
 
     // 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)
@@ -1962,7 +1962,7 @@ void DocxAttributeOutput::EndRun(const SwTextNode* pNode, 
sal_Int32 nPos, sal_In
 
     if ( m_pRedlineData )
     {
-        EndRedline( m_pRedlineData );
+        EndRedline( m_pRedlineData, bLastRun );
         m_pRedlineData = nullptr;
     }
 
@@ -3916,13 +3916,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++ ) );
 
@@ -3965,7 +3966,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;
@@ -3989,7 +3990,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 a73a7a344070..26f977539cae 100644
--- a/sw/source/filter/ww8/docxattributeoutput.hxx
+++ b/sw/source/filter/ww8/docxattributeoutput.hxx
@@ -235,12 +235,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;

Reply via email to