[Libreoffice-commits] core.git: Branch 'private/swe/libreoffice-5-2+backports' - 41 commits - basegfx/source drawinglayer/CppunitTest_drawinglayer_border.mk drawinglayer/qa drawinglayer/source editeng/source include/basegfx include/drawinglayer include/oox include/sal include/svx offapi/com officecfg/registry oox/source sc/source sd/source sfx2/source svx/sdi svx/source sw/inc sw/qa sw/sdi sw/source sw/uiconfig vcl/inc vcl/source writerfilter/source xmloff/source xmlsecurity/inc xmlsecurity/qa xmlsecurity/source

Tamás Zolnai tamas.zolnai at collabora.com
Tue Nov 7 12:41:17 UTC 2017


Rebased ref, commits from common ancestor:
commit df88051ebf6117141d2d738bcdbec2004bf17390
Author: Tamás Zolnai <tamas.zolnai at collabora.com>
Date:   Mon Nov 6 18:46:56 2017 +0100

    tdf#42346: DOCX export of cross-references to objects
    
    * Objects means tables, images, text frames and shapes
    * Implementation
    ** MSO uses simple bookmark references as cross-references to objects
    ** So generate bookmarks in export time if a caption is referenced
    ** In some cases we also need to split some of the runs
    ** Implemented all types of cross-references, except the chapter reference
    
    Reviewed-on: https://gerrit.libreoffice.org/44294
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Tamás Zolnai <tamas.zolnai at collabora.com>
    (cherry picked from commit 98bc7215935f1eb2e0dc6f1db826d8e729430c13)
    
    Change-Id: I3b17753123d94a04e4f28783ad5663831e7c6c84
    Reviewed-on: https://gerrit.libreoffice.org/44372
    Reviewed-by: Thorsten Behrens <Thorsten.Behrens at CIB.de>
    Tested-by: Thorsten Behrens <Thorsten.Behrens at CIB.de>

diff --git a/sw/qa/extras/ooxmlexport/data/object_cross_reference.odt b/sw/qa/extras/ooxmlexport/data/object_cross_reference.odt
new file mode 100755
index 000000000000..18b02a38c2a9
Binary files /dev/null and b/sw/qa/extras/ooxmlexport/data/object_cross_reference.odt differ
diff --git a/sw/qa/extras/ooxmlexport/data/table_cross_reference.odt b/sw/qa/extras/ooxmlexport/data/table_cross_reference.odt
new file mode 100755
index 000000000000..bd9c84016157
Binary files /dev/null and b/sw/qa/extras/ooxmlexport/data/table_cross_reference.odt differ
diff --git a/sw/qa/extras/ooxmlexport/data/table_cross_reference_custom_format.odt b/sw/qa/extras/ooxmlexport/data/table_cross_reference_custom_format.odt
new file mode 100755
index 000000000000..cbf03d34ed9f
Binary files /dev/null and b/sw/qa/extras/ooxmlexport/data/table_cross_reference_custom_format.odt differ
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport7.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport7.cxx
index b82b39e7c34c..51e3089d9647 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport7.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport7.cxx
@@ -9,8 +9,6 @@
 
 #include <swmodeltestbase.hxx>
 
-#if !defined(_WIN32)
-
 #include <com/sun/star/drawing/EnhancedCustomShapeParameterPair.hpp>
 #include <com/sun/star/drawing/EnhancedCustomShapeSegment.hpp>
 #include <com/sun/star/drawing/EnhancedCustomShapeSegmentCommand.hpp>
@@ -45,6 +43,8 @@ protected:
     }
 };
 
+#if !defined(_WIN32)
+
 DECLARE_OOXMLEXPORT_TEST( testChildNodesOfCubicBezierTo, "FDO74774.docx")
 {
     /* Number of children required by cubicBexTo is 3 of type "pt".
@@ -1245,6 +1245,577 @@ DECLARE_OOXMLEXPORT_TEST(testTdf107111, "tdf107111.docx")
 
 #endif
 
+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;
+            }
+            // Page style reference / exported as simple page reference
+            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_full"), sValue);
+                xPropertySet->getPropertyValue("SequenceNumber") >>= nValue;
+                CPPUNIT_ASSERT_EQUAL(sal_Int16(0), nValue);
+                break;
+            }
+            // Reference to table number
+            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("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 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 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 4:
+            {
+                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 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;
+    }
+}
+
+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());
+    }
+
+    // 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)
+        {
+            // Reference to image number
+            case 0:
+            {
+                CPPUNIT_ASSERT(xServiceInfo->supportsService("com.sun.star.text.TextField.GetReference"));
+                OUString sValue;
+                xPropertySet->getPropertyValue("CurrentPresentation") >>= sValue;
+                CPPUNIT_ASSERT_EQUAL(OUString("1"), sValue);
+                xPropertySet->getPropertyValue("SourceName") >>= sValue;
+                CPPUNIT_ASSERT_EQUAL(OUString("Ref_Illustration0_number_only"), sValue);
+                break;
+            }
+            // Full reference to the circle shape
+            case 1:
+            {
+                CPPUNIT_ASSERT(xServiceInfo->supportsService("com.sun.star.text.TextField.GetReference"));
+                OUString sValue;
+                xPropertySet->getPropertyValue("CurrentPresentation") >>= sValue;
+                CPPUNIT_ASSERT_EQUAL(OUString("Drawing 2: a circle"), sValue);
+                xPropertySet->getPropertyValue("SourceName") >>= sValue;
+                CPPUNIT_ASSERT_EQUAL(OUString("Ref_Drawing1_full"), sValue);
+                break;
+            }
+            // Caption only reference to the second picture
+            case 2:
+            {
+                CPPUNIT_ASSERT(xServiceInfo->supportsService("com.sun.star.text.TextField.GetReference"));
+                OUString sValue;
+                xPropertySet->getPropertyValue("CurrentPresentation") >>= sValue;
+                CPPUNIT_ASSERT_EQUAL(OUString("an other image"), sValue);
+                xPropertySet->getPropertyValue("SourceName") >>= sValue;
+                CPPUNIT_ASSERT_EQUAL(OUString("Ref_Illustration1_caption_only"), sValue);
+                break;
+            }
+            // Category and number reference to second text frame
+            case 3:
+            {
+                CPPUNIT_ASSERT(xServiceInfo->supportsService("com.sun.star.text.TextField.GetReference"));
+                OUString sValue;
+                xPropertySet->getPropertyValue("CurrentPresentation") >>= sValue;
+                CPPUNIT_ASSERT_EQUAL(OUString("Text 2"), sValue);
+                xPropertySet->getPropertyValue("SourceName") >>= sValue;
+                CPPUNIT_ASSERT_EQUAL(OUString("Ref_Text1_label_and_number"), sValue);
+                break;
+            }
+            // Full reference to rectangle shape
+            case 4:
+            {
+                CPPUNIT_ASSERT(xServiceInfo->supportsService("com.sun.star.text.TextField.GetReference"));
+                OUString sValue;
+                xPropertySet->getPropertyValue("CurrentPresentation") >>= sValue;
+                CPPUNIT_ASSERT_EQUAL(OUString("Drawing 1: A rectangle"), sValue);
+                xPropertySet->getPropertyValue("SourceName") >>= sValue;
+                CPPUNIT_ASSERT_EQUAL(OUString("Ref_Drawing0_full"), sValue);
+                break;
+            }
+            // Caption only reference to rectangle shape
+            case 5:
+            {
+                CPPUNIT_ASSERT(xServiceInfo->supportsService("com.sun.star.text.TextField.GetReference"));
+                OUString sValue;
+                xPropertySet->getPropertyValue("CurrentPresentation") >>= sValue;
+                CPPUNIT_ASSERT_EQUAL(OUString("A rectangle"), sValue);
+                xPropertySet->getPropertyValue("SourceName") >>= sValue;
+                CPPUNIT_ASSERT_EQUAL(OUString("Ref_Drawing0_caption_only"), sValue);
+                break;
+            }
+            // Category and number reference to rectangle shape
+            case 6:
+            {
+                CPPUNIT_ASSERT(xServiceInfo->supportsService("com.sun.star.text.TextField.GetReference"));
+                OUString sValue;
+                xPropertySet->getPropertyValue("CurrentPresentation") >>= sValue;
+                CPPUNIT_ASSERT_EQUAL(OUString("Drawing 1"), sValue);
+                xPropertySet->getPropertyValue("SourceName") >>= sValue;
+                CPPUNIT_ASSERT_EQUAL(OUString("Ref_Drawing0_label_and_number"), sValue);
+                break;
+            }
+            // Reference to rectangle shape's number
+            case 7:
+            {
+                CPPUNIT_ASSERT(xServiceInfo->supportsService("com.sun.star.text.TextField.GetReference"));
+                OUString sValue;
+                xPropertySet->getPropertyValue("CurrentPresentation") >>= sValue;
+                CPPUNIT_ASSERT_EQUAL(OUString("1"), sValue);
+                xPropertySet->getPropertyValue("SourceName") >>= sValue;
+                CPPUNIT_ASSERT_EQUAL(OUString("Ref_Drawing0_number_only"), sValue);
+                break;
+            }
+            // Full reference to first text frame
+            case 8:
+            {
+                CPPUNIT_ASSERT(xServiceInfo->supportsService("com.sun.star.text.TextField.GetReference"));
+                OUString sValue;
+                xPropertySet->getPropertyValue("CurrentPresentation") >>= sValue;
+                CPPUNIT_ASSERT_EQUAL(OUString("Text 1: A frame"), sValue);
+                xPropertySet->getPropertyValue("SourceName") >>= sValue;
+                CPPUNIT_ASSERT_EQUAL(OUString("Ref_Text0_full"), sValue);
+                break;
+            }
+            // Caption only reference to first text frame
+            case 9:
+            {
+                CPPUNIT_ASSERT(xServiceInfo->supportsService("com.sun.star.text.TextField.GetReference"));
+                OUString sValue;
+                xPropertySet->getPropertyValue("CurrentPresentation") >>= sValue;
+                CPPUNIT_ASSERT_EQUAL(OUString("A frame"), sValue);
+                xPropertySet->getPropertyValue("SourceName") >>= sValue;
+                CPPUNIT_ASSERT_EQUAL(OUString("Ref_Text0_caption_only"), sValue);
+                break;
+            }
+            // Category and number reference to first text frame
+            case 10:
+            {
+                CPPUNIT_ASSERT(xServiceInfo->supportsService("com.sun.star.text.TextField.GetReference"));
+                OUString sValue;
+                xPropertySet->getPropertyValue("CurrentPresentation") >>= sValue;
+                CPPUNIT_ASSERT_EQUAL(OUString("Text 1"), sValue);
+                xPropertySet->getPropertyValue("SourceName") >>= sValue;
+                CPPUNIT_ASSERT_EQUAL(OUString("Ref_Text0_label_and_number"), sValue);
+                break;
+            }
+            // Number only reference to first text frame
+            case 11:
+            {
+                CPPUNIT_ASSERT(xServiceInfo->supportsService("com.sun.star.text.TextField.GetReference"));
+                OUString sValue;
+                xPropertySet->getPropertyValue("CurrentPresentation") >>= sValue;
+                CPPUNIT_ASSERT_EQUAL(OUString("1"), sValue);
+                xPropertySet->getPropertyValue("SourceName") >>= sValue;
+                CPPUNIT_ASSERT_EQUAL(OUString("Ref_Text0_number_only"), sValue);
+                break;
+            }
+            // Full reference to first picture
+            case 12:
+            {
+                CPPUNIT_ASSERT(xServiceInfo->supportsService("com.sun.star.text.TextField.GetReference"));
+                OUString sValue;
+                xPropertySet->getPropertyValue("CurrentPresentation") >>= sValue;
+                CPPUNIT_ASSERT_EQUAL(OUString("Illustration 1: A picture"), sValue.trim()); // failes on MAC without trim
+                xPropertySet->getPropertyValue("SourceName") >>= sValue;
+                CPPUNIT_ASSERT_EQUAL(OUString("Ref_Illustration0_full"), sValue);
+                break;
+            }
+            // Reference to first picture' caption
+            case 13:
+            {
+                CPPUNIT_ASSERT(xServiceInfo->supportsService("com.sun.star.text.TextField.GetReference"));
+                OUString sValue;
+                xPropertySet->getPropertyValue("CurrentPresentation") >>= sValue;
+                CPPUNIT_ASSERT_EQUAL(OUString("A picture"), sValue);
+                xPropertySet->getPropertyValue("SourceName") >>= sValue;
+                CPPUNIT_ASSERT_EQUAL(OUString("Ref_Illustration0_caption_only"), sValue);
+                break;
+            }
+            // Category and number reference to first picture
+            case 14:
+            {
+                CPPUNIT_ASSERT(xServiceInfo->supportsService("com.sun.star.text.TextField.GetReference"));
+                OUString sValue;
+                xPropertySet->getPropertyValue("CurrentPresentation") >>= sValue;
+                CPPUNIT_ASSERT_EQUAL(OUString("Illustration 1"), sValue);
+                xPropertySet->getPropertyValue("SourceName") >>= sValue;
+                CPPUNIT_ASSERT_EQUAL(OUString("Ref_Illustration0_label_and_number"), sValue);
+                break;
+            }
+            default:
+                break;
+        }
+        ++nIndex;
+    }
+}
+
+
 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 6e8c0ca0bb26..dc32dd36d8fe 100644
--- a/sw/source/filter/ww8/attributeoutputbase.hxx
+++ b/sw/source/filter/ww8/attributeoutputbase.hxx
@@ -209,6 +209,8 @@ public:
 
     virtual void FieldVanish( const OUString& rText, ww::eField eType ) = 0;
 
+    virtual void GenerateBookmarksForSequenceField(const SwTextNode& rNode, SwWW8AttrIter& rAttrIter) = 0;
+
     void StartTOX( const SwSection& rSect );
 
     void EndTOX( const SwSection& rSect,bool bCareEnd=true );
diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx b/sw/source/filter/ww8/docxattributeoutput.cxx
index 45c5ed84cbd3..467177d013fa 100644
--- a/sw/source/filter/ww8/docxattributeoutput.cxx
+++ b/sw/source/filter/ww8/docxattributeoutput.cxx
@@ -117,6 +117,8 @@
 #include <IDocumentSettingAccess.hxx>
 #include <IDocumentStylePoolAccess.hxx>
 #include <IDocumentRedlineAccess.hxx>
+#include <IDocumentFieldsAccess.hxx>
+#include <reffld.hxx>
 
 #include <osl/file.hxx>
 #include <vcl/embeddedfontshelper.hxx>
@@ -601,6 +603,10 @@ 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();
+
 }
 
 void DocxAttributeOutput::WriteSdtBlock( sal_Int32& nSdtPrToken,
@@ -1267,6 +1273,8 @@ void DocxAttributeOutput::EndRun(const SwTextNode* pNode, sal_Int32 nPos)
         m_endPageRef = true;
     }
 
+    DoWriteBookmarkStartIfExist(nPos);
+
     m_pSerializer->startElementNS( XML_w, XML_r, FSEND );
     if(GetExport().m_bTabInTOC && m_pHyperlinkAttrList.is())
     {
@@ -1364,6 +1372,8 @@ void DocxAttributeOutput::EndRun(const SwTextNode* pNode, sal_Int32 nPos)
         }
         m_nFieldsInHyperlink = 0;
     }
+
+    DoWriteBookmarkEndIfExist(nPos);
 }
 
 void DocxAttributeOutput::DoWriteBookmarkTagStart(const OUString & bookmarkName)
@@ -1391,6 +1401,34 @@ void DocxAttributeOutput::DoWriteBookmarkTagEnd(const OUString & bookmarkName)
     }
 }
 
+void DocxAttributeOutput::DoWriteBookmarkStartIfExist(sal_Int32 nPos)
+{
+    auto aRange = m_aBookmarksWithPosStart.equal_range(nPos);
+    for( auto aIter = aRange.first; aIter != aRange.second; ++aIter)
+    {
+        DoWriteBookmarkTagStart(aIter->second);
+        m_rOpenedBookmarksIds[aIter->second] = m_nNextBookmarkId;
+        m_sLastOpenedBookmark = OUStringToOString(BookmarkToWord(aIter->second), RTL_TEXTENCODING_UTF8).getStr();
+        m_nNextBookmarkId++;
+    }
+}
+
+void DocxAttributeOutput::DoWriteBookmarkEndIfExist(sal_Int32 nPos)
+{
+    auto aRange = m_aBookmarksWithPosEnd.equal_range(nPos);
+    for( auto aIter = aRange.first; aIter != aRange.second; ++aIter)
+    {
+        // Get the id of the bookmark
+        auto pPos = m_rOpenedBookmarksIds.find(aIter->second);
+        if (pPos != m_rOpenedBookmarksIds.end())
+        {
+            // Output the bookmark
+            DoWriteBookmarkTagEnd(aIter->second);
+            m_rOpenedBookmarksIds.erase(aIter->second);
+        }
+    }
+}
+
 /// Write the start bookmarks
 void DocxAttributeOutput::DoWriteBookmarksStart()
 {
@@ -1655,7 +1693,7 @@ void DocxAttributeOutput::StartField_Impl( const SwTextNode* pNode, sal_Int32 nP
         else
         {
             // Write the field start
-            if ( rInfos.pField && rInfos.pField->GetSubType() & FIXEDFLD )
+            if ( rInfos.pField && (rInfos.pField->Which() == RES_DATETIMEFLD) && rInfos.pField->GetSubType() & FIXEDFLD )
             {
                 m_pSerializer->startElementNS( XML_w, XML_fldChar,
                     FSNS( XML_w, XML_fldCharType ), "begin",
@@ -6509,7 +6547,7 @@ void DocxAttributeOutput::CharFont( const SvxFontItem& rFont)
     const OString sFontNameUtf8 = OUStringToOString(sFontName, RTL_TEXTENCODING_UTF8);
     if (!sFontNameUtf8.isEmpty())
     {
-        if (m_pFontsAttrList &&
+        if (m_pFontsAttrList.is() &&
             (   m_pFontsAttrList->hasAttribute(FSNS( XML_w, XML_ascii )) ||
                 m_pFontsAttrList->hasAttribute(FSNS( XML_w, XML_hAnsi ))    )
             )
@@ -6934,6 +6972,176 @@ 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 )
@@ -7040,6 +7248,12 @@ 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 2456fffac0a6..4c41f83d2f30 100644
--- a/sw/source/filter/ww8/docxattributeoutput.hxx
+++ b/sw/source/filter/ww8/docxattributeoutput.hxx
@@ -370,6 +370,7 @@ 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();
@@ -696,6 +697,8 @@ private:
     void DoWriteBookmarkTagEnd(const OUString & bookmarkName);
     void DoWriteBookmarksStart();
     void DoWriteBookmarksEnd();
+    void DoWriteBookmarkStartIfExist(sal_Int32 nPos);
+    void DoWriteBookmarkEndIfExist(sal_Int32 nPos);
 
     void DoWritePermissionTagStart(const OUString & permission);
     void DoWritePermissionTagEnd(const OUString & permission);
@@ -727,6 +730,7 @@ 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 );
+    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, ... );
@@ -784,6 +788,10 @@ 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;
+
     /// Permissions to output
     std::vector<OUString> m_rPermissionsStart;
     std::vector<OUString> m_rPermissionsEnd;
diff --git a/sw/source/filter/ww8/docxexport.hxx b/sw/source/filter/ww8/docxexport.hxx
index 047b497dcce5..2cfd53a866d2 100644
--- a/sw/source/filter/ww8/docxexport.hxx
+++ b/sw/source/filter/ww8/docxexport.hxx
@@ -177,6 +177,8 @@ public:
 
     void WriteOutliner(const OutlinerParaObject& rOutliner, sal_uInt8 nTyp);
 
+    virtual ExportFormat GetExportFormat() const override { return ExportFormat::DOCX; }
+
 protected:
     /// Format-dependent part of the actual export.
     virtual void ExportDocument_Impl() override;
diff --git a/sw/source/filter/ww8/rtfattributeoutput.hxx b/sw/source/filter/ww8/rtfattributeoutput.hxx
index e465dbbe8a8f..82e2817e1a03 100644
--- a/sw/source/filter/ww8/rtfattributeoutput.hxx
+++ b/sw/source/filter/ww8/rtfattributeoutput.hxx
@@ -217,6 +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 {};
 
 protected:
     /// Output frames - the implementation.
diff --git a/sw/source/filter/ww8/rtfexport.hxx b/sw/source/filter/ww8/rtfexport.hxx
index ecef9ee60217..1c1f4d62c161 100644
--- a/sw/source/filter/ww8/rtfexport.hxx
+++ b/sw/source/filter/ww8/rtfexport.hxx
@@ -124,6 +124,8 @@ public:
 
     virtual sal_uLong ReplaceCr(sal_uInt8 nChar) override;
 
+    ExportFormat GetExportFormat() const override { return ExportFormat::RTF; }
+
 protected:
     /// Format-dependent part of the actual export.
     virtual void ExportDocument_Impl() override;
diff --git a/sw/source/filter/ww8/wrtw8nds.cxx b/sw/source/filter/ww8/wrtw8nds.cxx
index d04facf6af8c..e9ba18f40d6f 100644
--- a/sw/source/filter/ww8/wrtw8nds.cxx
+++ b/sw/source/filter/ww8/wrtw8nds.cxx
@@ -1156,6 +1156,25 @@ void SwWW8AttrIter::OutSwFormatRefMark(const SwFormatRefMark& rAttr, bool)
                                             &rAttr.GetRefName(), 0 ));
 }
 
+void SwWW8AttrIter::SplitRun( sal_Int32 nSplitEndPos )
+{
+    for(auto aIter = maCharRuns.begin(); aIter != maCharRuns.end(); ++aIter)
+    {
+        if(aIter->mnEndPos == nSplitEndPos)
+            return;
+        else if (aIter->mnEndPos > nSplitEndPos)
+        {
+            CharRunEntry aNewEntry = *aIter;
+            aIter->mnEndPos = nSplitEndPos;
+            maCharRuns.insert( ++aIter, aNewEntry);
+            maCharRunIter = maCharRuns.begin();
+            IterToCurrent();
+            nAktSwPos = SearchNext(1);
+            break;
+        }
+    }
+}
+
 void WW8AttributeOutput::FieldVanish( const OUString& rText, ww::eField /*eType*/ )
 {
     ww::bytes aItems;
@@ -2146,6 +2165,10 @@ void MSWordExportBase::OutputTextNode( const SwTextNode& rNode )
         AppendWordBookmark( sBkmkName );
     }
 
+    // Call this before write out fields and runs
+    if(GetExportFormat() == ExportFormat::DOCX)
+        AttrOutput().GenerateBookmarksForSequenceField(rNode, aAttrIter);
+
     const OUString& aStr( rNode.GetText() );
 
     sal_Int32 nAktPos = 0;
diff --git a/sw/source/filter/ww8/wrtww8.hxx b/sw/source/filter/ww8/wrtww8.hxx
index 9ee2645f2d38..dafffeaafd44 100644
--- a/sw/source/filter/ww8/wrtww8.hxx
+++ b/sw/source/filter/ww8/wrtww8.hxx
@@ -779,6 +779,9 @@ public:
     /// Returns the index of a picture bullet, used in numberings.
     int GetGrfIndex(const SvxBrushItem& rBrush);
 
+    enum ExportFormat { DOC = 0, RTF = 1, DOCX = 2};
+    virtual ExportFormat GetExportFormat() const = 0;
+
 protected:
     /// Format-dependent part of the actual export.
     virtual void ExportDocument_Impl() = 0;
@@ -1141,6 +1144,8 @@ public:
             const SwFrameFormat& rFormat, const SwFrameFormat& rLeftFormat, const SwFrameFormat& rFirstPageFormat,
         sal_uInt8 nBreakCode) override;
 
+    virtual ExportFormat GetExportFormat() const override { return ExportFormat::DOC; }
+
 protected:
     /// Output SwGrfNode
     virtual void OutputGrfNode( const SwGrfNode& ) override;
@@ -1504,6 +1509,8 @@ public:
 
     bool IsWatermarkFrame();
     bool IsAnchorLinkedToThisNode( sal_uLong nNodePos );
+
+    void SplitRun( sal_Int32 nSplitEndPos );
 };
 
 /// Class to collect and output the styles table.
diff --git a/sw/source/filter/ww8/ww8atr.cxx b/sw/source/filter/ww8/ww8atr.cxx
index db888c475a20..fbb763a1459a 100644
--- a/sw/source/filter/ww8/ww8atr.cxx
+++ b/sw/source/filter/ww8/ww8atr.cxx
@@ -902,7 +902,12 @@ OUString MSWordExportBase::GetBookmarkName( sal_uInt16 nTyp, const OUString* pNa
             }
             break;
         case REF_SEQUENCEFLD:
-            break;      // ???
+        {
+            assert(pName);
+            sRet += "Ref_";
+            sRet += *pName;
+            break;
+        }
         case REF_BOOKMARK:
             if ( pName )
                 sRet = *pName;
@@ -2784,6 +2789,63 @@ void AttributeOutputBase::TextField( const SwFormatField& rField )
                             break;
                     }
                     break;
+                case REF_SEQUENCEFLD:
+                {
+                    // Have this only for DOCX format by now
+                    if(!(GetExport().GetExportFormat() == MSWordExportBase::ExportFormat::DOCX))
+                        break;
+
+                    switch (pField->GetFormat())
+                    {
+                        case REF_PAGE:
+                        case REF_PAGE_PGDESC:
+                            eField = ww::ePAGEREF;
+                            break;
+                        default:
+                            eField = ww::eREF;
+                            break;
+                    }
+                    // Generate a unique bookmark name
+                    {
+                        OUString sName(rRField.GetSetRefName());
+                        sName += OUString::number(rRField.GetSeqNo());
+                        switch (pField->GetFormat())
+                        {
+                            case REF_PAGE:
+                            case REF_PAGE_PGDESC:
+                            case REF_CONTENT:
+                            case REF_UPDOWN:
+                                    sName += "_full";
+                                    break;
+                            case REF_ONLYNUMBER:
+                                    sName += "_label_and_number";
+                                    break;
+                            case REF_ONLYCAPTION:
+                                    sName += "_caption_only";
+                                    break;
+                            case REF_ONLYSEQNO:
+                                    sName += "_number_only";
+                                    break;
+                            default: // Ingore other types of reference fields
+                                    eField = ww::eNONE;
+                                    break;
+                        }
+                        sStr = FieldString(eField) + MSWordExportBase::GetBookmarkName(nSubType, &sName, 0);
+                    }
+                    switch (pField->GetFormat())
+                    {
+                        case REF_NUMBER:
+                            sStr += " \\r";
+                            break;
+                        case REF_NUMBER_NO_CONTEXT:
+                            sStr += " \\n";
+                            break;
+                        case REF_NUMBER_FULL_CONTEXT:
+                            sStr += " \\w";
+                            break;
+                    }
+                    break;
+                }
                 case REF_FOOTNOTE:
                 case REF_ENDNOTE:
                     switch (pField->GetFormat())
diff --git a/sw/source/filter/ww8/ww8attributeoutput.hxx b/sw/source/filter/ww8/ww8attributeoutput.hxx
index 0d41f0e33fb4..e2a978fcb4ac 100644
--- a/sw/source/filter/ww8/ww8attributeoutput.hxx
+++ b/sw/source/filter/ww8/ww8attributeoutput.hxx
@@ -84,6 +84,8 @@ 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;
 
commit 195df9bc6aad1fca77900bf294f073fa7d1efc0a
Author: Serge Krot <Serge.Krot at cib.de>
Date:   Tue Oct 17 19:03:14 2017 +0200

    tdf#38778 fix missing run properties export for fields in docx
    
    Not all runs got their text properties written during field export -
    previously only the first run had them. Adds SwTextNode param to EndRun
    and EndRuby methods, implementation empty for rtf and doc though.
    
    Change-Id: I77f39b40689feb9664044e61824ad3bb97776638
    Reviewed-on: https://gerrit.libreoffice.org/43465
    Reviewed-by: Serge Krot (CIB) <Serge.Krot at cib.de>
    Tested-by: Serge Krot (CIB) <Serge.Krot at cib.de>
    
    tdf#38778 Added colors into run properties of field run
    
    During export into DOCX all runs inside fields should
    contain all character properties including character color.
    
    Change-Id: I2a7d4fc26f1e1de1080f51de84180a19794709a9
    Reviewed-on: https://gerrit.libreoffice.org/43723
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Serge Krot (CIB) <Serge.Krot at cib.de>
    
    related tdf#38778 Speed-up: Do not traverse the whole array
    
    It is known that text attributes are sorted inside SwpHints.
    No need to check all entries if special position is provided.
    
    Change-Id: Iac92cd40cd6d094d158f3b50fd768f47029ccdce
    Reviewed-on: https://gerrit.libreoffice.org/43911
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Thorsten Behrens <Thorsten.Behrens at CIB.de>
    
    tdf#38778 Fix output of the font in DOC run
    
    The font information should be output before field declaration.
    Added unit test.
    
    tdf#38778 DOCX output: no double output of the font info
    
    Change-Id: I147dd8956fbd8e69c3a2e86aff01dc249f4fa815
    a080f742cde88b914e146fe7a95b90bf1952c96a
    Reviewed-on: https://gerrit.libreoffice.org/44160
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Thorsten Behrens <Thorsten.Behrens at CIB.de>
    Reviewed-on: https://gerrit.libreoffice.org/44359
    Tested-by: Thorsten Behrens <Thorsten.Behrens at CIB.de>
    
    (cherry picked from commit 37f9b0f50c82b985c7b1713240b628fa51cb7d02)

diff --git a/sw/qa/extras/ooxmlexport/data/tdf38778_properties_in_run_for_field.doc b/sw/qa/extras/ooxmlexport/data/tdf38778_properties_in_run_for_field.doc
new file mode 100644
index 000000000000..5f0f7238a153
Binary files /dev/null and b/sw/qa/extras/ooxmlexport/data/tdf38778_properties_in_run_for_field.doc differ
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport4.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport4.cxx
index 699cc0386f10..0fdfe003e161 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport4.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport4.cxx
@@ -671,6 +671,73 @@ DECLARE_OOXMLEXPORT_TEST(test_OpeningBrace, "2120112713_OpenBrace.docx")
     assertXPath(pXmlDoc, "/w:document/w:body/w:p[1]/m:oMath[1]/m:d[1]/m:dPr[1]/m:begChr[1]","val","");
 }
 
+// Checks that all runs of the field have text properties.
+// Old behaviour: only first run has text properties of the field
+//
+// There are several runs are used in fields:
+//     <w:r>
+//         <w:rPr>
+//             <!-- properties written with DocxAttributeOutput::StartRunProperties() / DocxAttributeOutput::EndRunProperties().
+//         </w:rPr>
+//         <w:fldChar w:fldCharType="begin" />
+//     </w:r>
+//         <w:r>
+//         <w:rPr>
+//             <!-- properties written with DocxAttributeOutput::DoWriteFieldRunProperties()
+//         </w:rPr>
+//         <w:instrText>TIME \@"HH:mm:ss"</w:instrText>
+//     </w:r>
+//     <w:r>
+//         <w:rPr>
+//             <!-- properties written with DocxAttributeOutput::DoWriteFieldRunProperties()
+//         </w:rPr>
+//         <w:fldChar w:fldCharType="separate" />
+//     </w:r>
+//     <w:r>
+//         <w:rPr>
+//             <!-- properties written with DocxAttributeOutput::DoWriteFieldRunProperties()
+//         </w:rPr>
+//         <w:t>14:01:13</w:t>
+//         </w:r>
+//     <w:r>
+//         <w:rPr>
+//             <!-- properties written with DocxAttributeOutput::DoWriteFieldRunProperties()
+//         </w:rPr>
+//         <w:fldChar w:fldCharType="end" />
+//     </w:r>
+// See, tdf#38778
+DECLARE_OOXMLEXPORT_TEST(testTdf38778, "tdf38778_properties_in_run_for_field.doc")
+{
+    xmlDocPtr pXmlDoc = parseExport("word/document.xml");
+    if (!pXmlDoc)
+        return;
+
+    const OUString psz("20");
+    const OUString pszCs("20");
+
+    // w:fldCharType="begin"
+    assertXPath(pXmlDoc,        "/w:document/w:body/w:p[1]/w:r[3]/w:rPr/w:sz",   "val", psz);
+    assertXPath(pXmlDoc,        "/w:document/w:body/w:p[1]/w:r[3]/w:rPr/w:szCs", "val", pszCs);
+
+    // PAGE
+    assertXPath(pXmlDoc,        "/w:document/w:body/w:p[1]/w:r[4]/w:rPr/w:sz",   "val", psz);
+    assertXPath(pXmlDoc,        "/w:document/w:body/w:p[1]/w:r[4]/w:rPr/w:szCs", "val", pszCs);
+    assertXPathContent(pXmlDoc, "/w:document/w:body/w:p[1]/w:r[4]/w:instrText",  " PAGE ");
+
+    // w:fldCharType="separate"
+    assertXPath(pXmlDoc,        "/w:document/w:body/w:p[1]/w:r[5]/w:rPr/w:sz",   "val", psz);
+    assertXPath(pXmlDoc,        "/w:document/w:body/w:p[1]/w:r[5]/w:rPr/w:szCs", "val", pszCs);
+
+    // field result: 1
+    assertXPath(pXmlDoc,        "/w:document/w:body/w:p[1]/w:r[6]/w:rPr/w:sz",   "val", psz);
+    assertXPath(pXmlDoc,        "/w:document/w:body/w:p[1]/w:r[6]/w:rPr/w:szCs", "val", pszCs);
+    assertXPathContent(pXmlDoc, "/w:document/w:body/w:p[1]/w:r[6]/w:t",          "1"); // field result
+
+    // w:fldCharType="end"
+    assertXPath(pXmlDoc,        "/w:document/w:body/w:p[1]/w:r[7]/w:rPr/w:sz",   "val", psz);
+    assertXPath(pXmlDoc,        "/w:document/w:body/w:p[1]/w:r[7]/w:rPr/w:szCs", "val", pszCs);
+}
+
 DECLARE_OOXMLEXPORT_TEST(testFDO76312, "FDO76312.docx")
 {
     xmlDocPtr pXmlDoc = parseExport("word/document.xml");
diff --git a/sw/qa/extras/ww8export/data/tdf38778_properties_in_run_for_field.doc b/sw/qa/extras/ww8export/data/tdf38778_properties_in_run_for_field.doc
new file mode 100644
index 000000000000..960fe50dae35
Binary files /dev/null and b/sw/qa/extras/ww8export/data/tdf38778_properties_in_run_for_field.doc differ
diff --git a/sw/qa/extras/ww8export/ww8export.cxx b/sw/qa/extras/ww8export/ww8export.cxx
index 24023a46f2cf..f31bbda02a06 100644
--- a/sw/qa/extras/ww8export/ww8export.cxx
+++ b/sw/qa/extras/ww8export/ww8export.cxx
@@ -88,6 +88,12 @@ protected:
     }
 };
 
+DECLARE_WW8EXPORT_TEST(testTdf38778, "tdf38778_properties_in_run_for_field.doc")
+{
+    CPPUNIT_ASSERT_EQUAL(10.0f, getProperty<float>(getRun(getParagraph(1), 1), "CharHeight"));
+    CPPUNIT_ASSERT_EQUAL(OUString("Courier New"), getProperty<OUString>(getRun(getParagraph(1), 1), "CharFontName"));
+}
+
 DECLARE_WW8EXPORT_TEST(testN325936, "n325936.doc")
 {
     /*
diff --git a/sw/source/filter/ww8/attributeoutputbase.hxx b/sw/source/filter/ww8/attributeoutputbase.hxx
index 092153ad0cbf..6e8c0ca0bb26 100644
--- a/sw/source/filter/ww8/attributeoutputbase.hxx
+++ b/sw/source/filter/ww8/attributeoutputbase.hxx
@@ -172,7 +172,7 @@ public:
     virtual void StartRun( const SwRedlineData* pRedlineData, bool bSingleEmptyRun = false ) = 0;
 
     /// End of the text run.
-    virtual void EndRun() = 0;
+    virtual void EndRun( const SwTextNode* pNode, sal_Int32 nPos ) = 0;
 
     /// Called before we start outputting the attributes.
     virtual void StartRunProperties() = 0;
@@ -199,7 +199,7 @@ public:
     virtual void StartRuby( const SwTextNode& rNode, sal_Int32 nPos, const SwFormatRuby& rRuby ) = 0;
 
     /// Output ruby end.
-    virtual void EndRuby() = 0;
+    virtual void EndRuby( const SwTextNode& rNode, sal_Int32 nPos ) = 0;
 
     /// Output URL start.
     virtual bool StartURL( const OUString& rUrl, const OUString& rTarget ) = 0;
diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx b/sw/source/filter/ww8/docxattributeoutput.cxx
index 2b245545583c..45c5ed84cbd3 100644
--- a/sw/source/filter/ww8/docxattributeoutput.cxx
+++ b/sw/source/filter/ww8/docxattributeoutput.cxx
@@ -1116,7 +1116,7 @@ void DocxAttributeOutput::StartRun( const SwRedlineData* pRedlineData, bool /*bS
     m_pSerializer->mark(Tag_StartRun_3); // let's call it "postponed text"
 }
 
-void DocxAttributeOutput::EndRun()
+void DocxAttributeOutput::EndRun(const SwTextNode* pNode, sal_Int32 nPos)
 {
     int nFieldsInPrevHyperlink = m_nFieldsInHyperlink;
     // Reset m_nFieldsInHyperlink if a new hyperlink is about to start
@@ -1131,7 +1131,7 @@ void DocxAttributeOutput::EndRun()
         // Add the fields starts for all but hyperlinks and TOCs
         if ( pIt->bOpen && pIt->pField )
         {
-            StartField_Impl( *pIt );
+            StartField_Impl( pNode, nPos, *pIt );
 
             // Remove the field from the stack if only the start has to be written
             // Unknown fields should be removed too
@@ -1179,7 +1179,7 @@ void DocxAttributeOutput::EndRun()
             {
                 // If fields begin before hyperlink then
                 // it should end before hyperlink close
-                EndField_Impl( m_Fields.back( ) );
+                EndField_Impl( pNode, nPos, m_Fields.back( ) );
                 m_Fields.pop_back();
             }
             m_pSerializer->endElementNS( XML_w, XML_hyperlink );
@@ -1196,7 +1196,7 @@ void DocxAttributeOutput::EndRun()
         // Add the fields starts for hyperlinks, TOCs and index marks
         if ( pIt->bOpen && !pIt->pField )
         {
-            StartField_Impl( *pIt, true );
+            StartField_Impl( pNode, nPos, *pIt, true );
 
             if (m_startedHyperlink)
                 ++m_nFieldsInHyperlink;
@@ -1343,7 +1343,7 @@ void DocxAttributeOutput::EndRun()
             {
                 // If fields begin after hyperlink start then
                 // it should end before hyperlink close
-                EndField_Impl( m_Fields.back( ) );
+                EndField_Impl( pNode, nPos, m_Fields.back( ) );
                 m_Fields.pop_back();
             }
             m_nFieldsInHyperlink = 0;
@@ -1359,7 +1359,7 @@ void DocxAttributeOutput::EndRun()
     {
         while ( m_Fields.begin() != m_Fields.end() )
         {
-            EndField_Impl( m_Fields.front( ) );
+            EndField_Impl( pNode, nPos, m_Fields.front( ) );
             m_Fields.erase( m_Fields.begin( ) );
         }
         m_nFieldsInHyperlink = 0;
@@ -1615,7 +1615,7 @@ void DocxAttributeOutput::WriteFFData(  const FieldInfos& rInfos )
     }
 }
 
-void DocxAttributeOutput::StartField_Impl( FieldInfos& rInfos, bool bWriteRun )
+void DocxAttributeOutput::StartField_Impl( const SwTextNode* pNode, sal_Int32 nPos, FieldInfos const & rInfos, bool bWriteRun )
 {
     if ( rInfos.pField && rInfos.eType == ww::eUNKNOWN )
     {
@@ -1648,9 +1648,9 @@ void DocxAttributeOutput::StartField_Impl( FieldInfos& rInfos, bool bWriteRun )
 
                 if ( bWriteRun )
                     m_pSerializer->endElementNS( XML_w, XML_r );
-                if ( !rInfos.pField )
-                    CmdField_Impl( rInfos );
 
+                if ( !rInfos.pField )
+                    CmdField_Impl( pNode, nPos, rInfos, bWriteRun );
         }
         else
         {
@@ -1680,7 +1680,7 @@ void DocxAttributeOutput::StartField_Impl( FieldInfos& rInfos, bool bWriteRun )
             // The hyperlinks fields can't be expanded: the value is
             // normally in the text run
             if ( !rInfos.pField )
-                CmdField_Impl( rInfos );
+                CmdField_Impl( pNode, nPos, rInfos, bWriteRun );
         }
     }
 }
@@ -1700,48 +1700,146 @@ void DocxAttributeOutput::DoWriteCmd( const OUString& rCmd )
 
 }
 
-void DocxAttributeOutput::CmdField_Impl( FieldInfos& rInfos )
+void DocxAttributeOutput::CmdField_Impl( const SwTextNode* pNode, sal_Int32 nPos, FieldInfos const & rInfos, bool bWriteRun )
 {
-    m_pSerializer->startElementNS( XML_w, XML_r, FSEND );
-    sal_Int32 nNbToken = comphelper::string::getTokenCount(rInfos.sCmd, '\t');
+    // Write the Field instruction
+    {
+        if ( bWriteRun )
+        {
+            m_pSerializer->startElementNS( XML_w, XML_r, FSEND );
+            DoWriteFieldRunProperties( pNode, nPos );
+        }
+
+        sal_Int32 nNbToken = comphelper::string::getTokenCount(rInfos.sCmd, '\t');
+
+        for ( sal_Int32 i = 0; i < nNbToken; i++ )
+        {
+            OUString sToken = rInfos.sCmd.getToken( i, '\t' );
+            if ( rInfos.eType ==  ww::eCREATEDATE
+              || rInfos.eType ==  ww::eSAVEDATE
+              || rInfos.eType ==  ww::ePRINTDATE
+              || rInfos.eType ==  ww::eDATE
+              || rInfos.eType ==  ww::eTIME )
+            {
+               sToken = sToken.replaceAll("NNNN", "dddd");
+               sToken = sToken.replaceAll("NN", "ddd");
+            }
+
+            // Write the Field command
+            DoWriteCmd( sToken );
+
+            // Replace tabs by </instrText><tab/><instrText>
+            if ( i < ( nNbToken - 1 ) )
+                RunText( "\t" );
+        }
+
+        if ( bWriteRun )
+        {
+            m_pSerializer->endElementNS( XML_w, XML_r );
+        }
+    }
 
-    for ( sal_Int32 i = 0; i < nNbToken; i++ )
+    // Write the Field separator
     {
-        OUString sToken = rInfos.sCmd.getToken( i, '\t' );
-        if ( rInfos.eType ==  ww::eCREATEDATE
-          || rInfos.eType ==  ww::eSAVEDATE
-          || rInfos.eType ==  ww::ePRINTDATE
-          || rInfos.eType ==  ww::eDATE
-          || rInfos.eType ==  ww::eTIME )
+        if ( bWriteRun )
         {
-           sToken = sToken.replaceAll("NNNN", "dddd");
-           sToken = sToken.replaceAll("NN", "ddd");
+            m_pSerializer->startElementNS( XML_w, XML_r, FSEND );
+            DoWriteFieldRunProperties( pNode, nPos );
         }
 
-        // Write the Field command
-        DoWriteCmd( sToken );
+        m_pSerializer->singleElementNS( XML_w, XML_fldChar,
+              FSNS( XML_w, XML_fldCharType ), "separate",
+              FSEND );
 
-        // Replace tabs by </instrText><tab/><instrText>
-        if ( i < ( nNbToken - 1 ) )
-            RunText( "\t" );
+        if ( bWriteRun )
+        {
+            m_pSerializer->endElementNS( XML_w, XML_r );
+        }
     }
+}
 
-    m_pSerializer->endElementNS( XML_w, XML_r );
+/// Writes properties for run that is used to separate field implementation.
+/// There are several runs are used:
+///     <w:r>
+///         <w:rPr>
+///             <!-- properties written with StartRunProperties() / EndRunProperties().
+///         </w:rPr>
+///         <w:fldChar w:fldCharType="begin" />
+///     </w:r>
+///         <w:r>
+///         <w:rPr>
+///             <!-- properties written with DoWriteFieldRunProperties()
+///         </w:rPr>
+///         <w:instrText>TIME \@"HH:mm:ss"</w:instrText>
+///     </w:r>
+///     <w:r>
+///         <w:rPr>
+///             <!-- properties written with DoWriteFieldRunProperties()
+///         </w:rPr>
+///         <w:fldChar w:fldCharType="separate" />
+///     </w:r>
+///     <w:r>
+///         <w:rPr>
+///             <!-- properties written with DoWriteFieldRunProperties()
+///         </w:rPr>
+///         <w:t>14:01:13</w:t>
+///         </w:r>
+///     <w:r>
+///         <w:rPr>
+///             <!-- properties written with DoWriteFieldRunProperties()
+///         </w:rPr>
+///         <w:fldChar w:fldCharType="end" />
+///     </w:r>
+/// See, tdf#38778
+void DocxAttributeOutput::DoWriteFieldRunProperties( const SwTextNode * pNode, sal_Int32 nPos )
+{
+    if (! pNode)
+    {
+        // nothing to do
+        return;
+    }
 
-    // Write the Field separator
-    m_pSerializer->startElementNS( XML_w, XML_r, FSEND );
-    m_pSerializer->singleElementNS( XML_w, XML_fldChar,
-          FSNS( XML_w, XML_fldCharType ), "separate",
-          FSEND );
-    m_pSerializer->endElementNS( XML_w, XML_r );
+    m_bPreventDoubleFieldsHandling = true;
+
+    {
+        m_pSerializer->startElementNS( XML_w, XML_rPr, FSEND );
+
+        // 1. output webHidden flag
+        if(GetExport().m_bHideTabLeaderAndPageNumbers && m_pHyperlinkAttrList.is() )
+        {
+            m_pSerializer->singleElementNS( XML_w, XML_webHidden, FSEND );
+        }
+
+        // 2. output color
+        if ( m_pColorAttrList.is() )
+        {
+            XFastAttributeListRef xAttrList( m_pColorAttrList.get() );
+            m_pColorAttrList.clear();
+
+            m_pSerializer->singleElementNS( XML_w, XML_color, xAttrList );
+        }
+
+        // 3. output all other character properties
+        SwWW8AttrIter aAttrIt( m_rExport, *pNode );
+        aAttrIt.OutAttr( nPos, false );
+
+        m_pSerializer->endElementNS( XML_w, XML_rPr );
+
+        // During SwWW8AttrIter::OutAttr() call the new value of the text color could be set into [m_pColorAttrList].
+        // But we do not need to keep it any more and should clean up,
+        // While the next run could define a new color that is different to current one.
+        m_pColorAttrList.clear();
+    }
+
+    m_bPreventDoubleFieldsHandling = false;
 }
 
-void DocxAttributeOutput::EndField_Impl( FieldInfos& rInfos )
+void DocxAttributeOutput::EndField_Impl( const SwTextNode* pNode, sal_Int32 nPos, FieldInfos& rInfos )
 {
     // The command has to be written before for the hyperlinks
     if ( rInfos.pField )
     {
-        CmdField_Impl( rInfos );
+        CmdField_Impl( pNode, nPos, rInfos, true );
     }
 
     // Write the bookmark start if any
@@ -1754,6 +1852,8 @@ void DocxAttributeOutput::EndField_Impl( FieldInfos& rInfos )
     {
         // Write the Field latest value
         m_pSerializer->startElementNS( XML_w, XML_r, FSEND );
+        DoWriteFieldRunProperties( pNode, nPos );
+
         OUString sExpand;
         if(rInfos.eType == ww::eCITATION)
         {
@@ -1782,6 +1882,7 @@ void DocxAttributeOutput::EndField_Impl( FieldInfos& rInfos )
     if ( rInfos.bClose  )
     {
         m_pSerializer->startElementNS( XML_w, XML_r, FSEND );
+        DoWriteFieldRunProperties( pNode, nPos );
         m_pSerializer->singleElementNS( XML_w, XML_fldChar,
               FSNS( XML_w, XML_fldCharType ), "end",
               FSEND );
@@ -1813,7 +1914,7 @@ void DocxAttributeOutput::EndField_Impl( FieldInfos& rInfos )
             m_sFieldBkm = OUString( );
 
             // Write the end of the field
-            EndField_Impl( rInfos );
+            EndField_Impl( pNode, nPos, rInfos );
         }
     }
 }
@@ -2326,8 +2427,8 @@ void DocxAttributeOutput::RawText(const OUString& /*rText*/, rtl_TextEncoding /*
 
 void DocxAttributeOutput::StartRuby( const SwTextNode& rNode, sal_Int32 nPos, const SwFormatRuby& rRuby )
 {
-    OSL_TRACE("TODO DocxAttributeOutput::StartRuby( const SwTextNode& rNode, const SwFormatRuby& rRuby )" );
-    EndRun(); // end run before starting ruby to avoid nested runs, and overlap
+    SAL_INFO("sw.ww8", "TODO DocxAttributeOutput::StartRuby( const SwTextNode& rNode, const SwFormatRuby& rRuby )" );
+    EndRun( &rNode, nPos ); // end run before starting ruby to avoid nested runs, and overlap
     assert(!m_closeHyperlinkInThisRun); // check that no hyperlink overlaps ruby
     assert(!m_closeHyperlinkInPreviousRun);
     m_pSerializer->startElementNS( XML_w, XML_ruby, FSEND );
@@ -2381,17 +2482,17 @@ void DocxAttributeOutput::StartRuby( const SwTextNode& rNode, sal_Int32 nPos, co
 
     EndRunProperties( nullptr );
     RunText( rRuby.GetText( ) );
-    EndRun( );
+    EndRun( &rNode, nPos );
     m_pSerializer->endElementNS( XML_w, XML_rt );
 
     m_pSerializer->startElementNS( XML_w, XML_rubyBase, FSEND );
     StartRun( nullptr );
 }
 
-void DocxAttributeOutput::EndRuby()
+void DocxAttributeOutput::EndRuby(const SwTextNode& rNode, sal_Int32 nPos)
 {
-    OSL_TRACE( "TODO DocxAttributeOutput::EndRuby()" );
-    EndRun( );
+    SAL_INFO("sw.ww8", "TODO DocxAttributeOutput::EndRuby()" );
+    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
@@ -6405,11 +6506,24 @@ void DocxAttributeOutput::CharFont( const SvxFontItem& rFont)
 {
     GetExport().GetId( rFont ); // ensure font info is written to fontTable.xml
     const OUString& sFontName(rFont.GetFamilyName());
-    OString sFontNameUtf8 = OUStringToOString(sFontName, RTL_TEXTENCODING_UTF8);
+    const OString sFontNameUtf8 = OUStringToOString(sFontName, RTL_TEXTENCODING_UTF8);
     if (!sFontNameUtf8.isEmpty())
+    {
+        if (m_pFontsAttrList &&
+            (   m_pFontsAttrList->hasAttribute(FSNS( XML_w, XML_ascii )) ||
+                m_pFontsAttrList->hasAttribute(FSNS( XML_w, XML_hAnsi ))    )
+            )
+        {
+            // tdf#38778: do to fields output into DOC the font could be added before and after field declaration
+            // that all sub runs of the field will have correct font inside.
+            // For DOCX we should do not add the same font information twice in the same node
+            return;
+        }
+
         AddToAttrList( m_pFontsAttrList, 2,
             FSNS( XML_w, XML_ascii ), sFontNameUtf8.getStr(),
             FSNS( XML_w, XML_hAnsi ), sFontNameUtf8.getStr() );
+    }
 }
 
 void DocxAttributeOutput::CharFontSize( const SvxFontHeightItem& rFontSize)
@@ -6858,6 +6972,9 @@ void DocxAttributeOutput::WriteExpand( const SwField* pField )
 
 void DocxAttributeOutput::WriteField_Impl( const SwField* pField, ww::eField eType, const OUString& rFieldCmd, sal_uInt8 nMode )
 {
+    if (m_bPreventDoubleFieldsHandling)
+        return;
+
     struct FieldInfos infos;
     if (pField)
         infos.pField.reset(pField->CopyField());
@@ -8397,6 +8514,9 @@ void DocxAttributeOutput::ParaGrabBag(const SfxGrabBagItem& rItem)
 
 void DocxAttributeOutput::CharGrabBag( const SfxGrabBagItem& rItem )
 {
+    if (m_bPreventDoubleFieldsHandling)
+        return;
+
     const std::map< OUString, css::uno::Any >& rMap = rItem.GetGrabBag();
 
     // get original values of theme-derived properties to check if they have changed during the edition
@@ -8598,6 +8718,7 @@ DocxAttributeOutput::DocxAttributeOutput( DocxExport &rExport, FSHelperPtr pSeri
       m_bRunTextIsOn( false ),
       m_bWritingHeaderFooter( false ),
       m_bAnchorLinkedToNode(false),
+      m_bPreventDoubleFieldsHandling( false ),
       m_sFieldBkm( ),
       m_nNextBookmarkId( 0 ),
       m_nNextAnnotationMarkId( 0 ),
diff --git a/sw/source/filter/ww8/docxattributeoutput.hxx b/sw/source/filter/ww8/docxattributeoutput.hxx
index 8413b487d0b4..2456fffac0a6 100644
--- a/sw/source/filter/ww8/docxattributeoutput.hxx
+++ b/sw/source/filter/ww8/docxattributeoutput.hxx
@@ -166,7 +166,7 @@ public:
     virtual void StartRun( const SwRedlineData* pRedlineData, bool bSingleEmptyRun = false ) override;
 
     /// End of the text run.
-    virtual void EndRun() override;
+    virtual void EndRun(const SwTextNode* pNode, sal_Int32 nPos) override;
 
     /// Called before we start outputting the attributes.
     virtual void StartRunProperties() override;
@@ -190,7 +190,7 @@ public:
     virtual void StartRuby( const SwTextNode& rNode, sal_Int32 nPos, const SwFormatRuby& rRuby ) override;
 
     /// Output ruby end.
-    virtual void EndRuby() override;
+    virtual void EndRuby(const SwTextNode& rNode, sal_Int32 nPos) override;
 
     /// Output URL start.
     virtual bool StartURL( const OUString& rUrl, const OUString& rTarget ) override;
@@ -722,10 +722,11 @@ private:
     /// Closes a currently open SDT block.
     void EndSdtBlock();
 
-    void StartField_Impl( FieldInfos& rInfos, bool bWriteRun = false );
+    void StartField_Impl( const SwTextNode* pNode, sal_Int32 nPos, FieldInfos const & rInfos, bool bWriteRun = false );
     void DoWriteCmd( const OUString& rCmd );
-    void CmdField_Impl( FieldInfos& rInfos );
-    void EndField_Impl( FieldInfos& rInfos );
+    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 );
 
     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, ... );
@@ -773,6 +774,7 @@ private:
     bool m_bAnchorLinkedToNode;
 
     /// Field data to remember in the text run
+    bool m_bPreventDoubleFieldsHandling;
     std::vector< FieldInfos > m_Fields;
     OUString m_sFieldBkm;
     sal_Int32 m_nNextBookmarkId;
diff --git a/sw/source/filter/ww8/docxexport.cxx b/sw/source/filter/ww8/docxexport.cxx
index e8e738377f25..3f62a6c56310 100644
--- a/sw/source/filter/ww8/docxexport.cxx
+++ b/sw/source/filter/ww8/docxexport.cxx
@@ -1464,7 +1464,9 @@ void DocxExport::WriteOutliner(const OutlinerParaObject& rParaObj, sal_uInt8 nTy
             nAktPos = nNextAttr;
             eChrSet = eNextChrSet;
             aAttrIter.NextPos();
-            AttrOutput().EndRun();
+
+            AttrOutput().EndRun( nullptr, 0 );
+
         } while( nAktPos < nEnd );
 //        aAttrIter.OutParaAttr(false);
         AttrOutput().EndParagraph( ww8::WW8TableNodeInfoInner::Pointer_t());
diff --git a/sw/source/filter/ww8/rtfattributeoutput.cxx b/sw/source/filter/ww8/rtfattributeoutput.cxx
index de38628bb4d5..ee3ff68665e7 100644
--- a/sw/source/filter/ww8/rtfattributeoutput.cxx
+++ b/sw/source/filter/ww8/rtfattributeoutput.cxx
@@ -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()
+void RtfAttributeOutput::EndRun(const SwTextNode* /*pNode*/, sal_Int32 /*nPos*/)
 {
     m_aRun->append(SAL_NEWLINE_STRING);
     m_aRun.appendAndClear(m_aRunText);
@@ -432,7 +432,7 @@ void RtfAttributeOutput::RawText(const OUString& rText, rtl_TextEncoding eCharSe
     m_aRunText->append(msfilter::rtfutil::OutString(rText, eCharSet));
 }
 
-void RtfAttributeOutput::StartRuby(const SwTextNode& rNode, sal_Int32 /*nPos*/, const SwFormatRuby& rRuby)
+void RtfAttributeOutput::StartRuby(const SwTextNode& rNode, sal_Int32 nPos, const SwFormatRuby& rRuby)
 {
     OUString aStr(FieldString(ww::eEQ));
     aStr += "\\* jc";
@@ -533,7 +533,7 @@ void RtfAttributeOutput::StartRuby(const SwTextNode& rNode, sal_Int32 /*nPos*/,
     nHeight = (rHeightItem.GetHeight() + 10)/20-1;
     aStr += OUString::number(nHeight);
     aStr += "(";
-    EndRun();
+    EndRun(&rNode, nPos);
     m_rExport.OutputField(nullptr, ww::eEQ, aStr, WRITEFIELD_START | WRITEFIELD_CMD_START);
     aStr  = rRuby.GetText();
     aStr += ")";
@@ -541,10 +541,10 @@ void RtfAttributeOutput::StartRuby(const SwTextNode& rNode, sal_Int32 /*nPos*/,
     m_rExport.OutputField(nullptr, ww::eEQ, aStr, 0);
 }
 
-void RtfAttributeOutput::EndRuby()
+void RtfAttributeOutput::EndRuby(const SwTextNode& rNode, sal_Int32 nPos)
 {
     m_rExport.OutputField(nullptr, ww::eEQ, ")", WRITEFIELD_END | WRITEFIELD_CLOSE);
-    EndRun();
+    EndRun(&rNode, nPos);
 }
 
 bool RtfAttributeOutput::StartURL(const OUString& rUrl, const OUString& rTarget)
diff --git a/sw/source/filter/ww8/rtfattributeoutput.hxx b/sw/source/filter/ww8/rtfattributeoutput.hxx
index 1c3e32ed9445..e465dbbe8a8f 100644
--- a/sw/source/filter/ww8/rtfattributeoutput.hxx
+++ b/sw/source/filter/ww8/rtfattributeoutput.hxx
@@ -65,7 +65,7 @@ public:
     virtual void StartRun(const SwRedlineData* pRedlineData, bool bSingleEmptyRun = false) override;
 
     /// End of the text run.
-    virtual void EndRun() override;
+    void EndRun(const SwTextNode* pNode, sal_Int32 nPos) override;
 
     /// Called before we start outputting the attributes.
     virtual void StartRunProperties() override;
@@ -91,7 +91,7 @@ public:
     virtual void StartRuby(const SwTextNode& rNode, sal_Int32 nPos, const SwFormatRuby& rRuby) override;
 
     /// Output ruby end.
-    virtual void EndRuby() override;
+    void EndRuby(const SwTextNode& rNode, sal_Int32 nPos) override;
 
     /// Output URL start.
     virtual bool StartURL(const OUString& rUrl, const OUString& rTarget) override;
diff --git a/sw/source/filter/ww8/wrtw8nds.cxx b/sw/source/filter/ww8/wrtw8nds.cxx
index 6792fea1ef79..d04facf6af8c 100644
--- a/sw/source/filter/ww8/wrtw8nds.cxx
+++ b/sw/source/filter/ww8/wrtw8nds.cxx
@@ -485,7 +485,10 @@ void SwWW8AttrIter::OutAttr( sal_Int32 nSwPos, bool bRuby )
         m_rExport.m_pOutFormatNode = &rNd;
         m_rExport.m_aCurrentCharPropStarts.push( nSwPos );
 
-        m_rExport.ExportPoolItemsToCHP( aExportItems, GetScript() );
+        // tdf#38778 Fix output of the font in DOC run for fields
+        const SvxFontItem * pFontToOutput = ( rParentFont != *pFont )? pFont : nullptr;
+
+        m_rExport.ExportPoolItemsToCHP( aExportItems, GetScript(), pFontToOutput );
 
         // HasTextItem only allowed in the above range
         m_rExport.m_aCurrentCharPropStarts.pop();
@@ -667,10 +670,16 @@ bool SwWW8AttrIter::IsTextAttr( sal_Int32 nSwPos )
         for (size_t i = 0; i < pTextAttrs->Count(); ++i)
         {
             const SwTextAttr* pHt = pTextAttrs->Get(i);
-            if ( ( pHt->HasDummyChar() || pHt->HasContent() )
-                 && (pHt->GetStart() == nSwPos) )
+            if (nSwPos == pHt->GetStart())
             {
-                return true;
+                if (pHt->HasDummyChar() || pHt->HasContent() )
+                {
+                    return true;
+                }
+            }
+            else if (nSwPos < pHt->GetStart())
+            {
+                break; // sorted by start
             }
         }
     }
@@ -880,7 +889,7 @@ void WW8AttributeOutput::StartRuby( const SwTextNode& rNode, sal_Int32 /*nPos*/,
             WRITEFIELD_START | WRITEFIELD_CMD_START );
 }
 
-void WW8AttributeOutput::EndRuby()
+void WW8AttributeOutput::EndRuby(const SwTextNode& /*rNode*/, sal_Int32 /*nPos*/)
 {
     m_rWW8Export.WriteChar( ')' );
     m_rWW8Export.OutputField( nullptr, ww::eEQ, OUString(), WRITEFIELD_END | WRITEFIELD_CLOSE );
@@ -1228,7 +1237,7 @@ void AttributeOutputBase::TOXMark( const SwTextNode& rNode, const SwTOXMark& rAt
         FieldVanish( sText, eType );
 }
 
-int SwWW8AttrIter::OutAttrWithRange(sal_Int32 nPos)
+int SwWW8AttrIter::OutAttrWithRange(const SwTextNode& rNode, sal_Int32 nPos)
 {
     int nRet = 0;
     if ( const SwpHints* pTextAttrs = rNd.GetpSwpHints() )
@@ -1262,7 +1271,7 @@ int SwWW8AttrIter::OutAttrWithRange(sal_Int32 nPos)
                     pEnd = pHt->End();
                     if (nPos == *pEnd && nPos != pHt->GetStart())
                     {
-                        m_rExport.AttrOutput().EndRuby();
+                        m_rExport.AttrOutput().EndRuby(rNode, nPos);
                         --nRet;
                     }
                     break;
@@ -1316,7 +1325,7 @@ int SwWW8AttrIter::OutAttrWithRange(sal_Int32 nPos)
                     pEnd = pHt->End();
                     if (nPos == *pEnd && nPos == pHt->GetStart())
                     {   // special case: empty must be handled here
-                        m_rExport.AttrOutput().EndRuby();
+                        m_rExport.AttrOutput().EndRuby( rNd, nPos );
                         --nRet;
                     }
                     break;
@@ -2192,7 +2201,7 @@ void MSWordExportBase::OutputTextNode( const SwTextNode& rNode )
             AppendSmartTags(rNode);
 
         bool bTextAtr = aAttrIter.IsTextAttr( nAktPos );
-        nOpenAttrWithRange += aAttrIter.OutAttrWithRange(nAktPos);
+        nOpenAttrWithRange += aAttrIter.OutAttrWithRange( rNode, nAktPos );
 
         sal_Int32 nLen = nNextAttr - nAktPos;
         if ( !bTextAtr && nLen )
@@ -2380,7 +2389,7 @@ void MSWordExportBase::OutputTextNode( const SwTextNode& rNode )
             bool bAttrWithRange = (nOpenAttrWithRange > 0);
             if ( nAktPos != nEnd )
             {
-                nOpenAttrWithRange += aAttrIter.OutAttrWithRange(nEnd);
+                nOpenAttrWithRange += aAttrIter.OutAttrWithRange( rNode, nEnd );
                 OSL_ENSURE(nOpenAttrWithRange == 0,
                     "odd to see this happening, expected 0");
             }
@@ -2429,7 +2438,7 @@ void MSWordExportBase::OutputTextNode( const SwTextNode& rNode )
 
         if( bPostponeWritingText && FLY_PROCESSED == nStateOfFlyFrame )
         {
-            AttrOutput().EndRun();
+            AttrOutput().EndRun(&rNode, nAktPos);
             //write the postponed text run
             AttrOutput().StartRun( pRedlineData, bSingleEmptyRun );
             AttrOutput().SetAnchorIsLinkedToNode( false );
@@ -2441,16 +2450,16 @@ void MSWordExportBase::OutputTextNode( const SwTextNode& rNode )
                 AttrOutput().EndRunProperties( pRedlineData );
             }
             AttrOutput().RunText( aSavedSnippet, eChrSet );
-            AttrOutput().EndRun();
+            AttrOutput().EndRun(&rNode, nAktPos);
         }
         else if( bPostponeWritingText && !aSavedSnippet.isEmpty() )
         {
             //write the postponed text run
             AttrOutput().RunText( aSavedSnippet, eChrSet );
-            AttrOutput().EndRun();
+            AttrOutput().EndRun(&rNode, nAktPos);
         }
         else
-            AttrOutput().EndRun();
+            AttrOutput().EndRun(&rNode, nAktPos);
 
         nAktPos = nNextAttr;
         UpdatePosition( &aAttrIter, nAktPos, nEnd );
diff --git a/sw/source/filter/ww8/wrtww8.hxx b/sw/source/filter/ww8/wrtww8.hxx
index 683076061470..9ee2645f2d38 100644
--- a/sw/source/filter/ww8/wrtww8.hxx
+++ b/sw/source/filter/ww8/wrtww8.hxx
@@ -584,7 +584,7 @@ public:
     void WriteSpecialText( sal_uLong nStart, sal_uLong nEnd, sal_uInt8 nTTyp );
 
     /// Export the pool items to attributes (through an attribute output class).
-    void ExportPoolItemsToCHP( ww8::PoolItems &rItems, sal_uInt16 nScript );
+    void ExportPoolItemsToCHP( ww8::PoolItems &rItems, sal_uInt16 nScript, const SvxFontItem *pFont );
 
     /// Return the numeric id of the numbering rule
     sal_uInt16 GetId( const SwNumRule& rNumRule );
@@ -1488,7 +1488,7 @@ public:
     void OutAttr( sal_Int32 nSwPos, bool bRuby = false );
     virtual const SfxPoolItem* HasTextItem( sal_uInt16 nWhich ) const override;
     virtual const SfxPoolItem& GetItem( sal_uInt16 nWhich ) const override;
-    int OutAttrWithRange(sal_Int32 nPos);
+    int OutAttrWithRange(const SwTextNode& rNode, sal_Int32 nPos);
     const SwRedlineData* GetParagraphLevelRedline( );
     const SwRedlineData* GetRunLevelRedline( sal_Int32 nPos );
     FlyProcessingState OutFlys(sal_Int32 nSwPos);
diff --git a/sw/source/filter/ww8/ww8atr.cxx b/sw/source/filter/ww8/ww8atr.cxx
index 9df4a6a7bf13..db888c475a20 100644
--- a/sw/source/filter/ww8/ww8atr.cxx
+++ b/sw/source/filter/ww8/ww8atr.cxx
@@ -204,7 +204,7 @@ bool WW8Export::CollapseScriptsforWordOk( sal_uInt16 nScript, sal_uInt16 nWhich
 
 //  Hilfsroutinen fuer Styles
 
-void MSWordExportBase::ExportPoolItemsToCHP( ww8::PoolItems &rItems, sal_uInt16 nScript )
+void MSWordExportBase::ExportPoolItemsToCHP( ww8::PoolItems &rItems, sal_uInt16 nScript, const SvxFontItem *pFont )
 {
     ww8::cPoolItemIter aEnd = rItems.end();
     for ( ww8::cPoolItemIter aI = rItems.begin(); aI != aEnd; ++aI )
@@ -220,7 +220,15 @@ void MSWordExportBase::ExportPoolItemsToCHP( ww8::PoolItems &rItems, sal_uInt16
              //add the second judgement for #i24291# definition.
              if ( nWhich == RES_TXTATR_INETFMT && ( rItems.begin()->second->Which() == RES_TXTATR_CHARFMT ) )
                  continue;
-            AttrOutput().OutputItem( *pItem );
+
+             // tdf#38778 Fix output of the font in DOC run for fields
+             if (pFont &&
+                 nWhich == RES_TXTATR_FIELD)
+             {
+                 AttrOutput().OutputItem( *pFont );
+             }
+
+             AttrOutput().OutputItem( *pItem );
         }
     }
 }
@@ -269,7 +277,7 @@ void MSWordExportBase::OutputItemSet( const SfxItemSet& rSet, bool bPapFormat, b
         ww8::PoolItems aItems;
         GetPoolItems( rSet, aItems, bExportParentItemSet );
         if ( bChpFormat )
-            ExportPoolItemsToCHP(aItems, nScript);
+            ExportPoolItemsToCHP(aItems, nScript, nullptr);
         if ( bPapFormat )
         {
             ww8::cPoolItemIter aEnd = aItems.end();
diff --git a/sw/source/filter/ww8/ww8attributeoutput.hxx b/sw/source/filter/ww8/ww8attributeoutput.hxx
index f48eb3816b51..0d41f0e33fb4 100644
--- a/sw/source/filter/ww8/ww8attributeoutput.hxx
+++ b/sw/source/filter/ww8/ww8attributeoutput.hxx
@@ -56,7 +56,7 @@ public:
     /// End of the text run.
     ///
     /// No-op for binary filters.
-    virtual void EndRun() override {}
+    virtual void EndRun(const SwTextNode* , sal_Int32 ) override {}
 
     /// Before we start outputting the attributes.
     virtual void StartRunProperties() override;
@@ -74,7 +74,7 @@ public:
     virtual void StartRuby( const SwTextNode& rNode, sal_Int32 nPos, const SwFormatRuby& rRuby ) override;
 
     /// Output ruby end.
-    virtual void EndRuby() override;
+    virtual void EndRuby(const SwTextNode& rNode, sal_Int32 nPos) override;
 
     /// Output URL start.
     virtual bool StartURL( const OUString &rUrl, const OUString &rTarget ) override;
commit 032dd35c63b0be0ea1df9245390e089052fab642
Author: Regina Henschel <rb.henschel at t-online.de>
Date:   Thu Oct 26 14:41:38 2017 +0200

    tdf#113367 Change namespace from svg to draw for attr transform
    
    The new feature of rotating images in Writer first time triggers the
    export of the attribute transform. So now it becomes visible, that
    it has the wrong namespace, see ODF 19.228 part 1.
    
    Change-Id: I00d5e6a12bd564e814679e8be862c7d08baae956
    Reviewed-on: https://gerrit.libreoffice.org/43890
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Thorsten Behrens <Thorsten.Behrens at CIB.de>
    (cherry picked from commit 11c842f450561953b11f3bc9a44404c6e83682ea)

diff --git a/xmloff/source/text/txtimp.cxx b/xmloff/source/text/txtimp.cxx
index 08dafafdcbfe..3c19db3b8a1a 100644
--- a/xmloff/source/text/txtimp.cxx
+++ b/xmloff/source/text/txtimp.cxx
@@ -364,7 +364,7 @@ static const SvXMLTokenMapEntry aTextFrameAttrTokenMap[] =
     { XML_NAMESPACE_XLINK, XML_HREF, XML_TOK_TEXT_FRAME_HREF },

... etc. - the rest is truncated


More information about the Libreoffice-commits mailing list