[Libreoffice-commits] core.git: Branch 'private/swe/libreoffice-5-2+backports' - sw/qa sw/source

Tamás Zolnai tamas.zolnai at collabora.com
Fri Nov 10 01:03:40 UTC 2017


 sw/qa/extras/ww8export/data/object_cross_reference.odt              |binary
 sw/qa/extras/ww8export/data/table_cross_reference.odt               |binary
 sw/qa/extras/ww8export/data/table_cross_reference_custom_format.odt |binary
 sw/qa/extras/ww8export/ww8export.cxx                                |  387 ++++++++++
 sw/source/filter/ww8/attributeoutputbase.hxx                        |   10 
 sw/source/filter/ww8/docxattributeoutput.cxx                        |  209 -----
 sw/source/filter/ww8/docxattributeoutput.hxx                        |   18 
 sw/source/filter/ww8/docxexport.cxx                                 |    2 
 sw/source/filter/ww8/rtfattributeoutput.cxx                         |    4 
 sw/source/filter/ww8/rtfattributeoutput.hxx                         |    6 
 sw/source/filter/ww8/wrtw8nds.cxx                                   |   27 
 sw/source/filter/ww8/wrtww8.cxx                                     |    6 
 sw/source/filter/ww8/wrtww8.hxx                                     |    1 
 sw/source/filter/ww8/ww8atr.cxx                                     |  203 +++++
 sw/source/filter/ww8/ww8attributeoutput.hxx                         |   12 
 15 files changed, 658 insertions(+), 227 deletions(-)

New commits:
commit 9df0dcc797dfa201f7843bb32984c342d274c1af
Author: Tamás Zolnai <tamas.zolnai at collabora.com>
Date:   Thu Nov 9 17:55:14 2017 +0100

    tdf#42346: DOC export of cross-references to objects
    
    Same solution which was used for DOCX export:
    98bc7215935f1eb2e0dc6f1db826d8e729430c13
    
    Reviewed-on: https://gerrit.libreoffice.org/44502
    Reviewed-by: Tamás Zolnai <tamas.zolnai at collabora.com>
    Tested-by: Tamás Zolnai <tamas.zolnai at collabora.com>
    (cherry picked from commit cbaa72d6e963847a4b98526430cd928bc7928fdd)
    
    Change-Id: I8af46db003a6192c6adaae1a35dff58744919eee
    Reviewed-on: https://gerrit.libreoffice.org/44560
    Reviewed-by: Thorsten Behrens <Thorsten.Behrens at CIB.de>
    Tested-by: Thorsten Behrens <Thorsten.Behrens at CIB.de>

diff --git a/sw/qa/extras/ww8export/data/object_cross_reference.odt b/sw/qa/extras/ww8export/data/object_cross_reference.odt
new file mode 100755
index 000000000000..9eaca352b68c
Binary files /dev/null and b/sw/qa/extras/ww8export/data/object_cross_reference.odt differ
diff --git a/sw/qa/extras/ww8export/data/table_cross_reference.odt b/sw/qa/extras/ww8export/data/table_cross_reference.odt
new file mode 100755
index 000000000000..95f33139c522
Binary files /dev/null and b/sw/qa/extras/ww8export/data/table_cross_reference.odt differ
diff --git a/sw/qa/extras/ww8export/data/table_cross_reference_custom_format.odt b/sw/qa/extras/ww8export/data/table_cross_reference_custom_format.odt
new file mode 100755
index 000000000000..1c41e364c6e5
Binary files /dev/null and b/sw/qa/extras/ww8export/data/table_cross_reference_custom_format.odt differ
diff --git a/sw/qa/extras/ww8export/ww8export.cxx b/sw/qa/extras/ww8export/ww8export.cxx
index f31bbda02a06..7985f479f0fa 100644
--- a/sw/qa/extras/ww8export/ww8export.cxx
+++ b/sw/qa/extras/ww8export/ww8export.cxx
@@ -726,6 +726,393 @@ DECLARE_WW8EXPORT_TEST(testTdf99474, "tdf99474.odt")
     CPPUNIT_ASSERT_EQUAL(COL_AUTO, charColor);
 }
 
+DECLARE_OOXMLEXPORT_TEST( testTableCrossReference, "table_cross_reference.odt" )
+{
+    // tdf#42346: Cross references to tables were not saved
+    // MSO uses simple bookmarks for referencing table caption, so we do the same by export
+    if (!mbExported)
+        return;
+
+    // Check whether we have all the neccessary bookmarks exported and imported back
+    uno::Reference<text::XBookmarksSupplier> xBookmarksSupplier(mxComponent, uno::UNO_QUERY);
+    uno::Reference<container::XIndexAccess> xBookmarksByIdx(xBookmarksSupplier->getBookmarks(), uno::UNO_QUERY);
+    CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(4), xBookmarksByIdx->getCount());
+    uno::Reference<container::XNameAccess> xBookmarksByName(xBookmarksSupplier->getBookmarks(), uno::UNO_QUERY);
+    CPPUNIT_ASSERT(xBookmarksByName->hasByName("Ref_Table0_full"));
+    CPPUNIT_ASSERT(xBookmarksByName->hasByName("Ref_Table0_label_and_number"));
+    CPPUNIT_ASSERT(xBookmarksByName->hasByName("Ref_Table0_caption_only"));
+    CPPUNIT_ASSERT(xBookmarksByName->hasByName("Ref_Table0_number_only"));
+
+    // Check bookmark text ranges
+    {
+        uno::Reference<text::XTextContent> xContent(xBookmarksByName->getByName("Ref_Table0_full"), uno::UNO_QUERY);
+        uno::Reference<text::XTextRange> xRange(xContent->getAnchor(), uno::UNO_QUERY);
+        CPPUNIT_ASSERT_EQUAL(OUString("Table 1: Table caption"), xRange->getString());
+    }
+    {
+        uno::Reference<text::XTextContent> xContent(xBookmarksByName->getByName("Ref_Table0_label_and_number"), uno::UNO_QUERY);
+        uno::Reference<text::XTextRange> xRange(xContent->getAnchor(), uno::UNO_QUERY);
+        CPPUNIT_ASSERT_EQUAL(OUString("Table 1"), xRange->getString());
+    }
+    {
+        uno::Reference<text::XTextContent> xContent(xBookmarksByName->getByName("Ref_Table0_caption_only"), uno::UNO_QUERY);
+        uno::Reference<text::XTextRange> xRange(xContent->getAnchor(), uno::UNO_QUERY);
+        CPPUNIT_ASSERT_EQUAL(OUString("Table caption"), xRange->getString());
+    }
+    {
+        uno::Reference<text::XTextContent> xContent(xBookmarksByName->getByName("Ref_Table0_number_only"), uno::UNO_QUERY);
+        uno::Reference<text::XTextRange> xRange(xContent->getAnchor(), uno::UNO_QUERY);
+        CPPUNIT_ASSERT_EQUAL(OUString("1"), xRange->getString());
+    }
+
+    // Check reference fields
+    uno::Reference<text::XTextFieldsSupplier> xTextFieldsSupplier(mxComponent, uno::UNO_QUERY);
+    uno::Reference<container::XEnumerationAccess> xFieldsAccess(xTextFieldsSupplier->getTextFields());
+    uno::Reference<container::XEnumeration> xFields(xFieldsAccess->createEnumeration());
+    CPPUNIT_ASSERT(xFields->hasMoreElements());
+
+    sal_uInt16 nIndex = 0;
+    while (xFields->hasMoreElements())
+    {
+        uno::Reference<lang::XServiceInfo> xServiceInfo(xFields->nextElement(), uno::UNO_QUERY);
+        uno::Reference<beans::XPropertySet> xPropertySet(xServiceInfo, uno::UNO_QUERY);
+        switch (nIndex)
+        {
+            // Full reference to table caption
+            case 0:
+            {
+                CPPUNIT_ASSERT(xServiceInfo->supportsService("com.sun.star.text.TextField.GetReference"));
+                OUString sValue;
+                sal_Int16 nValue;
+                xPropertySet->getPropertyValue("CurrentPresentation") >>= sValue;
+                CPPUNIT_ASSERT_EQUAL(OUString("Table 1: Table caption"), sValue);
+                xPropertySet->getPropertyValue("SourceName") >>= sValue;
+                CPPUNIT_ASSERT_EQUAL(OUString("Ref_Table0_full"), sValue);
+                xPropertySet->getPropertyValue("SequenceNumber") >>= nValue;
+                CPPUNIT_ASSERT_EQUAL(sal_Int16(0), nValue);
+                break;
+            }
+            // Reference to table number
+            case 1:
+            {
+                CPPUNIT_ASSERT(xServiceInfo->supportsService("com.sun.star.text.TextField.GetReference"));
+                OUString sValue;
+                sal_Int16 nValue;
+                xPropertySet->getPropertyValue("CurrentPresentation") >>= sValue;
+                CPPUNIT_ASSERT_EQUAL(OUString("1"), sValue);
+                xPropertySet->getPropertyValue("SourceName") >>= sValue;
+                CPPUNIT_ASSERT_EQUAL(OUString("Ref_Table0_number_only"), sValue);
+                xPropertySet->getPropertyValue("SequenceNumber") >>= nValue;
+                CPPUNIT_ASSERT_EQUAL(sal_Int16(0), nValue);
+                break;
+            }
+            // Reference to caption only
+            case 2:
+            {
+                CPPUNIT_ASSERT(xServiceInfo->supportsService("com.sun.star.text.TextField.GetReference"));
+                OUString sValue;
+                sal_Int16 nValue;
+                xPropertySet->getPropertyValue("CurrentPresentation") >>= sValue;
+                CPPUNIT_ASSERT_EQUAL(OUString("Table caption"), sValue);
+                xPropertySet->getPropertyValue("SourceName") >>= sValue;
+                CPPUNIT_ASSERT_EQUAL(OUString("Ref_Table0_caption_only"), sValue);
+                xPropertySet->getPropertyValue("SequenceNumber") >>= nValue;
+                CPPUNIT_ASSERT_EQUAL(sal_Int16(0), nValue);
+                break;
+            }
+            // Reference to category and number
+            case 3:
+            {
+                CPPUNIT_ASSERT(xServiceInfo->supportsService("com.sun.star.text.TextField.GetReference"));
+                OUString sValue;
+                sal_Int16 nValue;
+                xPropertySet->getPropertyValue("CurrentPresentation") >>= sValue;
+                CPPUNIT_ASSERT_EQUAL(OUString("Table 1"), sValue);
+                xPropertySet->getPropertyValue("SourceName") >>= sValue;
+                CPPUNIT_ASSERT_EQUAL(OUString("Ref_Table0_label_and_number"), sValue);
+                xPropertySet->getPropertyValue("SequenceNumber") >>= nValue;
+                CPPUNIT_ASSERT_EQUAL(sal_Int16(0), nValue);
+                break;
+            }
+            // Reference to page of the table
+            case 4:
+            {
+                CPPUNIT_ASSERT(xServiceInfo->supportsService("com.sun.star.text.TextField.GetReference"));
+                OUString sValue;
+                sal_Int16 nValue;
+                xPropertySet->getPropertyValue("CurrentPresentation") >>= sValue;
+                CPPUNIT_ASSERT_EQUAL(OUString("1"), sValue);
+                xPropertySet->getPropertyValue("SourceName") >>= sValue;
+                CPPUNIT_ASSERT_EQUAL(OUString("Ref_Table0_full"), sValue);
+                xPropertySet->getPropertyValue("SequenceNumber") >>= nValue;
+                CPPUNIT_ASSERT_EQUAL(sal_Int16(0), nValue);
+                break;
+            }
+            // Page style reference / exported as simple page reference
+            case 5:
+            {
+                CPPUNIT_ASSERT(xServiceInfo->supportsService("com.sun.star.text.TextField.GetReference"));
+                OUString sValue;
+                sal_Int16 nValue;
+                xPropertySet->getPropertyValue("CurrentPresentation") >>= sValue;
+                CPPUNIT_ASSERT_EQUAL(OUString("1"), sValue);
+                xPropertySet->getPropertyValue("SourceName") >>= sValue;
+                CPPUNIT_ASSERT_EQUAL(OUString("Ref_Table0_full"), sValue);
+                xPropertySet->getPropertyValue("SequenceNumber") >>= nValue;
+                CPPUNIT_ASSERT_EQUAL(sal_Int16(0), nValue);
+                break;
+            }
+            // Above / bellow reference
+            case 6:
+            {
+                CPPUNIT_ASSERT(xServiceInfo->supportsService("com.sun.star.text.TextField.GetReference"));
+                OUString sValue;
+                sal_Int16 nValue;
+                xPropertySet->getPropertyValue("CurrentPresentation") >>= sValue;
+                CPPUNIT_ASSERT_EQUAL(OUString("above"), sValue);
+                xPropertySet->getPropertyValue("SourceName") >>= sValue;
+                CPPUNIT_ASSERT_EQUAL(OUString("Ref_Table0_full"), sValue);
+                xPropertySet->getPropertyValue("SequenceNumber") >>= nValue;
+                CPPUNIT_ASSERT_EQUAL(sal_Int16(0), nValue);
+                break;
+            }
+            default:
+                break;
+        }
+        ++nIndex;
+    }
+    CPPUNIT_ASSERT_EQUAL(sal_uInt16(8), nIndex);
+}
+
+DECLARE_OOXMLEXPORT_TEST( testTableCrossReferenceCustomFormat, "table_cross_reference_custom_format.odt" )
+{
+    // tdf#42346: Cross references to tables were not saved
+    // Check also captions with custom formatting
+    if (!mbExported)
+        return;
+
+    // Check whether we have all the neccessary bookmarks exported and imported back
+    uno::Reference<text::XBookmarksSupplier> xBookmarksSupplier(mxComponent, uno::UNO_QUERY);
+    uno::Reference<container::XIndexAccess> xBookmarksByIdx(xBookmarksSupplier->getBookmarks(), uno::UNO_QUERY);
+    CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(16), xBookmarksByIdx->getCount());
+    uno::Reference<container::XNameAccess> xBookmarksByName(xBookmarksSupplier->getBookmarks(), uno::UNO_QUERY);
+    CPPUNIT_ASSERT(xBookmarksByName->hasByName("Ref_Table0_full"));
+    CPPUNIT_ASSERT(xBookmarksByName->hasByName("Ref_Table0_label_and_number"));
+    CPPUNIT_ASSERT(xBookmarksByName->hasByName("Ref_Table0_caption_only"));
+    CPPUNIT_ASSERT(xBookmarksByName->hasByName("Ref_Table0_number_only"));
+    CPPUNIT_ASSERT(xBookmarksByName->hasByName("Ref_Table1_full"));
+    CPPUNIT_ASSERT(xBookmarksByName->hasByName("Ref_Table1_label_and_number"));
+    CPPUNIT_ASSERT(xBookmarksByName->hasByName("Ref_Table1_caption_only"));
+    CPPUNIT_ASSERT(xBookmarksByName->hasByName("Ref_Table1_number_only"));
+    CPPUNIT_ASSERT(xBookmarksByName->hasByName("Ref_Table2_full"));
+    CPPUNIT_ASSERT(xBookmarksByName->hasByName("Ref_Table2_label_and_number"));
+    CPPUNIT_ASSERT(xBookmarksByName->hasByName("Ref_Table2_caption_only"));
+    CPPUNIT_ASSERT(xBookmarksByName->hasByName("Ref_Table2_number_only"));
+    CPPUNIT_ASSERT(xBookmarksByName->hasByName("Ref_Table3_full"));
+    CPPUNIT_ASSERT(xBookmarksByName->hasByName("Ref_Table3_label_and_number"));
+    CPPUNIT_ASSERT(xBookmarksByName->hasByName("Ref_Table3_caption_only"));
+    CPPUNIT_ASSERT(xBookmarksByName->hasByName("Ref_Table3_number_only"));
+
+    // Check bookmark text ranges
+    // First table's caption
+    {
+        uno::Reference<text::XTextContent> xContent(xBookmarksByName->getByName("Ref_Table0_full"), uno::UNO_QUERY);
+        uno::Reference<text::XTextRange> xRange(xContent->getAnchor(), uno::UNO_QUERY);
+        CPPUNIT_ASSERT_EQUAL(OUString("1. Table: Table caption"), xRange->getString());
+    }
+    {
+        uno::Reference<text::XTextContent> xContent(xBookmarksByName->getByName("Ref_Table0_label_and_number"), uno::UNO_QUERY);
+        uno::Reference<text::XTextRange> xRange(xContent->getAnchor(), uno::UNO_QUERY);
+        CPPUNIT_ASSERT_EQUAL(OUString("1. Table"), xRange->getString());
+    }
+    {
+        uno::Reference<text::XTextContent> xContent(xBookmarksByName->getByName("Ref_Table0_caption_only"), uno::UNO_QUERY);
+        uno::Reference<text::XTextRange> xRange(xContent->getAnchor(), uno::UNO_QUERY);
+        CPPUNIT_ASSERT_EQUAL(OUString("Table caption"), xRange->getString());
+    }
+    {
+        uno::Reference<text::XTextContent> xContent(xBookmarksByName->getByName("Ref_Table0_number_only"), uno::UNO_QUERY);
+        uno::Reference<text::XTextRange> xRange(xContent->getAnchor(), uno::UNO_QUERY);
+        CPPUNIT_ASSERT_EQUAL(OUString("1"), xRange->getString());
+    }
+    // Second table's caption
+    {
+        uno::Reference<text::XTextContent> xContent(xBookmarksByName->getByName("Ref_Table1_full"), uno::UNO_QUERY);
+        uno::Reference<text::XTextRange> xRange(xContent->getAnchor(), uno::UNO_QUERY);
+        CPPUNIT_ASSERT_EQUAL(OUString("2. TableTable caption"), xRange->getString());
+    }
+    {
+        uno::Reference<text::XTextContent> xContent(xBookmarksByName->getByName("Ref_Table1_label_and_number"), uno::UNO_QUERY);
+        uno::Reference<text::XTextRange> xRange(xContent->getAnchor(), uno::UNO_QUERY);
+        CPPUNIT_ASSERT_EQUAL(OUString("2. Table"), xRange->getString());
+    }
+    {
+        uno::Reference<text::XTextContent> xContent(xBookmarksByName->getByName("Ref_Table1_caption_only"), uno::UNO_QUERY);
+        uno::Reference<text::XTextRange> xRange(xContent->getAnchor(), uno::UNO_QUERY);
+        CPPUNIT_ASSERT_EQUAL(OUString("Table caption"), xRange->getString());
+    }
+    {
+        uno::Reference<text::XTextContent> xContent(xBookmarksByName->getByName("Ref_Table1_number_only"), uno::UNO_QUERY);
+        uno::Reference<text::XTextRange> xRange(xContent->getAnchor(), uno::UNO_QUERY);
+        CPPUNIT_ASSERT_EQUAL(OUString("2"), xRange->getString());
+    }
+    // Third table's caption
+    {
+        uno::Reference<text::XTextContent> xContent(xBookmarksByName->getByName("Ref_Table2_full"), uno::UNO_QUERY);
+        uno::Reference<text::XTextRange> xRange(xContent->getAnchor(), uno::UNO_QUERY);
+        CPPUNIT_ASSERT_EQUAL(OUString("3) Table Table caption"), xRange->getString());
+    }
+    {
+        uno::Reference<text::XTextContent> xContent(xBookmarksByName->getByName("Ref_Table2_label_and_number"), uno::UNO_QUERY);
+        uno::Reference<text::XTextRange> xRange(xContent->getAnchor(), uno::UNO_QUERY);
+        CPPUNIT_ASSERT_EQUAL(OUString("3) Table"), xRange->getString());
+    }
+    {
+        uno::Reference<text::XTextContent> xContent(xBookmarksByName->getByName("Ref_Table2_caption_only"), uno::UNO_QUERY);
+        uno::Reference<text::XTextRange> xRange(xContent->getAnchor(), uno::UNO_QUERY);
+        CPPUNIT_ASSERT_EQUAL(OUString("Table caption"), xRange->getString());
+    }
+    {
+        uno::Reference<text::XTextContent> xContent(xBookmarksByName->getByName("Ref_Table2_number_only"), uno::UNO_QUERY);
+        uno::Reference<text::XTextRange> xRange(xContent->getAnchor(), uno::UNO_QUERY);
+        CPPUNIT_ASSERT_EQUAL(OUString("3"), xRange->getString());
+    }
+    // Fourth table's caption
+    {
+        uno::Reference<text::XTextContent> xContent(xBookmarksByName->getByName("Ref_Table3_full"), uno::UNO_QUERY);
+        uno::Reference<text::XTextRange> xRange(xContent->getAnchor(), uno::UNO_QUERY);
+        CPPUNIT_ASSERT_EQUAL(OUString("Table 4- Table caption"), xRange->getString());
+    }
+    {
+        uno::Reference<text::XTextContent> xContent(xBookmarksByName->getByName("Ref_Table3_label_and_number"), uno::UNO_QUERY);
+        uno::Reference<text::XTextRange> xRange(xContent->getAnchor(), uno::UNO_QUERY);
+        CPPUNIT_ASSERT_EQUAL(OUString("Table 4"), xRange->getString());
+    }
+    {
+        uno::Reference<text::XTextContent> xContent(xBookmarksByName->getByName("Ref_Table3_caption_only"), uno::UNO_QUERY);
+        uno::Reference<text::XTextRange> xRange(xContent->getAnchor(), uno::UNO_QUERY);
+        CPPUNIT_ASSERT_EQUAL(OUString("Table caption"), xRange->getString());
+    }
+    {
+        uno::Reference<text::XTextContent> xContent(xBookmarksByName->getByName("Ref_Table3_number_only"), uno::UNO_QUERY);
+        uno::Reference<text::XTextRange> xRange(xContent->getAnchor(), uno::UNO_QUERY);
+        CPPUNIT_ASSERT_EQUAL(OUString("4"), xRange->getString());
+    }
+}
+
+DECLARE_OOXMLEXPORT_TEST( testObjectCrossReference, "object_cross_reference.odt" )
+{
+    // tdf#42346: Cross references to objects were not saved
+    // MSO uses simple bookmarks for referencing table caption, so we do the same by export
+    if (!mbExported)
+        return;
+
+    // Check whether we have all the neccessary bookmarks exported and imported back
+    uno::Reference<text::XBookmarksSupplier> xBookmarksSupplier(mxComponent, uno::UNO_QUERY);
+    uno::Reference<container::XIndexAccess> xBookmarksByIdx(xBookmarksSupplier->getBookmarks(), uno::UNO_QUERY);
+    CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(15), xBookmarksByIdx->getCount());
+    uno::Reference<container::XNameAccess> xBookmarksByName(xBookmarksSupplier->getBookmarks(), uno::UNO_QUERY);
+    CPPUNIT_ASSERT(xBookmarksByName->hasByName("Ref_Drawing0_full"));
+    CPPUNIT_ASSERT(xBookmarksByName->hasByName("Ref_Drawing0_label_and_number"));
+    CPPUNIT_ASSERT(xBookmarksByName->hasByName("Ref_Drawing0_caption_only"));
+    CPPUNIT_ASSERT(xBookmarksByName->hasByName("Ref_Drawing0_number_only"));
+    CPPUNIT_ASSERT(xBookmarksByName->hasByName("Ref_Drawing1_full"));
+
+    CPPUNIT_ASSERT(xBookmarksByName->hasByName("Ref_Illustration0_full"));
+    CPPUNIT_ASSERT(xBookmarksByName->hasByName("Ref_Illustration0_label_and_number"));
+    CPPUNIT_ASSERT(xBookmarksByName->hasByName("Ref_Illustration0_caption_only"));
+    CPPUNIT_ASSERT(xBookmarksByName->hasByName("Ref_Illustration0_number_only"));
+    CPPUNIT_ASSERT(xBookmarksByName->hasByName("Ref_Illustration1_caption_only"));
+
+    CPPUNIT_ASSERT(xBookmarksByName->hasByName("Ref_Text0_full"));
+    CPPUNIT_ASSERT(xBookmarksByName->hasByName("Ref_Text0_label_and_number"));
+    CPPUNIT_ASSERT(xBookmarksByName->hasByName("Ref_Text0_caption_only"));
+    CPPUNIT_ASSERT(xBookmarksByName->hasByName("Ref_Text0_number_only"));
+    CPPUNIT_ASSERT(xBookmarksByName->hasByName("Ref_Text1_label_and_number"));
+
+    // Check bookmark text ranges
+    // Cross references to shapes
+    {
+        uno::Reference<text::XTextContent> xContent(xBookmarksByName->getByName("Ref_Drawing0_full"), uno::UNO_QUERY);
+        uno::Reference<text::XTextRange> xRange(xContent->getAnchor(), uno::UNO_QUERY);
+        CPPUNIT_ASSERT_EQUAL(OUString("Drawing 1: A rectangle"), xRange->getString());
+    }
+    {
+        uno::Reference<text::XTextContent> xContent(xBookmarksByName->getByName("Ref_Drawing0_label_and_number"), uno::UNO_QUERY);
+        uno::Reference<text::XTextRange> xRange(xContent->getAnchor(), uno::UNO_QUERY);
+        CPPUNIT_ASSERT_EQUAL(OUString("Drawing 1"), xRange->getString());
+    }
+    {
+        uno::Reference<text::XTextContent> xContent(xBookmarksByName->getByName("Ref_Drawing0_caption_only"), uno::UNO_QUERY);
+        uno::Reference<text::XTextRange> xRange(xContent->getAnchor(), uno::UNO_QUERY);
+        CPPUNIT_ASSERT_EQUAL(OUString("A rectangle"), xRange->getString());
+    }
+    {
+        uno::Reference<text::XTextContent> xContent(xBookmarksByName->getByName("Ref_Drawing0_number_only"), uno::UNO_QUERY);
+        uno::Reference<text::XTextRange> xRange(xContent->getAnchor(), uno::UNO_QUERY);
+        CPPUNIT_ASSERT_EQUAL(OUString("1"), xRange->getString());
+    }
+    {
+        uno::Reference<text::XTextContent> xContent(xBookmarksByName->getByName("Ref_Drawing1_full"), uno::UNO_QUERY);
+        uno::Reference<text::XTextRange> xRange(xContent->getAnchor(), uno::UNO_QUERY);
+        CPPUNIT_ASSERT_EQUAL(OUString("Drawing 2: a circle"), xRange->getString());
+    }
+
+    // Cross references to pictures
+    {
+        uno::Reference<text::XTextContent> xContent(xBookmarksByName->getByName("Ref_Illustration0_full"), uno::UNO_QUERY);
+        uno::Reference<text::XTextRange> xRange(xContent->getAnchor(), uno::UNO_QUERY);
+        CPPUNIT_ASSERT_EQUAL(OUString("Illustration 1: A picture"), xRange->getString());
+    }
+    {
+        uno::Reference<text::XTextContent> xContent(xBookmarksByName->getByName("Ref_Illustration0_label_and_number"), uno::UNO_QUERY);
+        uno::Reference<text::XTextRange> xRange(xContent->getAnchor(), uno::UNO_QUERY);
+        CPPUNIT_ASSERT_EQUAL(OUString("Illustration 1"), xRange->getString());
+    }
+    {
+        uno::Reference<text::XTextContent> xContent(xBookmarksByName->getByName("Ref_Illustration0_caption_only"), uno::UNO_QUERY);
+        uno::Reference<text::XTextRange> xRange(xContent->getAnchor(), uno::UNO_QUERY);
+        CPPUNIT_ASSERT_EQUAL(OUString("A picture"), xRange->getString());
+    }
+    {
+        uno::Reference<text::XTextContent> xContent(xBookmarksByName->getByName("Ref_Illustration0_number_only"), uno::UNO_QUERY);
+        uno::Reference<text::XTextRange> xRange(xContent->getAnchor(), uno::UNO_QUERY);
+        CPPUNIT_ASSERT_EQUAL(OUString("1"), xRange->getString());
+    }
+    {
+        uno::Reference<text::XTextContent> xContent(xBookmarksByName->getByName("Ref_Illustration1_caption_only"), uno::UNO_QUERY);
+        uno::Reference<text::XTextRange> xRange(xContent->getAnchor(), uno::UNO_QUERY);
+        CPPUNIT_ASSERT_EQUAL(OUString("an other image"), xRange->getString());
+    }
+
+    // Cross references to text frames
+    {
+        uno::Reference<text::XTextContent> xContent(xBookmarksByName->getByName("Ref_Text0_full"), uno::UNO_QUERY);
+        uno::Reference<text::XTextRange> xRange(xContent->getAnchor(), uno::UNO_QUERY);
+        CPPUNIT_ASSERT_EQUAL(OUString("Text 1: A frame"), xRange->getString());
+    }
+    {
+        uno::Reference<text::XTextContent> xContent(xBookmarksByName->getByName("Ref_Text0_label_and_number"), uno::UNO_QUERY);
+        uno::Reference<text::XTextRange> xRange(xContent->getAnchor(), uno::UNO_QUERY);
+        CPPUNIT_ASSERT_EQUAL(OUString("Text 1"), xRange->getString());
+    }
+    {
+        uno::Reference<text::XTextContent> xContent(xBookmarksByName->getByName("Ref_Text0_caption_only"), uno::UNO_QUERY);
+        uno::Reference<text::XTextRange> xRange(xContent->getAnchor(), uno::UNO_QUERY);
+        CPPUNIT_ASSERT_EQUAL(OUString("A frame"), xRange->getString());
+    }
+    {
+        uno::Reference<text::XTextContent> xContent(xBookmarksByName->getByName("Ref_Text0_number_only"), uno::UNO_QUERY);
+        uno::Reference<text::XTextRange> xRange(xContent->getAnchor(), uno::UNO_QUERY);
+        CPPUNIT_ASSERT_EQUAL(OUString("1"), xRange->getString());
+    }
+    {
+        uno::Reference<text::XTextContent> xContent(xBookmarksByName->getByName("Ref_Text1_label_and_number"), uno::UNO_QUERY);
+        uno::Reference<text::XTextRange> xRange(xContent->getAnchor(), uno::UNO_QUERY);
+        CPPUNIT_ASSERT_EQUAL(OUString("Text 2"), xRange->getString());
+    }
+}
+
 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 dc32dd36d8fe..86b468198ed9 100644
--- a/sw/source/filter/ww8/attributeoutputbase.hxx
+++ b/sw/source/filter/ww8/attributeoutputbase.hxx
@@ -169,10 +169,10 @@ public:
     virtual void EmptyParagraph() = 0;
 
     /// Start of the text run.
-    virtual void StartRun( const SwRedlineData* pRedlineData, bool bSingleEmptyRun = false ) = 0;
+    virtual void StartRun( const SwRedlineData* pRedlineData, sal_Int32 nPos, bool bSingleEmptyRun = false ) = 0;
 
     /// End of the text run.
-    virtual void EndRun( const SwTextNode* pNode, sal_Int32 nPos ) = 0;
+    virtual void EndRun( const SwTextNode* pNode, sal_Int32 nPos, bool bLastRun = false ) = 0;
 
     /// Called before we start outputting the attributes.
     virtual void StartRunProperties() = 0;
@@ -209,7 +209,8 @@ public:
 
     virtual void FieldVanish( const OUString& rText, ww::eField eType ) = 0;
 
-    virtual void GenerateBookmarksForSequenceField(const SwTextNode& rNode, SwWW8AttrIter& rAttrIter) = 0;
+    /// MSO uses bookmarks to reference sequence fields, so we need to generate these additional bookmarks during export
+    void GenerateBookmarksForSequenceField(const SwTextNode& rNode, SwWW8AttrIter& rAttrIter);
 
     void StartTOX( const SwSection& rSect );
 
@@ -625,6 +626,9 @@ protected:
 
     virtual bool AnalyzeURL( const OUString& rUrl, const OUString& rTarget, OUString* pLinkURL, OUString* pMark );
 
+    /// Insert a bookmark inside the currently processed parargaph.
+    virtual void WriteBookmarkInActParagraph( const OUString& rName, sal_Int32 nFirstRunPos, sal_Int32 nLastRunPos ) = 0;
+
     ww8::GridColsPtr GetGridCols( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner );
     ww8::WidthsPtr   GetColumnWidths( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner );
 
diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx b/sw/source/filter/ww8/docxattributeoutput.cxx
index e8cdfc86182c..76de5cabb222 100644
--- a/sw/source/filter/ww8/docxattributeoutput.cxx
+++ b/sw/source/filter/ww8/docxattributeoutput.cxx
@@ -117,8 +117,6 @@
 #include <IDocumentSettingAccess.hxx>
 #include <IDocumentStylePoolAccess.hxx>
 #include <IDocumentRedlineAccess.hxx>
-#include <IDocumentFieldsAccess.hxx>
-#include <reffld.hxx>
 
 #include <osl/file.hxx>
 #include <vcl/embeddedfontshelper.hxx>
@@ -603,10 +601,9 @@ void DocxAttributeOutput::EndParagraph( ww8::WW8TableNodeInfoInner::Pointer_t pT
     if( !m_rExport.SdrExporter().IsDMLAndVMLDrawingOpen() )
         m_bParagraphOpened = false;
 
-    // Clear gererated bookmarks
-    m_aBookmarksWithPosStart.clear();
-    m_aBookmarksWithPosEnd.clear();
-
+    // Clear bookmarks of the current paragraph
+    m_aBookmarksOfParagraphStart.clear();
+    m_aBookmarksOfParagraphEnd.clear();
 }
 
 void DocxAttributeOutput::WriteSdtBlock( sal_Int32& nSdtPrToken,
@@ -1103,7 +1100,7 @@ bool DocxAttributeOutput::IsFlyProcessingPostponed()
     return m_bPostponedProcessingFly;
 }
 
-void DocxAttributeOutput::StartRun( const SwRedlineData* pRedlineData, bool /*bSingleEmptyRun*/ )
+void DocxAttributeOutput::StartRun( const SwRedlineData* pRedlineData, sal_Int32 /*nPos*/, bool /*bSingleEmptyRun*/ )
 {
     // Don't start redline data here, possibly there is a hyperlink later, and
     // that has to be started first.
@@ -1122,7 +1119,7 @@ void DocxAttributeOutput::StartRun( const SwRedlineData* pRedlineData, bool /*bS
     m_pSerializer->mark(Tag_StartRun_3); // let's call it "postponed text"
 }
 
-void DocxAttributeOutput::EndRun(const SwTextNode* pNode, sal_Int32 nPos)
+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
@@ -1401,9 +1398,9 @@ void DocxAttributeOutput::DoWriteBookmarkTagEnd(const OUString & bookmarkName)
     }
 }
 
-void DocxAttributeOutput::DoWriteBookmarkStartIfExist(sal_Int32 nPos)
+void DocxAttributeOutput::DoWriteBookmarkStartIfExist(sal_Int32 nRunPos)
 {
-    auto aRange = m_aBookmarksWithPosStart.equal_range(nPos);
+    auto aRange = m_aBookmarksOfParagraphStart.equal_range(nRunPos);
     for( auto aIter = aRange.first; aIter != aRange.second; ++aIter)
     {
         DoWriteBookmarkTagStart(aIter->second);
@@ -1413,9 +1410,9 @@ void DocxAttributeOutput::DoWriteBookmarkStartIfExist(sal_Int32 nPos)
     }
 }
 
-void DocxAttributeOutput::DoWriteBookmarkEndIfExist(sal_Int32 nPos)
+void DocxAttributeOutput::DoWriteBookmarkEndIfExist(sal_Int32 nRunPos)
 {
-    auto aRange = m_aBookmarksWithPosEnd.equal_range(nPos);
+    auto aRange = m_aBookmarksOfParagraphEnd.equal_range(nRunPos);
     for( auto aIter = aRange.first; aIter != aRange.second; ++aIter)
     {
         // Get the id of the bookmark
@@ -2524,7 +2521,7 @@ void DocxAttributeOutput::StartRuby( const SwTextNode& rNode, sal_Int32 nPos, co
     m_pSerializer->endElementNS( XML_w, XML_rubyPr );
 
     m_pSerializer->startElementNS( XML_w, XML_rt, FSEND );
-    StartRun( nullptr );
+    StartRun( nullptr, nPos );
     StartRunProperties( );
     SwWW8AttrIter aAttrIt( m_rExport, rNode );
     aAttrIt.OutAttr( nPos, true );
@@ -2540,7 +2537,7 @@ void DocxAttributeOutput::StartRuby( const SwTextNode& rNode, sal_Int32 nPos, co
     m_pSerializer->endElementNS( XML_w, XML_rt );
 
     m_pSerializer->startElementNS( XML_w, XML_rubyBase, FSEND );
-    StartRun( nullptr );
+    StartRun( nullptr, nPos );
 }
 
 void DocxAttributeOutput::EndRuby(const SwTextNode& rNode, sal_Int32 nPos)
@@ -2549,7 +2546,7 @@ void DocxAttributeOutput::EndRuby(const SwTextNode& rNode, sal_Int32 nPos)
     EndRun( &rNode, nPos );
     m_pSerializer->endElementNS( XML_w, XML_rubyBase );
     m_pSerializer->endElementNS( XML_w, XML_ruby );
-    StartRun(nullptr); // open Run again so OutputTextNode loop can close it
+    StartRun(nullptr, nPos); // open Run again so OutputTextNode loop can close it
 }
 
 bool DocxAttributeOutput::AnalyzeURL( const OUString& rUrl, const OUString& rTarget, OUString* pLinkURL, OUString* pMark )
@@ -2576,6 +2573,12 @@ bool DocxAttributeOutput::AnalyzeURL( const OUString& rUrl, const OUString& rTar
     return bBookMarkOnly;
 }
 
+void DocxAttributeOutput::WriteBookmarkInActParagraph( const OUString& rName, sal_Int32 nFirstRunPos, sal_Int32 nLastRunPos )
+{
+    m_aBookmarksOfParagraphStart.insert(std::pair<sal_Int32, OUString>(nFirstRunPos, rName));
+    m_aBookmarksOfParagraphEnd.insert(std::pair<sal_Int32, OUString>(nLastRunPos, rName));
+}
+
 bool DocxAttributeOutput::StartURL( const OUString& rUrl, const OUString& rTarget )
 {
     OUString sMark;
@@ -6988,176 +6991,6 @@ bool DocxAttributeOutput::PlaceholderField( const SwField* pField )
     return false; // do not expand
 }
 
-void DocxAttributeOutput::GenerateBookmarksForSequenceField(const SwTextNode& rNode, SwWW8AttrIter& rAttrIter)
-{
-    if (const SwpHints* pTextAttrs = rNode.GetpSwpHints())
-    {
-        for( size_t i = 0; i < pTextAttrs->Count(); ++i )
-        {
-            const SwTextAttr* pHt = pTextAttrs->Get(i);
-            if (pHt->GetAttr().Which() == RES_TXTATR_FIELD)
-            {
-                const SwFormatField& rField = static_cast<const SwFormatField&>(pHt->GetAttr());
-                const SwField* pField = rField.GetField();
-                // Need to have bookmarks only for sequence fields
-                if (pField && pField->GetTyp()->Which() == RES_SETEXPFLD && pField->GetSubType() == nsSwGetSetExpType::GSE_SEQ)
-                {
-                    const sal_uInt16 nSeqFieldNumber = static_cast<const SwSetExpField*>(pField)->GetSeqNumber();
-                    const OUString sObjectName = static_cast<const SwSetExpFieldType*>(pField->GetTyp())->GetName();
-                    const SwFieldTypes* pFieldTypes = m_rExport.m_pDoc->getIDocumentFieldsAccess().GetFieldTypes();
-                    bool bHaveFullBkm = false;
-                    bool bHaveLabelAndNumberBkm = false;
-                    bool bHaveCaptionOnlyBkm = false;
-                    bool bHaveNumberOnlyBkm = false;
-                    bool bRunSplittedAtSep = false;
-                    for( auto pFieldType : *pFieldTypes )
-                    {
-                        if( RES_GETREFFLD == pFieldType->Which() )
-                        {
-                            SwIterator<SwFormatField,SwFieldType> aIter( *pFieldType );
-                            for( SwFormatField* pFormatField = aIter.First(); pFormatField; pFormatField = aIter.Next() )
-                            {
-                                SwGetRefField* pRefField = static_cast<SwGetRefField*>(pFormatField->GetField());
-                                // If we have a reference to the current sequence field
-                                if(pRefField->GetSeqNo() == nSeqFieldNumber && pRefField->GetSetRefName() == sObjectName)
-                                {
-                                    // Need to create a seperate run for separator character
-                                    SwWW8AttrIter aLocalAttrIter( m_rExport, rNode );
-                                    const OUString aText = rNode.GetText();
-                                    const sal_Int32 nCategoryStart = aText.indexOf(pRefField->GetSetRefName());
-                                    const sal_Int32 nPosBeforeSeparator = std::max(nCategoryStart, pHt->GetStart());
-                                    bool bCategoryFirst = nCategoryStart < pHt->GetStart();
-                                    sal_Int32 nSeparatorPos = 0;
-                                    if (bCategoryFirst)
-                                    {
-                                        nSeparatorPos = aLocalAttrIter.WhereNext();
-                                        while (nSeparatorPos <= nPosBeforeSeparator)
-                                        {
-                                            aLocalAttrIter.NextPos();
-                                            nSeparatorPos = aLocalAttrIter.WhereNext();
-                                        }
-                                    }
-                                    else
-                                    {
-                                        nSeparatorPos = nCategoryStart + pRefField->GetSetRefName().getLength();
-                                    }
-                                    sal_Int32 nRefTextPos = 0;
-                                    if(nSeparatorPos < aText.getLength())
-                                    {
-                                        nRefTextPos = SwGetExpField::GetReferenceTextPos(pHt->GetFormatField(), *m_rExport.m_pDoc, nSeparatorPos);
-                                        if(nRefTextPos != nSeparatorPos)
-                                        {
-                                            if(!bRunSplittedAtSep)
-                                            {
-                                                if(!bCategoryFirst)
-                                                    rAttrIter.SplitRun(nSeparatorPos);
-                                                rAttrIter.SplitRun(nRefTextPos);
-                                                bRunSplittedAtSep = true;
-                                            }
-                                            if(!bCategoryFirst)
-                                                aLocalAttrIter.SplitRun(nSeparatorPos);
-                                            aLocalAttrIter.SplitRun(nRefTextPos);
-                                        }
-                                        else if (bCategoryFirst)
-                                        {
-                                            if(!bRunSplittedAtSep)
-                                            {
-                                                rAttrIter.SplitRun(nSeparatorPos);
-                                                bRunSplittedAtSep = true;
-                                            }
-                                            aLocalAttrIter.SplitRun(nSeparatorPos);
-                                        }
-                                    }
-                                    // Generate bookmarks on the right position
-                                    OUString sName("Ref_" + pRefField->GetSetRefName());
-                                    sName += OUString::number(pRefField->GetSeqNo());
-                                    switch (pRefField->GetFormat())
-                                    {
-                                        case REF_PAGE:
-                                        case REF_PAGE_PGDESC:
-                                        case REF_CONTENT:
-                                        case REF_UPDOWN:
-                                            sName += "_full";
-                                            if(!bHaveFullBkm)
-                                            {
-                                                sal_Int32 nLastAttrStart = 0;
-                                                sal_Int32 nActAttr = aLocalAttrIter.WhereNext();
-                                                while (nActAttr < rNode.GetText().getLength())
-                                                {
-                                                    nLastAttrStart = nActAttr;
-                                                    aLocalAttrIter.NextPos();
-                                                    nActAttr = aLocalAttrIter.WhereNext();
-                                                }
-                                                WriteBookmarks_Impl( sName, std::min(nCategoryStart, pHt->GetStart()), nLastAttrStart );
-                                                bHaveFullBkm = true;
-                                            }
-                                            break;
-                                        case REF_ONLYNUMBER:
-                                        {
-                                            sName += "_label_and_number";
-                                            if(!bHaveLabelAndNumberBkm)
-                                            {
-                                                if(bCategoryFirst)
-                                                    WriteBookmarks_Impl( sName, std::min(nCategoryStart, pHt->GetStart()), std::max(nCategoryStart, pHt->GetStart()) );
-                                                else
-                                                {
-                                                    // Find the last run which contains category text
-                                                    SwWW8AttrIter aLocalAttrIter2( m_rExport, rNode );
-                                                    sal_Int32 nCatLastRun = 0;
-                                                    sal_Int32 nNextAttr = aLocalAttrIter2.WhereNext();
-                                                    while (nNextAttr < nSeparatorPos)
-                                                    {
-                                                        nCatLastRun = nNextAttr;
-                                                        aLocalAttrIter2.NextPos();
-                                                        nNextAttr = aLocalAttrIter2.WhereNext();
-                                                    }
-                                                    WriteBookmarks_Impl( sName, pHt->GetStart(), nCatLastRun );
-                                                }
-                                                bHaveLabelAndNumberBkm = true;
-                                            }
-                                            break;
-                                        }
-                                        case REF_ONLYCAPTION:
-                                        {
-                                            sName += "_caption_only";
-                                            if(!bHaveCaptionOnlyBkm)
-                                            {
-                                                // Find last run
-                                                sal_Int32 nLastAttrStart = 0;
-                                                sal_Int32 nActAttr = aLocalAttrIter.WhereNext();
-                                                while (nActAttr < rNode.GetText().getLength())
-                                                {
-                                                    nLastAttrStart = nActAttr;
-                                                    aLocalAttrIter.NextPos();
-                                                    nActAttr = aLocalAttrIter.WhereNext();
-                                                }
-                                                WriteBookmarks_Impl( sName, nRefTextPos, nLastAttrStart );
-                                                bHaveCaptionOnlyBkm = true;
-                                            }
-                                            break;
-                                        }
-                                        case REF_ONLYSEQNO:
-                                        {
-                                            sName += "_number_only";
-                                            if(!bHaveNumberOnlyBkm)
-                                            {
-                                                WriteBookmarks_Impl( sName, pHt->GetStart(), pHt->GetStart() );
-                                                bHaveNumberOnlyBkm = true;
-                                            }
-                                            break;
-                                        }
-                                    }
-                                }
-                            }
-                        }
-                    }
-                    return;
-                }
-            }
-        }
-    }
-}
-
 void DocxAttributeOutput::WritePendingPlaceholder()
 {
     if( pendingPlaceholder == nullptr )
@@ -7264,12 +7097,6 @@ void DocxAttributeOutput::WriteBookmarks_Impl( std::vector< OUString >& rStarts,
     rEnds.clear();
 }
 
-void DocxAttributeOutput::WriteBookmarks_Impl( const OUString& rName, sal_Int32 nWithStartPos, sal_Int32 nWithEndPos )
-{
-    m_aBookmarksWithPosStart.insert(std::pair<sal_Int32, OUString>(nWithStartPos, rName));
-    m_aBookmarksWithPosEnd.insert(std::pair<sal_Int32, OUString>(nWithEndPos, rName));
-}
-
 void DocxAttributeOutput::WriteAnnotationMarks_Impl( std::vector< OUString >& rStarts,
         std::vector< OUString >& rEnds )
 {
diff --git a/sw/source/filter/ww8/docxattributeoutput.hxx b/sw/source/filter/ww8/docxattributeoutput.hxx
index 64fa4238e617..c76b8a671f2d 100644
--- a/sw/source/filter/ww8/docxattributeoutput.hxx
+++ b/sw/source/filter/ww8/docxattributeoutput.hxx
@@ -163,10 +163,10 @@ public:
     virtual void EndParagraphProperties(const SfxItemSet& rParagraphMarkerProperties, const SwRedlineData* pRedlineData, const SwRedlineData* pRedlineParagraphMarkerDeleted, const SwRedlineData* pRedlineParagraphMarkerInserted) override;
 
     /// Start of the text run.
-    virtual void StartRun( const SwRedlineData* pRedlineData, bool bSingleEmptyRun = false ) override;
+    virtual void StartRun( const SwRedlineData* pRedlineData, sal_Int32 nPos, bool bSingleEmptyRun = false ) override;
 
     /// End of the text run.
-    virtual void EndRun(const SwTextNode* pNode, sal_Int32 nPos) override;
+    virtual void EndRun(const SwTextNode* pNode, sal_Int32 nPos, bool bLastRun = false) override;
 
     /// Called before we start outputting the attributes.
     virtual void StartRunProperties() override;
@@ -370,7 +370,6 @@ public:
     void WriteFormData_Impl( const ::sw::mark::IFieldmark& rFieldmark );
 
     void WriteBookmarks_Impl( std::vector< OUString >& rStarts, std::vector< OUString >& rEnds );
-    void WriteBookmarks_Impl( const OUString& rName, sal_Int32 nWithStartPos, sal_Int32 nWithEndPos );
     void WriteAnnotationMarks_Impl( std::vector< OUString >& rStarts, std::vector< OUString >& rEnds );
     void PushRelIdCache();
     void PopRelIdCache();
@@ -682,6 +681,8 @@ protected:
 
     virtual bool AnalyzeURL( const OUString& rURL, const OUString& rTarget, OUString* pLinkURL, OUString* pMark ) override;
 
+    virtual void WriteBookmarkInActParagraph( const OUString& rName, sal_Int32 nFirstRunPos, sal_Int32 nLastRunPos ) override;
+
     /// Reference to the export, where to get the data from
     DocxExport &m_rExport;
 
@@ -697,8 +698,8 @@ private:
     void DoWriteBookmarkTagEnd(const OUString & bookmarkName);
     void DoWriteBookmarksStart();
     void DoWriteBookmarksEnd();
-    void DoWriteBookmarkStartIfExist(sal_Int32 nPos);
-    void DoWriteBookmarkEndIfExist(sal_Int32 nPos);
+    void DoWriteBookmarkStartIfExist(sal_Int32 nRunPos);
+    void DoWriteBookmarkEndIfExist(sal_Int32 nRunPos);
 
     void DoWritePermissionTagStart(const OUString & permission);
     void DoWritePermissionTagEnd(const OUString & permission);
@@ -730,7 +731,6 @@ private:
     void CmdField_Impl( const SwTextNode* pNode, sal_Int32 nPos, FieldInfos const & rInfos, bool bWriteRun );
     void EndField_Impl( const SwTextNode* pNode, sal_Int32 nPos, FieldInfos& rInfos );
     void DoWriteFieldRunProperties( const SwTextNode* pNode, sal_Int32 nPos, bool bWriteCombChars = false );
-    virtual void GenerateBookmarksForSequenceField(const SwTextNode& rNode, SwWW8AttrIter& rAttrIter) override;
 
     static void AddToAttrList( css::uno::Reference<sax_fastparser::FastAttributeList>& pAttrList, sal_Int32 nAttrName, const sal_Char* sAttrValue );
     static void AddToAttrList( css::uno::Reference<sax_fastparser::FastAttributeList>& pAttrList, sal_Int32 nArgs, ... );
@@ -788,9 +788,9 @@ private:
     std::vector<OUString> m_rBookmarksStart;
     std::vector<OUString> m_rBookmarksEnd;
 
-    /// Bookmarks with position to output
-    std::multimap<sal_Int32, OUString> m_aBookmarksWithPosStart;
-    std::multimap<sal_Int32, OUString> m_aBookmarksWithPosEnd;
+    /// Bookmarks of the current paragraph
+    std::multimap<sal_Int32, OUString> m_aBookmarksOfParagraphStart;
+    std::multimap<sal_Int32, OUString> m_aBookmarksOfParagraphEnd;
 
     /// Permissions to output
     std::vector<OUString> m_rPermissionsStart;
diff --git a/sw/source/filter/ww8/docxexport.cxx b/sw/source/filter/ww8/docxexport.cxx
index 3f62a6c56310..7e32fe727519 100644
--- a/sw/source/filter/ww8/docxexport.cxx
+++ b/sw/source/filter/ww8/docxexport.cxx
@@ -1442,7 +1442,7 @@ void DocxExport::WriteOutliner(const OutlinerParaObject& rParaObj, sal_uInt8 nTy
         sal_Int32 nAktPos = 0;
         const sal_Int32 nEnd = aStr.getLength();
         do {
-            AttrOutput().StartRun( nullptr );
+            AttrOutput().StartRun( nullptr, 0 );
             const sal_Int32 nNextAttr = std::min(aAttrIter.WhereNext(), nEnd);
             rtl_TextEncoding eNextChrSet = aAttrIter.GetNextCharSet();
 
diff --git a/sw/source/filter/ww8/rtfattributeoutput.cxx b/sw/source/filter/ww8/rtfattributeoutput.cxx
index ee3ff68665e7..880bf36f12f7 100644
--- a/sw/source/filter/ww8/rtfattributeoutput.cxx
+++ b/sw/source/filter/ww8/rtfattributeoutput.cxx
@@ -376,7 +376,7 @@ void RtfAttributeOutput::EndParagraphProperties(const SfxItemSet& /*rParagraphMa
     m_rExport.Strm().WriteCharPtr(m_aStyles.makeStringAndClear().getStr());
 }
 
-void RtfAttributeOutput::StartRun(const SwRedlineData* pRedlineData, bool bSingleEmptyRun)
+void RtfAttributeOutput::StartRun(const SwRedlineData* pRedlineData, sal_Int32 /*nPos*/, bool bSingleEmptyRun)
 {
     SAL_INFO("sw.rtf", OSL_THIS_FUNC << ", bSingleEmptyRun: " << bSingleEmptyRun);
 
@@ -391,7 +391,7 @@ void RtfAttributeOutput::StartRun(const SwRedlineData* pRedlineData, bool bSingl
     OSL_ENSURE(m_aRunText.getLength() == 0, "m_aRunText is not empty");
 }
 
-void RtfAttributeOutput::EndRun(const SwTextNode* /*pNode*/, sal_Int32 /*nPos*/)
+void RtfAttributeOutput::EndRun(const SwTextNode* /*pNode*/, sal_Int32 /*nPos*/, bool /*bLastRun*/)
 {
     m_aRun->append(SAL_NEWLINE_STRING);
     m_aRun.appendAndClear(m_aRunText);
diff --git a/sw/source/filter/ww8/rtfattributeoutput.hxx b/sw/source/filter/ww8/rtfattributeoutput.hxx
index 82e2817e1a03..9dfebef27a86 100644
--- a/sw/source/filter/ww8/rtfattributeoutput.hxx
+++ b/sw/source/filter/ww8/rtfattributeoutput.hxx
@@ -62,10 +62,10 @@ public:
     virtual void EndParagraphProperties(const SfxItemSet& rParagraphMarkerProperties, const SwRedlineData* pRedlineData, const SwRedlineData* pRedlineParagraphMarkerDeleted, const SwRedlineData* pRedlineParagraphMarkerInserted) override;
 
     /// Start of the text run.
-    virtual void StartRun(const SwRedlineData* pRedlineData, bool bSingleEmptyRun = false) override;
+    virtual void StartRun(const SwRedlineData* pRedlineData, sal_Int32 nPos, bool bSingleEmptyRun = false) override;
 
     /// End of the text run.
-    void EndRun(const SwTextNode* pNode, sal_Int32 nPos) override;
+    void EndRun(const SwTextNode* pNode, sal_Int32 nPos, bool bLastRun = false) override;
 
     /// Called before we start outputting the attributes.
     virtual void StartRunProperties() override;
@@ -217,7 +217,7 @@ public:
     void WriteBookmarks_Impl(std::vector< OUString >& rStarts, std::vector< OUString >& rEnds);
     void WriteAnnotationMarks_Impl(std::vector< OUString >& rStarts, std::vector< OUString >& rEnds);
     void WriteHeaderFooter_Impl(const SwFrameFormat& rFormat, bool bHeader, const sal_Char* pStr, bool bTitlepg);
-    void GenerateBookmarksForSequenceField(const SwTextNode& /*rNode*/, SwWW8AttrIter& /*rAttrIter*/) override {};
+    void WriteBookmarkInActParagraph( const OUString& /*rName*/, sal_Int32 /*nFirstRunPos*/, sal_Int32 /*nLastRunPos*/ ) override {};
 
 protected:
     /// Output frames - the implementation.
diff --git a/sw/source/filter/ww8/wrtw8nds.cxx b/sw/source/filter/ww8/wrtw8nds.cxx
index 33b67ea5e627..cbc0a777154f 100644
--- a/sw/source/filter/ww8/wrtw8nds.cxx
+++ b/sw/source/filter/ww8/wrtw8nds.cxx
@@ -975,6 +975,12 @@ bool WW8AttributeOutput::AnalyzeURL( const OUString& rUrl, const OUString& rTarg
     return bBookMarkOnly;
 }
 
+void WW8AttributeOutput::WriteBookmarkInActParagraph( const OUString& rName, sal_Int32 nFirstRunPos, sal_Int32 nLastRunPos )
+{
+    m_aBookmarksOfParagraphStart.insert(std::pair<sal_Int32, OUString>(nFirstRunPos, rName));
+    m_aBookmarksOfParagraphEnd.insert(std::pair<sal_Int32, OUString>(nLastRunPos, rName));
+}
+
 bool WW8AttributeOutput::StartURL( const OUString &rUrl, const OUString &rTarget )
 {
     INetURLObject aURL( rUrl );
@@ -2166,8 +2172,7 @@ void MSWordExportBase::OutputTextNode( const SwTextNode& rNode )
     }
 
     // Call this before write out fields and runs
-    if(GetExportFormat() == ExportFormat::DOCX)
-        AttrOutput().GenerateBookmarksForSequenceField(rNode, aAttrIter);
+    AttrOutput().GenerateBookmarksForSequenceField(rNode, aAttrIter);
 
     const OUString& aStr( rNode.GetText() );
 
@@ -2192,14 +2197,14 @@ void MSWordExportBase::OutputTextNode( const SwTextNode& rNode )
         sal_Int32 nNextAttr = GetNextPos( &aAttrIter, rNode, nAktPos );
         // Is this the only run in this paragraph and it's empty?
         bool bSingleEmptyRun = nAktPos == 0 && nNextAttr == 0;
-        AttrOutput().StartRun( pRedlineData, bSingleEmptyRun );
-
-        if( m_nTextTyp == TXT_FTN || m_nTextTyp == TXT_EDN )
-            AttrOutput().FootnoteEndnoteRefTag();
+        AttrOutput().StartRun( pRedlineData, nAktPos, bSingleEmptyRun );
 
         if( nNextAttr > nEnd )
             nNextAttr = nEnd;
 
+        if( m_nTextTyp == TXT_FTN || m_nTextTyp == TXT_EDN )
+            AttrOutput().FootnoteEndnoteRefTag();
+
         /*
             1) If there is a text node and an overlapping anchor, then write them in two different
             runs and not as part of the same run.
@@ -2461,9 +2466,9 @@ void MSWordExportBase::OutputTextNode( const SwTextNode& rNode )
 
         if( bPostponeWritingText && FLY_PROCESSED == nStateOfFlyFrame )
         {
-            AttrOutput().EndRun(&rNode, nAktPos);
+            AttrOutput().EndRun(&rNode, nAktPos, nNextAttr == nEnd);
             //write the postponed text run
-            AttrOutput().StartRun( pRedlineData, bSingleEmptyRun );
+            AttrOutput().StartRun( pRedlineData, nAktPos, bSingleEmptyRun );
             AttrOutput().SetAnchorIsLinkedToNode( false );
             AttrOutput().ResetFlyProcessingFlag();
             if (0 != nEnd)
@@ -2473,16 +2478,16 @@ void MSWordExportBase::OutputTextNode( const SwTextNode& rNode )
                 AttrOutput().EndRunProperties( pRedlineData );
             }
             AttrOutput().RunText( aSavedSnippet, eChrSet );
-            AttrOutput().EndRun(&rNode, nAktPos);
+            AttrOutput().EndRun(&rNode, nAktPos, nNextAttr == nEnd);
         }
         else if( bPostponeWritingText && !aSavedSnippet.isEmpty() )
         {
             //write the postponed text run
             AttrOutput().RunText( aSavedSnippet, eChrSet );
-            AttrOutput().EndRun(&rNode, nAktPos);
+            AttrOutput().EndRun(&rNode, nAktPos, nNextAttr == nEnd);
         }
         else
-            AttrOutput().EndRun(&rNode, nAktPos);
+            AttrOutput().EndRun(&rNode, nAktPos, nNextAttr == nEnd);
 
         nAktPos = nNextAttr;
         UpdatePosition( &aAttrIter, nAktPos, nEnd );
diff --git a/sw/source/filter/ww8/wrtww8.cxx b/sw/source/filter/ww8/wrtww8.cxx
index 85bf4ea3a312..8e8c02496560 100644
--- a/sw/source/filter/ww8/wrtww8.cxx
+++ b/sw/source/filter/ww8/wrtww8.cxx
@@ -1514,6 +1514,12 @@ void WW8Export::AppendBookmark( const OUString& rName )
     m_pBkmks->Append( nSttCP, rName );
 }
 
+void WW8Export::AppendBookmarkEndWithCorrection( const OUString& rName )
+{
+    sal_uLong nEndCP = Fc2Cp( Strm().Tell() );
+    m_pBkmks->Append( nEndCP - 1, rName );
+}
+
 boost::optional<SvxBrushItem> MSWordExportBase::getBackground()
 {
     boost::optional<SvxBrushItem> oRet;
diff --git a/sw/source/filter/ww8/wrtww8.hxx b/sw/source/filter/ww8/wrtww8.hxx
index ff25dedd1c3e..b5633010789a 100644
--- a/sw/source/filter/ww8/wrtww8.hxx
+++ b/sw/source/filter/ww8/wrtww8.hxx
@@ -1036,6 +1036,7 @@ public:
 
     virtual void AppendBookmarks( const SwTextNode& rNd, sal_Int32 nAktPos, sal_Int32 nLen ) override;
     virtual void AppendBookmark( const OUString& rName ) override;
+    void AppendBookmarkEndWithCorrection( const OUString& rName );
 
     virtual void AppendAnnotationMarks( const SwTextNode& rNd, sal_Int32 nAktPos, sal_Int32 nLen ) override;
 
diff --git a/sw/source/filter/ww8/ww8atr.cxx b/sw/source/filter/ww8/ww8atr.cxx
index 3250808165a8..33b1bc42ee66 100644
--- a/sw/source/filter/ww8/ww8atr.cxx
+++ b/sw/source/filter/ww8/ww8atr.cxx
@@ -981,6 +981,10 @@ void WW8AttributeOutput::EndParagraph( ww8::WW8TableNodeInfoInner::Pointer_t pTe
             m_rWW8Export.pO->clear();
         }
     }
+
+    // Clear bookmarks of the current paragraph
+    m_aBookmarksOfParagraphStart.clear();
+    m_aBookmarksOfParagraphEnd.clear();
 }
 
 void WW8AttributeOutput::StartRunProperties()
@@ -989,7 +993,7 @@ void WW8AttributeOutput::StartRunProperties()
     m_nFieldResults = pCurrentFields ? pCurrentFields->ResultCount() : 0;
 }
 
-void WW8AttributeOutput::StartRun( const SwRedlineData* pRedlineData, bool /*bSingleEmptyRun*/ )
+void WW8AttributeOutput::StartRun( const SwRedlineData* pRedlineData, sal_Int32 nPos, bool /*bSingleEmptyRun*/ )
 {
     if (pRedlineData)
     {
@@ -1004,6 +1008,13 @@ void WW8AttributeOutput::StartRun( const SwRedlineData* pRedlineData, bool /*bSi
             }
         }
     }
+
+    /// Insert bookmarks started at this run
+    auto aRange = m_aBookmarksOfParagraphStart.equal_range(nPos);
+    for( auto aIter = aRange.first; aIter != aRange.second; ++aIter)
+    {
+        GetExport().AppendBookmark(BookmarkToWord(aIter->second));
+    }
 }
 
 void WW8AttributeOutput::OnTOXEnding()
@@ -1011,6 +1022,19 @@ void WW8AttributeOutput::OnTOXEnding()
     mbOnTOXEnding = true;
 }
 
+void WW8AttributeOutput::EndRun( const SwTextNode* /*pNode*/, sal_Int32 nPos, bool bLastRun )
+{
+    /// Insert bookmarks ended after this run
+    auto aRange = m_aBookmarksOfParagraphEnd.equal_range(nPos);
+    for( auto aIter = aRange.first; aIter != aRange.second; ++aIter)
+    {
+        if(bLastRun)
+            GetExport().AppendBookmarkEndWithCorrection(BookmarkToWord(aIter->second));
+        else
+            GetExport().AppendBookmark(BookmarkToWord(aIter->second));
+    }
+}
+
 void WW8AttributeOutput::EndRunProperties( const SwRedlineData* pRedlineData )
 {
     Redline( pRedlineData );
@@ -1950,6 +1974,179 @@ static bool lcl_IsHyperlinked(const SwForm& rForm, sal_uInt16 nTOXLvl)
     return bRes;
 }
 
+void AttributeOutputBase::GenerateBookmarksForSequenceField(const SwTextNode& rNode, SwWW8AttrIter& rAttrIter)
+{
+    if(GetExport().GetExportFormat() == MSWordExportBase::ExportFormat::RTF) // Not implemented for RTF
+        return;
+
+    if (const SwpHints* pTextAttrs = rNode.GetpSwpHints())
+    {
+        for( size_t i = 0; i < pTextAttrs->Count(); ++i )
+        {
+            const SwTextAttr* pHt = pTextAttrs->Get(i);
+            if (pHt->GetAttr().Which() == RES_TXTATR_FIELD)
+            {
+                const SwFormatField& rField = static_cast<const SwFormatField&>(pHt->GetAttr());
+                const SwField* pField = rField.GetField();
+                // Need to have bookmarks only for sequence fields
+                if (pField && pField->GetTyp()->Which() == RES_SETEXPFLD && pField->GetSubType() == nsSwGetSetExpType::GSE_SEQ)
+                {
+                    const sal_uInt16 nSeqFieldNumber = static_cast<const SwSetExpField*>(pField)->GetSeqNumber();
+                    const OUString sObjectName = static_cast<const SwSetExpFieldType*>(pField->GetTyp())->GetName();
+                    const SwFieldTypes* pFieldTypes = GetExport().m_pDoc->getIDocumentFieldsAccess().GetFieldTypes();
+                    bool bHaveFullBkm = false;
+                    bool bHaveLabelAndNumberBkm = false;
+                    bool bHaveCaptionOnlyBkm = false;
+                    bool bHaveNumberOnlyBkm = false;
+                    bool bRunSplittedAtSep = false;
+                    for( auto pFieldType : *pFieldTypes )
+                    {
+                        if( RES_GETREFFLD == pFieldType->Which() )
+                        {
+                            SwIterator<SwFormatField,SwFieldType> aIter( *pFieldType );
+                            for( SwFormatField* pFormatField = aIter.First(); pFormatField; pFormatField = aIter.Next() )
+                            {
+                                SwGetRefField* pRefField = static_cast<SwGetRefField*>(pFormatField->GetField());
+                                // If we have a reference to the current sequence field
+                                if(pRefField->GetSeqNo() == nSeqFieldNumber && pRefField->GetSetRefName() == sObjectName)
+                                {
+                                    // Need to create a seperate run for separator character
+                                    SwWW8AttrIter aLocalAttrIter( GetExport(), rNode ); // We need a local iterator having the right number of runs
+                                    const OUString aText = rNode.GetText();
+                                    const sal_Int32 nCategoryStart = aText.indexOf(pRefField->GetSetRefName());
+                                    const sal_Int32 nPosBeforeSeparator = std::max(nCategoryStart, pHt->GetStart());
+                                    bool bCategoryFirst = nCategoryStart < pHt->GetStart();
+                                    sal_Int32 nSeparatorPos = 0;
+                                    if (bCategoryFirst)
+                                    {
+                                        nSeparatorPos = aLocalAttrIter.WhereNext();
+                                        while (nSeparatorPos <= nPosBeforeSeparator)
+                                        {
+                                            aLocalAttrIter.NextPos();
+                                            nSeparatorPos = aLocalAttrIter.WhereNext();
+                                        }
+                                    }
+                                    else
+                                    {
+                                        nSeparatorPos = nCategoryStart + pRefField->GetSetRefName().getLength();
+                                    }
+                                    sal_Int32 nRefTextPos = 0;
+                                    if(nSeparatorPos < aText.getLength())
+                                    {
+                                        nRefTextPos = SwGetExpField::GetReferenceTextPos(pHt->GetFormatField(), *GetExport().m_pDoc, nSeparatorPos);
+                                        if(nRefTextPos != nSeparatorPos)
+                                        {
+                                            if(!bRunSplittedAtSep)
+                                            {
+                                                if(!bCategoryFirst)
+                                                    rAttrIter.SplitRun(nSeparatorPos);
+                                                rAttrIter.SplitRun(nRefTextPos);
+                                                bRunSplittedAtSep = true;
+                                            }
+                                            if(!bCategoryFirst)
+                                                aLocalAttrIter.SplitRun(nSeparatorPos);
+                                            aLocalAttrIter.SplitRun(nRefTextPos);
+                                        }
+                                        else if (bCategoryFirst)
+                                        {
+                                            if(!bRunSplittedAtSep)
+                                            {
+                                                rAttrIter.SplitRun(nSeparatorPos);
+                                                bRunSplittedAtSep = true;
+                                            }
+                                            aLocalAttrIter.SplitRun(nSeparatorPos);
+                                        }
+                                    }
+                                    // Generate bookmarks on the right position
+                                    OUString sName("Ref_" + pRefField->GetSetRefName());
+                                    sName += OUString::number(pRefField->GetSeqNo());
+                                    switch (pRefField->GetFormat())
+                                    {
+                                        case REF_PAGE:
+                                        case REF_PAGE_PGDESC:
+                                        case REF_CONTENT:
+                                        case REF_UPDOWN:
+                                            sName += "_full";
+                                            if(!bHaveFullBkm)
+                                            {
+                                                sal_Int32 nLastAttrStart = 0;
+                                                sal_Int32 nActAttr = aLocalAttrIter.WhereNext();
+                                                while (nActAttr < rNode.GetText().getLength())
+                                                {
+                                                    nLastAttrStart = nActAttr;
+                                                    aLocalAttrIter.NextPos();
+                                                    nActAttr = aLocalAttrIter.WhereNext();
+                                                }
+                                                WriteBookmarkInActParagraph( sName, std::min(nCategoryStart, pHt->GetStart()), nLastAttrStart );
+                                                bHaveFullBkm = true;
+                                            }
+                                            break;
+                                        case REF_ONLYNUMBER:
+                                        {
+                                            sName += "_label_and_number";
+                                            if(!bHaveLabelAndNumberBkm)
+                                            {
+                                                if(bCategoryFirst)
+                                                    WriteBookmarkInActParagraph( sName, std::min(nCategoryStart, pHt->GetStart()), std::max(nCategoryStart, pHt->GetStart()) );
+                                                else
+                                                {
+                                                    // Find the last run which contains category text
+                                                    SwWW8AttrIter aLocalAttrIter2( GetExport(), rNode );
+                                                    sal_Int32 nCatLastRun = 0;
+                                                    sal_Int32 nNextAttr = aLocalAttrIter2.WhereNext();
+                                                    while (nNextAttr < nSeparatorPos)
+                                                    {
+                                                        nCatLastRun = nNextAttr;
+                                                        aLocalAttrIter2.NextPos();
+                                                        nNextAttr = aLocalAttrIter2.WhereNext();
+                                                    }
+                                                    WriteBookmarkInActParagraph( sName, pHt->GetStart(), nCatLastRun );
+                                                }
+                                                bHaveLabelAndNumberBkm = true;
+                                            }
+                                            break;
+                                        }
+                                        case REF_ONLYCAPTION:
+                                        {
+                                            sName += "_caption_only";
+                                            if(!bHaveCaptionOnlyBkm)
+                                            {
+                                                // Find last run
+                                                sal_Int32 nLastAttrStart = 0;
+                                                sal_Int32 nActAttr = aLocalAttrIter.WhereNext();
+                                                while (nActAttr < rNode.GetText().getLength())
+                                                {
+                                                    nLastAttrStart = nActAttr;
+                                                    aLocalAttrIter.NextPos();
+                                                    nActAttr = aLocalAttrIter.WhereNext();
+                                                }
+                                                WriteBookmarkInActParagraph( sName, nRefTextPos, nLastAttrStart );
+                                                bHaveCaptionOnlyBkm = true;
+                                            }
+                                            break;
+                                        }
+                                        case REF_ONLYSEQNO:
+                                        {
+                                            sName += "_number_only";
+                                            if(!bHaveNumberOnlyBkm)
+                                            {
+                                                WriteBookmarkInActParagraph( sName, pHt->GetStart(), pHt->GetStart() );
+                                                bHaveNumberOnlyBkm = true;
+                                            }
+                                            break;
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                    return;
+                }
+            }
+        }
+    }
+}
+
 void AttributeOutputBase::StartTOX( const SwSection& rSect )
 {
     if ( const SwTOXBase* pTOX = rSect.GetTOXBase() )
@@ -2805,8 +3002,8 @@ void AttributeOutputBase::TextField( const SwFormatField& rField )
                     break;
                 case REF_SEQUENCEFLD:
                 {
-                    // Have this only for DOCX format by now
-                    if(!(GetExport().GetExportFormat() == MSWordExportBase::ExportFormat::DOCX))
+                    // Not implemented for RTF
+                    if(!(GetExport().GetExportFormat() != MSWordExportBase::ExportFormat::RTF))
                         break;
 
                     switch (pField->GetFormat())
diff --git a/sw/source/filter/ww8/ww8attributeoutput.hxx b/sw/source/filter/ww8/ww8attributeoutput.hxx
index e2a978fcb4ac..dc21f2a2fb28 100644
--- a/sw/source/filter/ww8/ww8attributeoutput.hxx
+++ b/sw/source/filter/ww8/ww8attributeoutput.hxx
@@ -49,14 +49,14 @@ public:
 
     /// Start of the text run.
     ///
-    virtual void StartRun( const SwRedlineData* pRedlineData, bool bSingleEmptyRun = false ) override;
+    virtual void StartRun( const SwRedlineData* pRedlineData, sal_Int32 nPos, bool bSingleEmptyRun = false ) override;
 
     virtual void OnTOXEnding() override;
 
     /// End of the text run.
     ///
     /// No-op for binary filters.
-    virtual void EndRun(const SwTextNode* , sal_Int32 ) override {}
+    virtual void EndRun(const SwTextNode* pNode, sal_Int32 nPos, bool bLastRun = false) override;
 
     /// Before we start outputting the attributes.
     virtual void StartRunProperties() override;
@@ -84,8 +84,6 @@ public:
 
     virtual void FieldVanish( const OUString& rText, ww::eField eType ) override;
 
-    virtual void GenerateBookmarksForSequenceField(const SwTextNode& /*rNode*/, SwWW8AttrIter& /*rAttrIter*/) override {};
-
     /// Output redlining.
     virtual void Redline( const SwRedlineData* pRedline ) override;
 
@@ -429,6 +427,8 @@ protected:
 
     virtual bool AnalyzeURL( const OUString& rURL, const OUString& rTarget, OUString* pLinkURL, OUString* pMark ) override;
 
+    virtual void WriteBookmarkInActParagraph( const OUString& rName, sal_Int32 nFirstRunPos, sal_Int32 nLastRunPos ) override;
+
     /// Reference to the export, where to get the data from
     WW8Export &m_rWW8Export;
 
@@ -457,6 +457,10 @@ protected:
 
     bool mbOnTOXEnding;
 
+    /// Bookmarks of the current paragraph
+    std::multimap<sal_Int32, OUString> m_aBookmarksOfParagraphStart;
+    std::multimap<sal_Int32, OUString> m_aBookmarksOfParagraphEnd;
+
 public:
     explicit WW8AttributeOutput( WW8Export &rWW8Export )
         : AttributeOutputBase()


More information about the Libreoffice-commits mailing list