sw/qa/extras/ooxmlexport/data/tdf153255.docx      |binary
 sw/qa/extras/ooxmlexport/ooxmlexport14.cxx        |   35 ++++++++++++++++++++++
 writerfilter/source/dmapper/DomainMapper_Impl.cxx |   14 ++++++--
 3 files changed, 46 insertions(+), 3 deletions(-)

New commits:
commit 76ab4aad33f6a019b5bc28af17917dd58e7cf9f7
Author:     László Németh <nem...@numbertext.org>
AuthorDate: Mon Mar 20 17:27:32 2023 +0100
Commit:     Xisco Fauli <xiscofa...@libreoffice.org>
CommitDate: Wed Mar 22 14:24:36 2023 +0000

    tdf#153255 DOCX import: fix footnote order
    
    Simple unit test for tdf#152203 allowed to create
    bad ordering algorithm by accident without noticing
    the problem, which caused problem for most of the DOCX
    files, where serialization in footnotes.xml doesn't follow
    the order of the footnotes.
    
    Regression from commit 9b39ce0e66acfe812e1d50e530dc2ccdef3e1357
    "tdf#76260 DOCX import: fix slow footnote import".
    
    Follow-up to commit 09ae3c01940bbc25ffde51963683b04e3cb4bb6a
    "tdf#152203 DOCX import: fix mixed footnotes/endnotes".
    
    Change-Id: I0628d96e3b8ad4df38d26e9288b47d39b958c441
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/149176
    Tested-by: Jenkins
    Reviewed-by: László Németh <nem...@numbertext.org>
    (cherry picked from commit 93a20c1d9c2f379906970bbe8a15905fc1a328bc)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/149242
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>

diff --git a/sw/qa/extras/ooxmlexport/data/tdf153255.docx 
b/sw/qa/extras/ooxmlexport/data/tdf153255.docx
new file mode 100644
index 000000000000..e9f2892d5670
Binary files /dev/null and b/sw/qa/extras/ooxmlexport/data/tdf153255.docx differ
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport14.cxx 
b/sw/qa/extras/ooxmlexport/ooxmlexport14.cxx
index 3916866b9ff4..c6949b14e6bc 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport14.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport14.cxx
@@ -1307,6 +1307,41 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf152206)
     CPPUNIT_ASSERT_EQUAL( OUString("Footnote for pg5"), 
xLastButOne->getString().trim() );
 }
 
+CPPUNIT_TEST_FIXTURE(Test, testTdf153255)
+{
+    loadAndSave("tdf153255.docx");
+    xmlDocUniquePtr pXml = parseExport("word/footnotes.xml");
+    CPPUNIT_ASSERT(pXml);
+
+    uno::Reference<text::XFootnotesSupplier> xFootnotesSupplier(mxComponent, 
uno::UNO_QUERY);
+    uno::Reference<container::XIndexAccess> xFootnotes = 
xFootnotesSupplier->getFootnotes();
+    uno::Reference<text::XTextRange> xLastFootnote(xFootnotes->getByIndex(5), 
uno::UNO_QUERY);
+    // This was "Footnote for pg2" (replaced footnotes)
+    CPPUNIT_ASSERT_EQUAL( OUString("Footnote for pg 6"), 
xLastFootnote->getString().trim() );
+
+    uno::Reference<text::XTextRange> xLastButOne(xFootnotes->getByIndex(4), 
uno::UNO_QUERY);
+    // This was "Footnote for pg 6" (replaced footnotes)
+    CPPUNIT_ASSERT_EQUAL( OUString("Footnote for pg5"), 
xLastButOne->getString().trim() );
+
+    // check all the remaining footnotes
+
+    uno::Reference<text::XTextRange> xFootnote1(xFootnotes->getByIndex(0), 
uno::UNO_QUERY);
+    // This was "Footnote for pg3" (replaced footnotes)
+    CPPUNIT_ASSERT_EQUAL( OUString("Footnote for pg1"), 
xFootnote1->getString().trim() );
+
+    uno::Reference<text::XTextRange> xFootnote2(xFootnotes->getByIndex(1), 
uno::UNO_QUERY);
+    // This was "Footnote for pg5" (replaced footnotes)
+    CPPUNIT_ASSERT_EQUAL( OUString("Footnote for pg2"), 
xFootnote2->getString().trim() );
+
+    uno::Reference<text::XTextRange> xFootnote3(xFootnotes->getByIndex(2), 
uno::UNO_QUERY);
+    // This was "Footnote for pg4." (replaced footnotes)
+    CPPUNIT_ASSERT_EQUAL( OUString("Footnote for pg3"), 
xFootnote3->getString().trim() );
+
+    uno::Reference<text::XTextRange> xFootnote4(xFootnotes->getByIndex(3), 
uno::UNO_QUERY);
+    // This was "Footnote for pg1" (replaced footnotes)
+    CPPUNIT_ASSERT_EQUAL( OUString("Footnote for pg4."), 
xFootnote4->getString().trim() );
+}
+
 // skip test for macOS (missing fonts?)
 #if !defined(MACOSX)
 DECLARE_OOXMLEXPORT_TEST(testTdf146346, "tdf146346.docx")
diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.cxx 
b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
index e9fda3f50101..449c75e9b8ce 100644
--- a/writerfilter/source/dmapper/DomainMapper_Impl.cxx
+++ b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
@@ -3716,15 +3716,23 @@ void DomainMapper_Impl::RemoveTemporaryFootOrEndnotes()
 
 static void lcl_convertToNoteIndices(std::deque<sal_Int32>& rNoteIds, 
sal_Int32& rFirstNoteIndex)
 {
-    // convert arbitrary footnote identifiers to 0, 1, 2...
-    // indices, keeping their possible random order
+    // rNoteIds contains XML footnote identifiers in the loaded order of the 
footnotes
+    // (the same order as in footnotes.xml), i.e. it maps temporary footnote 
positions to the
+    // identifiers. For example: Ids[0] = 100; Ids[1] = -1, Ids[2] = 5.
+    // To copy the footnotes in their final place, create an array, which map 
the (normalized)
+    // footnote identifiers to the temporary footnote positions. Using the 
previous example,
+    // Pos[0] = 1; Pos[1] = 2; Pos[2] = 0 (where [0], [1], [2] are the 
normalized
+    // -1, 5 and 100 identifiers).
     std::deque<sal_Int32> aSortedIds = rNoteIds;
     std::sort(aSortedIds.begin(), aSortedIds.end());
     std::map<sal_Int32, size_t> aMapIds;
+    // normalize footnote identifiers to 0, 1, 2 ...
     for (size_t i = 0; i < aSortedIds.size(); ++i)
         aMapIds[aSortedIds[i]] = i;
+    // reusing rNoteIds, create the Pos array to map normalized identifiers to 
the loaded positions
+    std::deque<sal_Int32> aOrigNoteIds = rNoteIds;
     for (size_t i = 0; i < rNoteIds.size(); ++i)
-        rNoteIds[i] = aMapIds[rNoteIds[i]];
+        rNoteIds[aMapIds[aOrigNoteIds[i]]] = i;
     rFirstNoteIndex = rNoteIds.front();
     rNoteIds.pop_front();
 }

Reply via email to