include/xmloff/xmltoken.hxx                                 |    1 
 offapi/com/sun/star/text/ReferenceFieldSource.idl           |    5 
 schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng |   23 
 sw/inc/fldref.hrc                                           |    1 
 sw/inc/reffld.hxx                                           |   22 
 sw/qa/core/fields/data/tdf86790.docx                        |binary
 sw/qa/core/fields/fields.cxx                                |  228 +++++
 sw/qa/extras/ooxmlexport/ooxmlexport.cxx                    |    2 
 sw/qa/extras/uiwriter/uiwriter8.cxx                         |    6 
 sw/source/core/access/accpara.cxx                           |    3 
 sw/source/core/crsr/crstrvl.cxx                             |   10 
 sw/source/core/fields/reffld.cxx                            |  484 +++++++++---
 sw/source/core/text/txtfld.cxx                              |   10 
 sw/source/filter/ww8/wrtww8.hxx                             |    3 
 sw/source/filter/ww8/ww8atr.cxx                             |   87 +-
 sw/source/filter/ww8/ww8par5.cxx                            |    7 
 sw/source/ui/fldui/fldref.cxx                               |   70 +
 sw/source/ui/fldui/fldref.hxx                               |    1 
 sw/source/uibase/docvw/edtwin2.cxx                          |    2 
 sw/source/uibase/fldui/fldmgr.cxx                           |    3 
 sw/source/uibase/utlui/content.cxx                          |    2 
 writerfilter/source/dmapper/DomainMapper_Impl.cxx           |   55 +
 writerfilter/source/dmapper/FieldTypes.hxx                  |    5 
 xmloff/inc/txtflde.hxx                                      |    1 
 xmloff/source/core/xmltoken.cxx                             |    1 
 xmloff/source/text/txtflde.cxx                              |   32 
 xmloff/source/text/txtfldi.cxx                              |    5 
 xmloff/source/token/tokens.txt                              |    1 
 28 files changed, 920 insertions(+), 150 deletions(-)

New commits:
commit 32c588dd1164aa2fc4c8120ddb74bd510cc082f9
Author:     Skyler Grey <skyler.g...@collabora.com>
AuthorDate: Thu Sep 14 08:48:16 2023 +0000
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Fri Oct 20 08:53:34 2023 +0200

    tdf#86790: Add support for a word-style styleref
    
    STYLEREF is a field type in Word which changes its content based on
    nearby paragraphs. For example, upon creating a styleref referencing
    "Heading 1" you will see the text of the nearest "Heading 1"-styled
    paragraph that is above the field.
    
    This patch implements STYLEREF in Writer as a cross-reference. By using
    "insert>cross-reference>styles" you'll be presented with a list of
    styles. Selecting one and clicking "insert" will create a field which
    has text from the "most relevant" instance of the style. To find the
    most relevant instance we first search up for paragraphs with the style,
    and if there are any we take the closest. If there weren't any, we
    search down for paragraphs with the style.
    
    This patch also updates our use of STYLEREF for chapters exported to
    docx by using it for all chapters not only those in headers and footers.
    This allows us to approximate more chapter field functionality even when
    moving between Writer and Word.
    
    Finally, this patch adds some tests for STYLEREF:
    - testTdf86790 tests that the "sample file with STYLEREF" document from
      tdf#86790 has the correct fields
    - testStyleRefSearchUp tests that the STYLEREF searches up when there
      are bits of text both above and below it
    - testStyleRefSearchDown tests that the STYLEREF searches down when
      there are bits of text below it only
    - testMarginalStyleRef tests that the STYLEREF searches from the page
      top when it is placed in a footer
    - testFootnotetyleRef tests that the STYLEREF searches from the
      reference mark when it is placed in a footnote
    
    Still TODO:
    - [  ] Update documentation
    - [  ] Implement reverse-searching (\l) and nondelimiter
           suppression (\t)
           - Probably these 2 will be in a followup patch
    
    Change-Id: I25dd7a6940abee5651a784b9059fe23b32547d6c
    Signed-off-by: Skyler Grey <skyler.g...@collabora.com>
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/157456
    Tested-by: Jenkins
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>

diff --git a/include/xmloff/xmltoken.hxx b/include/xmloff/xmltoken.hxx
index 773d54f79318..00d0d5f349e1 100644
--- a/include/xmloff/xmltoken.hxx
+++ b/include/xmloff/xmltoken.hxx
@@ -1902,6 +1902,7 @@ namespace xmloff::token {
         XML_STRUCTURE_PROTECTED,
         XML_STYLE,
         XML_STYLE_NAME,
+        XML_STYLE_REF,
         XML_STYLES,
         XML_STYLESHEET,
         XML_SUB_TABLE,
diff --git a/offapi/com/sun/star/text/ReferenceFieldSource.idl 
b/offapi/com/sun/star/text/ReferenceFieldSource.idl
index 1892fdc04cd8..91295fef2844 100644
--- a/offapi/com/sun/star/text/ReferenceFieldSource.idl
+++ b/offapi/com/sun/star/text/ReferenceFieldSource.idl
@@ -44,6 +44,11 @@ published constants ReferenceFieldSource
     /** The source is an endnote.
     */
     const short ENDNOTE = 4;
+
+    /** The source is a style.
+    @since LibreOffice 24.2
+    */
+    const short STYLE = 5;
 };
 
 
diff --git a/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng 
b/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng
index 6b52ab7307df..ec0a86afaae4 100644
--- a/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng
+++ b/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng
@@ -2179,6 +2179,29 @@ 
xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.
     </rng:element>
   </rng:define>
 
+    <!-- TODO no proposal -->
+  <rng:define name="loext-style-reference">
+    <rng:element name="loext:style-ref">
+      <rng:interleave>
+        <rng:ref name="text-common-ref-content"/>
+        <rng:optional>
+          <rng:attribute name="text:reference-format">
+            <rng:choice>
+              <rng:value>text</rng:value>
+              <rng:value>direction</rng:value>
+              <rng:value>number</rng:value>
+              <rng:value>number-no-superior</rng:value>
+              <rng:value>number-all-superior</rng:value>
+            </rng:choice>
+          </rng:attribute>
+        </rng:optional>
+      </rng:interleave>
+    </rng:element>
+  </rng:define>
+  <rng:define name="paragraph-content" combine="choice">
+    <rng:ref name="loext-style-reference"/>
+  </rng:define>
+
   <rng:define name="loext-qrcode">
     <rng:element name="loext:qrcode">
       <rng:attribute name="office:string-value">
diff --git a/sw/inc/fldref.hrc b/sw/inc/fldref.hrc
index d28a1ea43cb5..a48d2d4e4a06 100644
--- a/sw/inc/fldref.hrc
+++ b/sw/inc/fldref.hrc
@@ -31,6 +31,7 @@ const TranslateId FLD_REF_PAGE_TYPES[] =
     NC_("fldrefpage|liststore1", "Endnotes"),
     NC_("fldrefpage|liststore1", "Headings"),
     NC_("fldrefpage|liststore1", "Numbered Paragraphs"),
+    NC_("fldrefpage|liststore1", "Styles"),
 };
 
 #endif
diff --git a/sw/inc/reffld.hxx b/sw/inc/reffld.hxx
index 931441d27725..bf9d563ab2ac 100644
--- a/sw/inc/reffld.hxx
+++ b/sw/inc/reffld.hxx
@@ -26,8 +26,10 @@
 class SfxPoolItem;
 class SwDoc;
 class SwTextNode;
+class SwContentFrame;
 class SwTextField;
 class SwRootFrame;
+class SwFrame;
 
 bool IsFrameBehind( const SwTextNode& rMyNd, sal_Int32 nMySttPos,
                     const SwTextNode& rBehindNd, sal_Int32 nSttPos );
@@ -39,7 +41,8 @@ enum REFERENCESUBTYPE
     REF_BOOKMARK,
     REF_OUTLINE,
     REF_FOOTNOTE,
-    REF_ENDNOTE
+    REF_ENDNOTE,
+    REF_STYLE
 };
 
 enum REFERENCEMARK
@@ -80,7 +83,8 @@ public:
     static SwTextNode* FindAnchor( SwDoc* pDoc, const OUString& rRefMark,
                                         sal_uInt16 nSubType, sal_uInt16 nSeqNo,
                                         sal_Int32* pStt, sal_Int32* pEnd = 
nullptr,
-                                        SwRootFrame const* pLayout = nullptr);
+                                        SwRootFrame const* pLayout = nullptr,
+                                        SwTextNode* pSelf = nullptr, SwFrame* 
pFrame = nullptr);
     void UpdateGetReferences();
 };
 
@@ -111,11 +115,13 @@ public:
     // #i81002#
     /** The <SwTextField> instance, which represents the text attribute for the
        <SwGetRefField> instance, has to be passed to the method.
-       This <SwTextField> instance is needed for the reference format type 
REF_UPDOWN
-       and REF_NUMBER.
+       This <SwTextField> instance is needed for the reference format type 
REF_UPDOWN, REF_NUMBER
+       and REF_STYLE.
        Note: This instance may be NULL (field in Undo/Redo). This will cause
        no update for these reference format types. */
-    void                UpdateField( const SwTextField* pFieldTextAttr );
+    void                UpdateField( const SwTextField* pFieldTextAttr, 
SwFrame* pFrame );
+    void                UpdateField( const SwTextField* pFieldTextAttr, 
SwFrame* pFrame,
+                                     const SwRootFrame* const pLayout, 
OUString& rText );
 
     void                SetExpand( const OUString& rStr );
 
@@ -126,9 +132,9 @@ public:
     // --> #i81002#
     bool IsRefToHeadingCrossRefBookmark() const;
     bool IsRefToNumItemCrossRefBookmark() const;
-    const SwTextNode* GetReferencedTextNode() const;
+    const SwTextNode* GetReferencedTextNode(SwTextNode* pTextNode, SwFrame* 
pFrame) const;
     // #i85090#
-    OUString GetExpandedTextOfReferencedTextNode(SwRootFrame const& rLayout) 
const;
+    OUString GetExpandedTextOfReferencedTextNode(SwRootFrame const& rLayout, 
SwTextNode* pTextNode, SwFrame* pFrame) const;
 
     /// Get/set SequenceNo (of interest only for REF_SEQUENCEFLD).
     sal_uInt16              GetSeqNo() const        { return m_nSeqNo; }
@@ -138,6 +144,8 @@ public:
     virtual OUString    GetPar1() const override;
     virtual void        SetPar1(const OUString& rStr) override;
 
+    void SetText(OUString sText, SwRootFrame* pLayout);
+
     virtual OUString    GetPar2() const override;
     virtual bool        QueryValue( css::uno::Any& rVal, sal_uInt16 nWhichId ) 
const override;
     virtual bool        PutValue( const css::uno::Any& rVal, sal_uInt16 
nWhichId ) override;
diff --git a/sw/qa/core/fields/data/tdf86790.docx 
b/sw/qa/core/fields/data/tdf86790.docx
new file mode 100644
index 000000000000..a45c03f6b898
Binary files /dev/null and b/sw/qa/core/fields/data/tdf86790.docx differ
diff --git a/sw/qa/core/fields/fields.cxx b/sw/qa/core/fields/fields.cxx
index f2fdd808734f..158e1c35dc2b 100644
--- a/sw/qa/core/fields/fields.cxx
+++ b/sw/qa/core/fields/fields.cxx
@@ -7,6 +7,36 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  */
 
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/frame/XStorable.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/container/XIndexAccess.hpp>
+#include <com/sun/star/text/ControlCharacter.hpp>
+#include <com/sun/star/text/ReferenceFieldPart.hpp>
+#include <com/sun/star/text/ReferenceFieldSource.hpp>
+#include <com/sun/star/text/XFootnote.hpp>
+#include <com/sun/star/text/XFootnotesSupplier.hpp>
+#include <com/sun/star/text/XSimpleText.hpp>
+#include <com/sun/star/text/XTextField.hpp>
+#include <com/sun/star/text/XTextRange.hpp>
+#include <com/sun/star/frame/XStorable.hpp>
+#include <com/sun/star/text/XPageCursor.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/beans/XPropertySetInfo.hpp>
+#include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
+#include <com/sun/star/text/XSimpleText.hpp>
+#include <com/sun/star/text/XText.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <com/sun/star/text/XPageCursor.hpp>
+#include <com/sun/star/text/XTextCursor.hpp>
+#include <com/sun/star/uno/Any.h>
+#include <com/sun/star/uno/Reference.h>
+#include <com/sun/star/uno/Sequence.h>
+#include <cppunit/TestAssert.h>
+#include <cppunit/extensions/HelperMacros.h>
+#include <rtl/ustring.hxx>
+#include <sal/types.h>
 #include <swmodeltestbase.hxx>
 
 #include <com/sun/star/text/XTextDocument.hpp>
@@ -132,6 +162,204 @@ CPPUNIT_TEST_FIXTURE(Test, testChapterFieldsFollowedBy)
         CPPUNIT_ASSERT_EQUAL(sValue, xField->getPresentation(false));
     }
 }
+
+CPPUNIT_TEST_FIXTURE(Test, testTdf86790)
+{
+    loadFromURL(u"tdf86790.docx");
+
+    uno::Reference<text::XTextFieldsSupplier> xTextFieldsSupplier(mxComponent, 
uno::UNO_QUERY);
+    uno::Reference<container::XEnumerationAccess> xFieldsAccess(
+        xTextFieldsSupplier->getTextFields());
+    uno::Reference<container::XEnumeration> 
xFields(xFieldsAccess->createEnumeration());
+
+    // Similarly to testChapterFieldsFollowedBy, the fields are enumerated 
with #1 first and everything else in reverse order
+    std::vector<std::pair<OUString, OUString>> aFieldValues = {
+        { " Heading 1", "1" }, // #1
+        { " foobar", "22.2" }, // #5
+        { " foobar", "4" }, // #4
+        { " Heading 2", "1.1" }, // #3
+        { " Heading 2", "1.1" }, // #2
+    };
+
+    for (const auto& sValue : aFieldValues)
+    {
+        CPPUNIT_ASSERT(xFields->hasMoreElements());
+        uno::Reference<text::XTextField> xField(xFields->nextElement(), 
uno::UNO_QUERY);
+        CPPUNIT_ASSERT_EQUAL(sValue.first, xField->getPresentation(true));
+        CPPUNIT_ASSERT_EQUAL(sValue.second, xField->getPresentation(false));
+    }
+}
+
+/// If there is referenced text both above and below, STYLEREF searches up
+CPPUNIT_TEST_FIXTURE(Test, testStyleRefSearchUp)
+{
+    createSwDoc();
+
+    uno::Reference<text::XTextDocument> xTextDocument(mxComponent, 
uno::UNO_QUERY);
+    uno::Reference<text::XText> xText = xTextDocument->getText();
+
+    uno::Reference<text::XTextCursor> xCursor = xText->createTextCursor();
+    uno::Reference<beans::XPropertySet> xCursorPropertySet(xCursor, 
uno::UNO_QUERY);
+
+    xCursorPropertySet->setPropertyValue("ParaStyleName", 
uno::Any(OUString("Heading 1")));
+    xText->insertString(xCursor, "Heading far above field", false);
+    xText->insertControlCharacter(xCursor, 
text::ControlCharacter::PARAGRAPH_BREAK, false);
+
+    xCursorPropertySet->setPropertyValue("ParaStyleName", 
uno::Any(OUString("Heading 1")));
+    xText->insertString(xCursor, "Heading above field", false);
+    xText->insertControlCharacter(xCursor, 
text::ControlCharacter::PARAGRAPH_BREAK, false);
+
+    uno::Reference<lang::XMultiServiceFactory> xFactory(mxComponent, 
uno::UNO_QUERY);
+    uno::Reference<text::XTextField> xField(
+        xFactory->createInstance("com.sun.star.text.TextField.GetReference"), 
uno::UNO_QUERY);
+
+    uno::Reference<beans::XPropertySet> xFieldPropertySet(xField, 
uno::UNO_QUERY);
+    xFieldPropertySet->setPropertyValue("ReferenceFieldSource",
+                                        
uno::Any(sal_Int16(text::ReferenceFieldSource::STYLE)));
+    xFieldPropertySet->setPropertyValue("ReferenceFieldPart",
+                                        
uno::Any(sal_Int16(text::ReferenceFieldPart::TEXT)));
+    xFieldPropertySet->setPropertyValue("SourceName", 
uno::Any(OUString("Heading 1")));
+
+    uno::Reference<text::XTextCursor> xFieldCursor = xText->createTextCursor();
+
+    xText->insertControlCharacter(xCursor, 
text::ControlCharacter::PARAGRAPH_BREAK, false);
+    xCursorPropertySet->setPropertyValue("ParaStyleName", 
uno::Any(OUString("Heading 1")));
+    xText->insertString(xCursor, "Heading below field", false);
+
+    xField->attach(xFieldCursor);
+    CPPUNIT_ASSERT_EQUAL(OUString("Heading above field"), 
xField->getPresentation(false));
+}
+
+/// If there is referenced text both above and below, STYLEREF searches down
+CPPUNIT_TEST_FIXTURE(Test, testStyleRefSearchDown)
+{
+    createSwDoc();
+
+    uno::Reference<text::XTextDocument> xTextDocument(mxComponent, 
uno::UNO_QUERY);
+    uno::Reference<text::XText> xText = xTextDocument->getText();
+
+    uno::Reference<text::XTextCursor> xCursor = xText->createTextCursor();
+    uno::Reference<beans::XPropertySet> xCursorPropertySet(xCursor, 
uno::UNO_QUERY);
+
+    uno::Reference<lang::XMultiServiceFactory> xFactory(mxComponent, 
uno::UNO_QUERY);
+    uno::Reference<text::XTextField> xField(
+        xFactory->createInstance("com.sun.star.text.TextField.GetReference"), 
uno::UNO_QUERY);
+
+    uno::Reference<beans::XPropertySet> xFieldPropertySet(xField, 
uno::UNO_QUERY);
+    xFieldPropertySet->setPropertyValue("ReferenceFieldSource",
+                                        
uno::Any(sal_Int16(text::ReferenceFieldSource::STYLE)));
+    xFieldPropertySet->setPropertyValue("ReferenceFieldPart",
+                                        
uno::Any(sal_Int16(text::ReferenceFieldPart::TEXT)));
+    xFieldPropertySet->setPropertyValue("SourceName", 
uno::Any(OUString("Heading 1")));
+
+    uno::Reference<text::XTextCursor> xFieldCursor = xText->createTextCursor();
+
+    xText->insertControlCharacter(xCursor, 
text::ControlCharacter::PARAGRAPH_BREAK, false);
+    xCursorPropertySet->setPropertyValue("ParaStyleName", 
uno::Any(OUString("Heading 1")));
+    xText->insertString(xCursor, "Heading below field", false);
+
+    xText->insertControlCharacter(xCursor, 
text::ControlCharacter::PARAGRAPH_BREAK, false);
+    xCursorPropertySet->setPropertyValue("ParaStyleName", 
uno::Any(OUString("Heading 1")));
+    xText->insertString(xCursor, "Heading far below field", false);
+
+    xField->attach(xFieldCursor);
+    CPPUNIT_ASSERT_EQUAL(OUString("Heading below field"), 
xField->getPresentation(false));
+}
+
+/// STYLEREFs in marginals (headers or footers) should search in the page they 
are on first, regardless if there is anything above them
+CPPUNIT_TEST_FIXTURE(Test, testMarginalStyleRef)
+{
+    createSwDoc();
+
+    uno::Reference<text::XTextDocument> xTextDocument(mxComponent, 
uno::UNO_QUERY);
+    uno::Reference<text::XText> xText = xTextDocument->getText();
+
+    uno::Reference<text::XTextCursor> xCursor = xText->createTextCursor();
+    uno::Reference<beans::XPropertySet> xCursorPropertySet(xCursor, 
uno::UNO_QUERY);
+
+    xCursorPropertySet->setPropertyValue("ParaStyleName", 
uno::Any(OUString("Heading 1")));
+    xText->insertString(xCursor, "Top heading on page", false);
+    xText->insertControlCharacter(xCursor, 
text::ControlCharacter::PARAGRAPH_BREAK, false);
+
+    xCursorPropertySet->setPropertyValue("ParaStyleName", 
uno::Any(OUString("Heading 1")));
+    xText->insertString(xCursor, "Bottom heading on page", false);
+    xText->insertControlCharacter(xCursor, 
text::ControlCharacter::PARAGRAPH_BREAK, false);
+
+    uno::Reference<lang::XMultiServiceFactory> xFactory(mxComponent, 
uno::UNO_QUERY);
+    uno::Reference<text::XTextField> xField(
+        xFactory->createInstance("com.sun.star.text.TextField.GetReference"), 
uno::UNO_QUERY);
+
+    uno::Reference<style::XStyleFamiliesSupplier> 
xStyleFamiliesSupplier(mxComponent,
+                                                                         
uno::UNO_QUERY);
+    uno::Reference<container::XNameContainer> xParagraphStylesContainer(
+        xStyleFamiliesSupplier->getStyleFamilies()->getByName("PageStyles"), 
uno::UNO_QUERY);
+
+    uno::Reference<beans::XPropertySet> xPagePropertySet(
+        xParagraphStylesContainer->getByName("Standard"), uno::UNO_QUERY);
+
+    xPagePropertySet->setPropertyValue("FooterIsOn", uno::Any(true));
+    uno::Reference<text::XText> 
xFooterText(xPagePropertySet->getPropertyValue("FooterText"),
+                                            uno::UNO_QUERY);
+
+    uno::Reference<beans::XPropertySet> xFieldPropertySet(xField, 
uno::UNO_QUERY);
+    xFieldPropertySet->setPropertyValue("ReferenceFieldSource",
+                                        
uno::Any(sal_Int16(text::ReferenceFieldSource::STYLE)));
+    xFieldPropertySet->setPropertyValue("ReferenceFieldPart",
+                                        
uno::Any(sal_Int16(text::ReferenceFieldPart::TEXT)));
+    xFieldPropertySet->setPropertyValue("SourceName", 
uno::Any(OUString("Heading 1")));
+
+    uno::Reference<text::XTextRange> xFooterCursor = 
xFooterText->createTextCursor();
+    xField->attach(xFooterCursor);
+
+    CPPUNIT_ASSERT_EQUAL(OUString("Top heading on page"), 
xField->getPresentation(false));
+}
+
+/// STYLEREFs in footnotes should search from the point of the reference mark
+CPPUNIT_TEST_FIXTURE(Test, testFootnoteStyleRef)
+{
+    createSwDoc();
+
+    uno::Reference<text::XTextDocument> xTextDocument(mxComponent, 
uno::UNO_QUERY);
+    uno::Reference<text::XText> xText = xTextDocument->getText();
+
+    uno::Reference<text::XTextCursor> xCursor = xText->createTextCursor();
+    uno::Reference<beans::XPropertySet> xCursorPropertySet(xCursor, 
uno::UNO_QUERY);
+
+    xCursorPropertySet->setPropertyValue("ParaStyleName", 
uno::Any(OUString("Heading 1")));
+    xText->insertString(xCursor, "Heading far above reference mark", false);
+    xText->insertControlCharacter(xCursor, 
text::ControlCharacter::PARAGRAPH_BREAK, false);
+
+    xCursorPropertySet->setPropertyValue("ParaStyleName", 
uno::Any(OUString("Heading 1")));
+    xText->insertString(xCursor, "Heading above reference mark", false);
+    xText->insertControlCharacter(xCursor, 
text::ControlCharacter::PARAGRAPH_BREAK, false);
+
+    uno::Reference<lang::XMultiServiceFactory> xFactory(mxComponent, 
uno::UNO_QUERY);
+
+    uno::Reference<text::XFootnote> xFootnote(
+        xFactory->createInstance("com.sun.star.text.Footnote"), 
uno::UNO_QUERY);
+    xFootnote->setLabel("Style reference mark");
+    xText->insertTextContent(xCursor, xFootnote, false);
+
+    xText->insertControlCharacter(xCursor, 
text::ControlCharacter::PARAGRAPH_BREAK, false);
+    xCursorPropertySet->setPropertyValue("ParaStyleName", 
uno::Any(OUString("Heading 1")));
+    xText->insertString(xCursor, "Heading below reference mark", false);
+
+    uno::Reference<text::XTextField> xField(
+        xFactory->createInstance("com.sun.star.text.TextField.GetReference"), 
uno::UNO_QUERY);
+
+    uno::Reference<beans::XPropertySet> xFieldPropertySet(xField, 
uno::UNO_QUERY);
+    xFieldPropertySet->setPropertyValue("ReferenceFieldSource",
+                                        
uno::Any(sal_Int16(text::ReferenceFieldSource::STYLE)));
+    xFieldPropertySet->setPropertyValue("ReferenceFieldPart",
+                                        
uno::Any(sal_Int16(text::ReferenceFieldPart::TEXT)));
+    xFieldPropertySet->setPropertyValue("SourceName", 
uno::Any(OUString("Heading 1")));
+
+    uno::Reference<text::XSimpleText> xFootnoteText(xFootnote, uno::UNO_QUERY);
+    uno::Reference<text::XTextRange> xFootnoteCursor = 
xFootnoteText->createTextCursor();
+    xField->attach(xFootnoteCursor);
+
+    CPPUNIT_ASSERT_EQUAL(OUString("Heading above reference mark"), 
xField->getPresentation(false));
+}
 }
 
 CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport.cxx 
b/sw/qa/extras/ooxmlexport/ooxmlexport.cxx
index cbca150319b7..c4530aa44f6a 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport.cxx
@@ -582,7 +582,7 @@ DECLARE_OOXMLEXPORT_TEST(testMultiPageToc, 
"multi-page-toc.docx")
     CPPUNIT_ASSERT_EQUAL(OUString("Table of Contents1"), 
xTextSection->getName());
     // There should be a field in the header as well.
     uno::Reference<text::XText> xHeaderText = getProperty< 
uno::Reference<text::XText> >(getStyles("PageStyles")->getByName("Standard"), 
"HeaderText");
-    CPPUNIT_ASSERT_EQUAL(OUString("TextFieldStart"), 
getProperty<OUString>(getRun(getParagraphOfText(1, xHeaderText), 1), 
"TextPortionType"));
+    CPPUNIT_ASSERT_EQUAL(OUString("TextField"), 
getProperty<OUString>(getRun(getParagraphOfText(1, xHeaderText), 1), 
"TextPortionType"));
 }
 
 DECLARE_OOXMLEXPORT_TEST(testTextboxTable, "textbox-table.docx")
diff --git a/sw/qa/extras/uiwriter/uiwriter8.cxx 
b/sw/qa/extras/uiwriter/uiwriter8.cxx
index d61bbf289663..8e4869c5d694 100644
--- a/sw/qa/extras/uiwriter/uiwriter8.cxx
+++ b/sw/qa/extras/uiwriter/uiwriter8.cxx
@@ -2454,9 +2454,9 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testTdf128106)
     CPPUNIT_ASSERT_EQUAL(sal_uInt16(REF_BOOKMARK), 
fields[0]->GetField()->GetSubType());
     CPPUNIT_ASSERT_EQUAL(OUString("bookmarkchapter1_text"),
                          static_cast<SwGetRefField 
const*>(fields[0]->GetField())->GetSetRefName());
-    CPPUNIT_ASSERT_EQUAL(OUString("Text"),
-                         static_cast<SwGetRefField 
const*>(fields[0]->GetField())
-                             
->GetExpandedTextOfReferencedTextNode(*pWrtShell->GetLayout()));
+    CPPUNIT_ASSERT_EQUAL(OUString("Text"), static_cast<SwGetRefField 
const*>(fields[0]->GetField())
+                                               
->GetExpandedTextOfReferencedTextNode(
+                                                   *pWrtShell->GetLayout(), 
nullptr, nullptr));
     CPPUNIT_ASSERT_EQUAL(sal_uInt16(REF_BOOKMARK), 
fields[1]->GetField()->GetSubType());
     CPPUNIT_ASSERT(
         static_cast<SwGetRefField 
const*>(fields[1]->GetField())->IsRefToHeadingCrossRefBookmark());
diff --git a/sw/source/core/access/accpara.cxx 
b/sw/source/core/access/accpara.cxx
index 578c71b7c21a..87d8dc1f73c5 100644
--- a/sw/source/core/access/accpara.cxx
+++ b/sw/source/core/access/accpara.cxx
@@ -1228,6 +1228,9 @@ OUString 
SwAccessibleParagraph::GetFieldTypeNameAtIndex(sal_Int32 nIndex)
                     case REF_SEQUENCEFLD:
                         sEntry = static_cast<const 
SwGetRefField*>(pField)->GetSetRefName();
                         break;
+                    case REF_STYLE:
+                        sEntry = "StyleRef";
+                        break;
                     }
                     //Get format string
                     strTypeName = sEntry;
diff --git a/sw/source/core/crsr/crstrvl.cxx b/sw/source/core/crsr/crstrvl.cxx
index 3face1677c13..93d22362745c 100644
--- a/sw/source/core/crsr/crstrvl.cxx
+++ b/sw/source/core/crsr/crstrvl.cxx
@@ -1409,8 +1409,14 @@ bool SwCursorShell::GotoRefMark( const OUString& 
rRefMark, sal_uInt16 nSubType,
     SwCursorSaveState aSaveState( *m_pCurrentCursor );
 
     sal_Int32 nPos = -1;
-    SwTextNode* pTextNd = SwGetRefFieldType::FindAnchor( GetDoc(), rRefMark,
-                                nSubType, nSeqNo, &nPos, nullptr, GetLayout());
+
+    SwPaM* pCursor = GetCursor();
+    SwPosition* pPos = pCursor->GetPoint();
+    SwTextNode* pRefTextNd = pPos->GetNode().GetTextNode();
+    SwContentFrame* pRefFrame = GetCurrFrame();
+
+    SwTextNode* pTextNd = SwGetRefFieldType::FindAnchor(GetDoc(), rRefMark,
+                                nSubType, nSeqNo, &nPos, nullptr, GetLayout(), 
pRefTextNd, pRefFrame);
     if( !pTextNd || !pTextNd->GetNodes().IsDocNodes() )
         return false;
 
diff --git a/sw/source/core/fields/reffld.cxx b/sw/source/core/fields/reffld.cxx
index d8a66d6ec7a7..442e1644a753 100644
--- a/sw/source/core/fields/reffld.cxx
+++ b/sw/source/core/fields/reffld.cxx
@@ -42,6 +42,7 @@
 #include <reffld.hxx>
 #include <expfld.hxx>
 #include <txtfrm.hxx>
+#include <notxtfrm.hxx>
 #include <flyfrm.hxx>
 #include <pagedesc.hxx>
 #include <IMark.hxx>
@@ -65,6 +66,7 @@
 #include <string_view>
 #include <map>
 #include <algorithm>
+#include <deque>
 
 using namespace ::com::sun::star;
 using namespace ::com::sun::star::text;
@@ -349,11 +351,11 @@ static void lcl_formatReferenceLanguage( OUString& 
rRefText,
 SwGetRefField::SwGetRefField( SwGetRefFieldType* pFieldType,
                               OUString aSetRef, OUString 
aSetReferenceLanguage, sal_uInt16 nSubTyp,
                               sal_uInt16 nSequenceNo, sal_uLong nFormat )
-    : SwField( pFieldType, nFormat ),
-      m_sSetRefName( std::move(aSetRef) ),
-      m_sSetReferenceLanguage( std::move(aSetReferenceLanguage) ),
-      m_nSubType( nSubTyp ),
-      m_nSeqNo( nSequenceNo )
+    : SwField(pFieldType, nFormat),
+      m_sSetRefName(std::move(aSetRef)),
+      m_sSetReferenceLanguage(std::move(aSetReferenceLanguage)),
+      m_nSubType(nSubTyp),
+      m_nSeqNo(nSequenceNo)
 {
 }
 
@@ -361,6 +363,18 @@ SwGetRefField::~SwGetRefField()
 {
 }
 
+void SwGetRefField::SetText(OUString sText, SwRootFrame* pLayout)
+{
+    if (pLayout->IsHideRedlines())
+    {
+        m_sTextRLHidden = sText;
+    }
+    else
+    {
+        m_sText = sText;
+    }
+}
+
 OUString SwGetRefField::GetDescription() const
 {
     return SwResId(STR_REFERENCE);
@@ -389,13 +403,14 @@ bool SwGetRefField::IsRefToNumItemCrossRefBookmark() const
         ::sw::mark::CrossRefNumItemBookmark::IsLegalName(m_sSetRefName);
 }
 
-const SwTextNode* SwGetRefField::GetReferencedTextNode() const
+const SwTextNode* SwGetRefField::GetReferencedTextNode(SwTextNode* pTextNode, 
SwFrame* pFrame) const
 {
     SwGetRefFieldType *pTyp = dynamic_cast<SwGetRefFieldType*>(GetTyp());
     if (!pTyp)
         return nullptr;
     sal_Int32 nDummy = -1;
-    return SwGetRefFieldType::FindAnchor( &pTyp->GetDoc(), m_sSetRefName, 
m_nSubType, m_nSeqNo, &nDummy );
+    return SwGetRefFieldType::FindAnchor( &pTyp->GetDoc(), m_sSetRefName, 
m_nSubType, m_nSeqNo, &nDummy,
+                                          nullptr, nullptr, pTextNode, pFrame 
);
 }
 
 // strikethrough for tooltips using Unicode combining character
@@ -411,9 +426,9 @@ static OUString 
lcl_formatStringByCombiningCharacter(std::u16string_view sText,
 
 // #i85090#
 OUString SwGetRefField::GetExpandedTextOfReferencedTextNode(
-        SwRootFrame const& rLayout) const
+        SwRootFrame const& rLayout, SwTextNode* pTextNode, SwFrame* pFrame) 
const
 {
-    const SwTextNode* pReferencedTextNode( GetReferencedTextNode() );
+    const SwTextNode* pReferencedTextNode( GetReferencedTextNode(pTextNode, 
pFrame) );
     if ( !pReferencedTextNode )
         return OUString();
 
@@ -481,38 +496,43 @@ static void FilterText(OUString & rText, LanguageType 
const eLang,
 }
 
 // #i81002# - parameter <pFieldTextAttr> added
-void SwGetRefField::UpdateField( const SwTextField* pFieldTextAttr )
+void SwGetRefField::UpdateField( const SwTextField* pFieldTextAttr, SwFrame* 
pFrame )
 {
-    m_sText.clear();
-    m_sTextRLHidden.clear();
+    SwDoc& rDoc = static_cast<SwGetRefFieldType*>(GetTyp())->GetDoc();
 
+    for (SwRootFrame const* const pLay : rDoc.GetAllLayouts())
+    {
+        if (pLay->IsHideRedlines())
+        {
+            UpdateField(pFieldTextAttr, pFrame, pLay, m_sTextRLHidden);
+        }
+        else
+        {
+            UpdateField(pFieldTextAttr, pFrame, pLay, m_sText);
+        }
+    }
+}
+
+void SwGetRefField::UpdateField(const SwTextField* pFieldTextAttr, SwFrame* 
pFrameContainingField,
+                                const SwRootFrame* const pLayout, OUString& 
rText)
+{
     SwDoc& rDoc = static_cast<SwGetRefFieldType*>(GetTyp())->GetDoc();
+
+    rText.clear();
+
     // finding the reference target (the number)
     sal_Int32 nNumStart = -1;
     sal_Int32 nNumEnd = -1;
     SwTextNode* pTextNd = SwGetRefFieldType::FindAnchor(
-        &rDoc, m_sSetRefName, m_nSubType, m_nSeqNo, &nNumStart, &nNumEnd
+        &rDoc, m_sSetRefName, m_nSubType, m_nSeqNo, &nNumStart, &nNumEnd,
+        pLayout, pFieldTextAttr ? pFieldTextAttr->GetpTextNode() : nullptr, 
pFrameContainingField
     );
     // not found?
     if ( !pTextNd )
     {
-        m_sText = SwViewShell::GetShellRes()->aGetRefField_RefItemNotFound;
-        m_sTextRLHidden = m_sText;
-        return ;
-    }
+        rText = SwViewShell::GetShellRes()->aGetRefField_RefItemNotFound;
 
-    SwRootFrame const* pLayout(nullptr);
-    SwRootFrame const* pLayoutRLHidden(nullptr);
-    for (SwRootFrame const*const pLay : rDoc.GetAllLayouts())
-    {
-        if (pLay->IsHideRedlines())
-        {
-            pLayoutRLHidden = pLay;
-        }
-        else
-        {
-            pLayout = pLay;
-        }
+        return;
     }
 
     // where is the category name (e.g. "Illustration")?
@@ -607,18 +627,21 @@ void SwGetRefField::UpdateField( const SwTextField* 
pFieldTextAttr )
                     SwTextFootnote* const pFootnoteIdx = 
rDoc.GetFootnoteIdxs()[i];
                     if( m_nSeqNo == pFootnoteIdx->GetSeqRefNo() )
                     {
-                        m_sText = 
pFootnoteIdx->GetFootnote().GetViewNumStr(rDoc, nullptr);
-                        m_sTextRLHidden = 
pFootnoteIdx->GetFootnote().GetViewNumStr(rDoc, pLayoutRLHidden);
+                        rText = 
pFootnoteIdx->GetFootnote().GetViewNumStr(rDoc, pLayout);
                         if (!m_sSetReferenceLanguage.isEmpty())
                         {
-                            lcl_formatReferenceLanguage(m_sText, false, 
GetLanguage(), m_sSetReferenceLanguage);
-                            lcl_formatReferenceLanguage(m_sTextRLHidden, 
false, GetLanguage(), m_sSetReferenceLanguage);
+                            lcl_formatReferenceLanguage(rText, false, 
GetLanguage(), m_sSetReferenceLanguage);
                         }
                         break;
                     }
                 }
                 return;
 
+            case REF_STYLE:
+                nStart = 0;
+                nEnd = nLen;
+                break;
+
             case REF_SETREFATTR:
                 nStart = nNumStart;
                 nEnd = nNumEnd;
@@ -630,26 +653,32 @@ void SwGetRefField::UpdateField( const SwTextField* 
pFieldTextAttr )
 
             if( nStart != nEnd ) // a section?
             {
-                m_sText = pTextNd->GetExpandText(pLayout, nStart, nEnd - 
nStart, false, false, false, ExpandMode::HideDeletions);
-                // show the referenced text without the deletions, but if the 
whole text was
-                // deleted, show the original text for the sake of the 
comfortable reviewing
-                // (with strikethrough in tooltip, see 
GetExpandedTextOfReferencedTextNode())
-                if ( m_sText.isEmpty() )
-                    m_sText = pTextNd->GetExpandText(pLayout, nStart, nEnd - 
nStart, false, false, false, ExpandMode(0));
-
-                if (m_nSubType == REF_OUTLINE
-                    || (m_nSubType == REF_SEQUENCEFLD && REF_CONTENT == 
GetFormat()))
+                if (pLayout->IsHideRedlines())
                 {
-                    m_sTextRLHidden = sw::GetExpandTextMerged(
-                        pLayoutRLHidden, *pTextNd, false, false, 
ExpandMode(0));
+                    if (m_nSubType == REF_OUTLINE
+                        || (m_nSubType == REF_SEQUENCEFLD && REF_CONTENT == 
GetFormat()))
+                    {
+                        rText = sw::GetExpandTextMerged(pLayout, *pTextNd, 
false, false,
+                                                        ExpandMode(0));
+                    }
+                    else
+                    {
+                        rText = pTextNd->GetExpandText(pLayout, nStart, nEnd - 
nStart, false, false,
+                                                       false, 
ExpandMode::HideDeletions);
+                    }
                 }
                 else
                 {
-                    m_sTextRLHidden = pTextNd->GetExpandText(pLayoutRLHidden,
-                        nStart, nEnd - nStart, false, false, false, 
ExpandMode::HideDeletions);
+                    rText = pTextNd->GetExpandText(pLayout, nStart, nEnd - 
nStart, false, false,
+                                                   false, 
ExpandMode::HideDeletions);
+                    // show the referenced text without the deletions, but if 
the whole text was
+                    // deleted, show the original text for the sake of the 
comfortable reviewing
+                    // (with strikethrough in tooltip, see 
GetExpandedTextOfReferencedTextNode())
+                    if (rText.isEmpty())
+                        rText = pTextNd->GetExpandText(pLayout, nStart, nEnd - 
nStart, false, false,
+                                                       false, ExpandMode(0));
                 }
                 FilterText(m_sText, GetLanguage(), m_sSetReferenceLanguage);
-                FilterText(m_sTextRLHidden, GetLanguage(), 
m_sSetReferenceLanguage);
             }
         }
         break;
@@ -657,10 +686,7 @@ void SwGetRefField::UpdateField( const SwTextField* 
pFieldTextAttr )
     case REF_PAGE:
     case REF_PAGE_PGDESC:
         {
-          auto const func =
-          [this, pTextNd, nNumStart](OUString & rText, SwRootFrame const*const 
pLay)
-          {
-            SwTextFrame const* pFrame = 
static_cast<SwTextFrame*>(pTextNd->getLayoutFrame(pLay, nullptr, nullptr));
+            SwTextFrame const* pFrame = 
static_cast<SwTextFrame*>(pTextNd->getLayoutFrame(pLayout, nullptr, nullptr));
             SwTextFrame const*const pSave = pFrame;
             if (pFrame)
             {
@@ -687,35 +713,25 @@ void SwGetRefField::UpdateField( const SwTextField* 
pFieldTextAttr )
                 if (!m_sSetReferenceLanguage.isEmpty())
                     lcl_formatReferenceLanguage(rText, false, GetLanguage(), 
m_sSetReferenceLanguage);
             }
-          };
-          // sw_redlinehide: currently only one of these layouts will exist,
-          // so the getLayoutFrame will use the same frame in both cases
-          func(m_sText, pLayout);
-          func(m_sTextRLHidden, pLayoutRLHidden);
         }
         break;
 
     case REF_CHAPTER:
+    {
+        // a bit tricky: search any frame
+        SwFrame const* const pFrame = pTextNd->getLayoutFrame(pLayout);
+        if (pFrame)
         {
-          auto const func =
-          [this, pTextNd](OUString & rText, SwRootFrame const*const pLay)
-          {
-            // a bit tricky: search any frame
-            SwFrame const*const pFrame = pTextNd->getLayoutFrame(pLay);
-            if( pFrame )
-            {
-                SwChapterFieldType aFieldTyp;
-                SwChapterField aField( &aFieldTyp, 0 );
-                aField.SetLevel( MAXLEVEL - 1 );
-                aField.ChangeExpansion( *pFrame, pTextNd, true );
-                rText = aField.GetNumber(pLay);
+            SwChapterFieldType aFieldTyp;
+            SwChapterField aField(&aFieldTyp, 0);
+            aField.SetLevel(MAXLEVEL - 1);
+            aField.ChangeExpansion(*pFrame, pTextNd, true);
 
-                if (!m_sSetReferenceLanguage.isEmpty())
-                    lcl_formatReferenceLanguage(rText, false, GetLanguage(), 
m_sSetReferenceLanguage);
-            }
-          };
-          func(m_sText, pLayout);
-          func(m_sTextRLHidden, pLayoutRLHidden);
+            rText = aField.GetNumber(pLayout);
+
+            if (!m_sSetReferenceLanguage.isEmpty())
+                lcl_formatReferenceLanguage(rText, false, GetLanguage(), 
m_sSetReferenceLanguage);
+        }
         }
         break;
 
@@ -731,22 +747,19 @@ void SwGetRefField::UpdateField( const SwTextField* 
pFieldTextAttr )
             // first a "short" test - in case both are in the same node
             if( pFieldTextAttr->GetpTextNode() == pTextNd )
             {
-                m_sText = nNumStart < pFieldTextAttr->GetStart()
+                rText = nNumStart < pFieldTextAttr->GetStart()
                             ? aLocaleData.getAboveWord()
                             : aLocaleData.getBelowWord();
-                m_sTextRLHidden = m_sText;
                 break;
             }
 
-            m_sText = ::IsFrameBehind( *pFieldTextAttr->GetpTextNode(), 
pFieldTextAttr->GetStart(),
+            rText = ::IsFrameBehind( *pFieldTextAttr->GetpTextNode(), 
pFieldTextAttr->GetStart(),
                                     *pTextNd, nNumStart )
                         ? aLocaleData.getAboveWord()
                         : aLocaleData.getBelowWord();
 
             if (!m_sSetReferenceLanguage.isEmpty())
-                    lcl_formatReferenceLanguage(m_sText, false, GetLanguage(), 
m_sSetReferenceLanguage);
-
-            m_sTextRLHidden = m_sText;
+                    lcl_formatReferenceLanguage(rText, false, GetLanguage(), 
m_sSetReferenceLanguage);
         }
         break;
     // #i81002#
@@ -758,20 +771,12 @@ void SwGetRefField::UpdateField( const SwTextField* 
pFieldTextAttr )
             {
                 auto result =
                     MakeRefNumStr(pLayout, pFieldTextAttr->GetTextNode(), 
*pTextNd, GetFormat());
-                m_sText = result.first;
+                rText = result.first;
                 // for differentiation of Roman numbers and letters in 
Hungarian article handling
                 bool bClosingParenthesis = result.second;
                 if (!m_sSetReferenceLanguage.isEmpty())
                 {
-                    lcl_formatReferenceLanguage(m_sText, bClosingParenthesis, 
GetLanguage(), m_sSetReferenceLanguage);
-                }
-                result =
-                    MakeRefNumStr(pLayoutRLHidden, 
pFieldTextAttr->GetTextNode(), *pTextNd, GetFormat());
-                m_sTextRLHidden = result.first;
-                bClosingParenthesis = result.second;
-                if (!m_sSetReferenceLanguage.isEmpty())
-                {
-                    lcl_formatReferenceLanguage(m_sTextRLHidden, 
bClosingParenthesis, GetLanguage(), m_sSetReferenceLanguage);
+                    lcl_formatReferenceLanguage(rText, bClosingParenthesis, 
GetLanguage(), m_sSetReferenceLanguage);
                 }
             }
         }
@@ -934,6 +939,7 @@ bool SwGetRefField::QueryValue( uno::Any& rAny, sal_uInt16 
nWhichId ) const
             case  REF_OUTLINE    : OSL_FAIL("not implemented"); break;
             case  REF_FOOTNOTE   : nSource = ReferenceFieldSource::FOOTNOTE; 
break;
             case  REF_ENDNOTE    : nSource = ReferenceFieldSource::ENDNOTE; 
break;
+            case  REF_STYLE      : nSource = ReferenceFieldSource::STYLE; 
break;
             }
             rAny <<= nSource;
         }
@@ -1018,6 +1024,7 @@ bool SwGetRefField::PutValue( const uno::Any& rAny, 
sal_uInt16 nWhichId )
             case ReferenceFieldSource::BOOKMARK       : m_nSubType = 
REF_BOOKMARK   ; break;
             case ReferenceFieldSource::FOOTNOTE       : m_nSubType = 
REF_FOOTNOTE   ; break;
             case ReferenceFieldSource::ENDNOTE        : m_nSubType = 
REF_ENDNOTE    ; break;
+            case ReferenceFieldSource::STYLE          : m_nSubType = REF_STYLE 
     ; break;
             }
         }
         break;
@@ -1115,7 +1122,7 @@ void SwGetRefFieldType::UpdateGetReferences()
         }
 
         // #i81002#
-        pGRef->UpdateField(pFormatField->GetTextField());
+        pGRef->UpdateField(pFormatField->GetTextField(), nullptr);
     }
     CallSwClientNotify(sw::LegacyModifyHint(nullptr, nullptr));
 }
@@ -1166,10 +1173,53 @@ bool IsMarkHintHidden(SwRootFrame const& rLayout,
 
 } // namespace sw
 
-SwTextNode* SwGetRefFieldType::FindAnchor( SwDoc* pDoc, const OUString& 
rRefMark,
-                                        sal_uInt16 nSubType, sal_uInt16 nSeqNo,
-                                        sal_Int32* pStt, sal_Int32* pEnd,
-                                        SwRootFrame const*const pLayout)
+namespace
+{
+    enum StyleRefElementType
+    {
+        Default,
+        Reference, /* e.g. footnotes, endnotes */
+        Marginal, /* headers, footers */
+    };
+
+    /// Picks the first text node with a matching style from a double ended 
queue, starting at the front
+    /// This allows us to use the deque either as a stack or as a queue 
depending on whether we want to search up or down
+    SwTextNode* SearchForStyleAnchor(SwTextNode* pSelf, const 
std::deque<SwNode*>& pToSearch,
+                                    std::u16string_view rStyleName, bool 
bCaseSensitive = true)
+    {
+        std::deque<SwNode*> pSearching(pToSearch);
+        while (!pSearching.empty())
+        {
+            SwNode* pCurrent = pSearching.front();
+            pSearching.pop_front();
+
+            if (*pCurrent == *pSelf)
+                continue;
+
+            SwTextNode* pTextNode = pCurrent->GetTextNode();
+            if (!pTextNode)
+                continue;
+
+            if (bCaseSensitive)
+            {
+                if (pTextNode->GetFormatColl()->GetName() == rStyleName)
+                    return pTextNode;
+            }
+            else
+            {
+                if 
(pTextNode->GetFormatColl()->GetName().equalsIgnoreAsciiCase(rStyleName))
+                    return pTextNode;
+            }
+        }
+
+        return nullptr;
+    }
+}
+
+SwTextNode* SwGetRefFieldType::FindAnchor(SwDoc* pDoc, const OUString& 
rRefMark,
+                                          sal_uInt16 nSubType, sal_uInt16 
nSeqNo, sal_Int32* pStt,
+                                          sal_Int32* pEnd, SwRootFrame const* 
const pLayout,
+                                          SwTextNode* pSelf, SwFrame* 
pContentFrame)
 {
     OSL_ENSURE( pStt, "Why did no one check the StartPos?" );
 
@@ -1284,6 +1334,250 @@ SwTextNode* SwGetRefFieldType::FindAnchor( SwDoc* pDoc, 
const OUString& rRefMark
                 }
         }
         break;
+        case REF_STYLE:
+            if (!pSelf) break;
+
+            const SwNodes& nodes = pDoc->GetNodes();
+
+            StyleRefElementType elementType = StyleRefElementType::Default;
+            const SwTextNode* pReference = nullptr;
+
+            { /* Check if we're a footnote/endnote */
+                for (SwTextFootnote* pFootnoteIdx : pDoc->GetFootnoteIdxs())
+                {
+                    if (pLayout && pLayout->IsHideRedlines()
+                        && sw::IsFootnoteDeleted(rIDRA, *pFootnoteIdx))
+                    {
+                        continue;
+                    }
+                    const SwNodeIndex* pIdx = pFootnoteIdx->GetStartNode();
+                    if (pIdx)
+                    {
+                        SwNodeIndex aIdx(*pIdx, 1);
+                        SwTextNode* pFootnoteNode = 
aIdx.GetNode().GetTextNode();
+                        if (nullptr == pFootnoteNode)
+                            pFootnoteNode
+                                = 
static_cast<SwTextNode*>(pDoc->GetNodes().GoNext(&aIdx));
+
+                        if (*pSelf == *pFootnoteNode)
+                        {
+                            elementType = StyleRefElementType::Reference;
+                            pReference = &pFootnoteIdx->GetTextNode();
+                        }
+                    }
+                }
+            }
+
+            if (pDoc->IsInHeaderFooter(*pSelf))
+            {
+                elementType = StyleRefElementType::Marginal;
+            }
+
+            if (pReference == nullptr)
+            {
+                pReference = pSelf;
+            }
+
+            switch (elementType)
+            {
+                case Marginal:
+                {
+                    // For marginals, styleref tries to act on the current 
page first
+                    // 1. Get the page we're on, search it from top to bottom
+
+                    Point aPt;
+                    std::pair<Point, bool> const tmp(aPt, false);
+
+                    if (!pContentFrame) SAL_WARN("xmloff.text", 
"<SwGetRefFieldType::FindAnchor(..)>: Missing content frame for marginal 
styleref");
+                    const SwPageFrame* pPageFrame = nullptr;
+
+                    if (pContentFrame)
+                        pPageFrame = pContentFrame->FindPageFrame();
+
+                    const SwNode* pPageStart(nullptr);
+                    const SwNode* pPageEnd(nullptr);
+
+                    if (pPageFrame)
+                    {
+                        const SwContentFrame* pPageStartFrame = 
pPageFrame->FindFirstBodyContent();
+                        const SwContentFrame* pPageEndFrame = 
pPageFrame->FindLastBodyContent();
+
+                        if (pPageStartFrame) {
+                            if (pPageStartFrame->IsTextFrame())
+                            {
+                                pPageStart = static_cast<const 
SwTextFrame*>(pPageStartFrame)
+                                                ->GetTextNodeFirst();
+                            }
+                            else
+                            {
+                                pPageStart
+                                    = static_cast<const 
SwNoTextFrame*>(pPageStartFrame)->GetNode();
+                            }
+                        }
+
+                        if (pPageEndFrame) {
+                            if (pPageEndFrame->IsTextFrame())
+                            {
+                                pPageEnd = static_cast<const 
SwTextFrame*>(pPageEndFrame)
+                                            ->GetTextNodeFirst();
+                            }
+                            else
+                            {
+                                pPageEnd = static_cast<const 
SwNoTextFrame*>(pPageEndFrame)->GetNode();
+                            }
+                        }
+                    }
+
+                    if (!pPageStart || !pPageEnd)
+                    {
+                        pPageStart = pReference;
+                        pPageEnd = pReference;
+                    }
+
+                    std::deque<SwNode*> pAbovePage;
+                    std::deque<SwNode*> pInPage;
+                    std::deque<SwNode*> pBelowPage;
+
+                    bool beforeStart = true;
+                    bool beforeEnd = true;
+
+                    for (SwNodeOffset n(0); n < nodes.Count(); n++)
+                    {
+                        if (beforeStart && *pPageStart == *nodes[n])
+                        {
+                            beforeStart = false;
+                        }
+
+                        if (beforeStart)
+                        {
+                            pAbovePage.push_front(nodes[n]);
+                        }
+                        else if (beforeEnd)
+                        {
+                            pInPage.push_back(nodes[n]);
+
+                            if (*pPageEnd == *nodes[n])
+                            {
+                                beforeEnd = false;
+                            }
+                        }
+                        else
+                        {
+                            pBelowPage.push_back(nodes[n]);
+                        }
+                    }
+
+                    pTextNd = SearchForStyleAnchor(pSelf, pInPage, rRefMark);
+                    if (pTextNd)
+                    {
+                        break;
+                    }
+
+                    // 2. Search up from the top of the page
+                    pTextNd = SearchForStyleAnchor(pSelf, pAbovePage, 
rRefMark);
+                    if (pTextNd)
+                    {
+                        break;
+                    }
+
+                    // 3. Search down from the bottom of the page
+                    pTextNd = SearchForStyleAnchor(pSelf, pBelowPage, 
rRefMark);
+                    if (pTextNd)
+                    {
+                        break;
+                    }
+
+                    // Word has case insensitive styles. LO has case sensitive 
styles. If we didn't find
+                    // it yet, maybe we could with a case insensitive search. 
Let's do that
+
+                    pTextNd = SearchForStyleAnchor(pSelf, pInPage, rRefMark,
+                                                   false /* bCaseSensitive */);
+                    if (pTextNd)
+                    {
+                        break;
+                    }
+
+                    pTextNd = SearchForStyleAnchor(pSelf, pAbovePage, rRefMark,
+                                                   false /* bCaseSensitive */);
+                    if (pTextNd)
+                    {
+                        break;
+                    }
+
+                    pTextNd = SearchForStyleAnchor(pSelf, pBelowPage, rRefMark,
+                                                   false /* bCaseSensitive */);
+                    break;
+                }
+                case Reference:
+                case Default:
+                {
+                    // Normally, styleref does searches around the field 
position
+                    // For references, styleref acts from the position of the 
reference not the field
+                    // Happily, the previous code saves either one into 
pReference, so the following is generic for both
+
+                    std::deque<SwNode*> pNotBelowElement;
+                    std::deque<SwNode*> pBelowElement;
+
+                    bool beforeElement = true;
+
+                    for (SwNodeOffset n(0); n < nodes.Count(); n++)
+                    {
+                        if (beforeElement)
+                        {
+                            pNotBelowElement.push_front(nodes[n]);
+
+                            if (*pReference == *nodes[n])
+                            {
+                                beforeElement = false;
+                            }
+                        }
+                        else
+                        {
+                            pBelowElement.push_back(nodes[n]);
+                        }
+                    }
+
+                    // 1. Search up until we hit the top of the document
+
+                    pTextNd = SearchForStyleAnchor(pSelf, pNotBelowElement, 
rRefMark);
+                    if (pTextNd)
+                    {
+                        break;
+                    }
+
+                    // 2. Search down until we hit the bottom of the document
+
+                    pTextNd = SearchForStyleAnchor(pSelf, pBelowElement, 
rRefMark);
+                    if (pTextNd)
+                    {
+                        break;
+                    }
+
+                    // Again, we need to remember that Word styles are not 
case sensitive
+
+                    pTextNd = SearchForStyleAnchor(pSelf, pNotBelowElement, 
rRefMark,
+                                                   false /* bCaseSensitive */);
+                    if (pTextNd)
+                    {
+                        break;
+                    }
+
+                    pTextNd = SearchForStyleAnchor(pSelf, pBelowElement, 
rRefMark,
+                                                   false /* bCaseSensitive */);
+                    break;
+                }
+                default:
+                    OSL_FAIL("<SwGetRefFieldType::FindAnchor(..)> - unknown 
getref element type");
+            }
+
+            if (pTextNd)
+            {
+                *pStt = 0;
+                if (pEnd)
+                    *pEnd = pTextNd->GetText().getLength();
+            }
+
+            break;
     }
 
     return pTextNd;
diff --git a/sw/source/core/text/txtfld.cxx b/sw/source/core/text/txtfld.cxx
index 464781428010..a912e169995b 100644
--- a/sw/source/core/text/txtfld.cxx
+++ b/sw/source/core/text/txtfld.cxx
@@ -240,7 +240,14 @@ SwExpandPortion *SwTextFormatter::NewFieldPortion( 
SwTextFormatInfo &rInf,
             bPlaceHolder = true;
             break;
         case SwFieldIds::GetRef:
+        {
             subType = static_cast<SwGetRefField*>(pField)->GetSubType();
+            if (!bName && subType == REF_STYLE)
+            {
+                static_cast<SwGetRefField*>(pField)->UpdateField(
+                    static_txtattr_cast<SwTextField const*>(pHint), pFrame);
+            }
+
             {
                 OUString const str( bName
                     ? pField->GetFieldName()
@@ -251,7 +258,8 @@ SwExpandPortion *SwTextFormatter::NewFieldPortion( 
SwTextFormatInfo &rInf,
                 static_cast<SwFieldPortion*>(pRet)->m_nAttrFieldType = 
ATTR_BOOKMARKFLD;
             else if( subType == REF_SETREFATTR )
                 static_cast<SwFieldPortion*>(pRet)->m_nAttrFieldType = 
ATTR_SETREFATTRFLD;
-            break;
+        }
+        break;
         case SwFieldIds::DateTime:
             subType = static_cast<SwDateTimeField*>(pField)->GetSubType();
             {
diff --git a/sw/source/filter/ww8/wrtww8.hxx b/sw/source/filter/ww8/wrtww8.hxx
index 50d772d6b71c..04737fb21410 100644
--- a/sw/source/filter/ww8/wrtww8.hxx
+++ b/sw/source/filter/ww8/wrtww8.hxx
@@ -642,6 +642,9 @@ public:
     /// Find the bookmark name.
     OUString GetBookmarkName( sal_uInt16 nTyp, const OUString* pName, 
sal_uInt16 nSeqNo );
 
+    /// Find out which style we should use in OOXML
+    OUString GetStyleRefName(const OUString& rName);
+
     /// Use OutputItem() on an item set according to the parameters.
     void OutputItemSet( const SfxItemSet& rSet, bool bPapFormat, bool 
bChpFormat, sal_uInt16 nScript, bool bExportParentItemSet );
 
diff --git a/sw/source/filter/ww8/ww8atr.cxx b/sw/source/filter/ww8/ww8atr.cxx
index 4751047e0f74..eda8e17caa53 100644
--- a/sw/source/filter/ww8/ww8atr.cxx
+++ b/sw/source/filter/ww8/ww8atr.cxx
@@ -128,6 +128,7 @@
 #include <fmthdft.hxx>
 #include <authfld.hxx>
 #include <dbfld.hxx>
+#include <docsh.hxx>
 
 #include "sprmids.hxx"
 
@@ -1071,6 +1072,18 @@ OUString MSWordExportBase::GetBookmarkName( sal_uInt16 
nTyp, const OUString* pNa
     return BookmarkToWord( sRet ); // #i43956# - encode bookmark accordingly
 }
 
+OUString MSWordExportBase::GetStyleRefName(const OUString& rName)
+{
+    SwTextFormatColls* pTextFormatColls = m_rDoc.GetTextFormatColls();
+    SwTextFormatColl* pTextFormat = pTextFormatColls->FindFormatByName(rName);
+
+    if (pTextFormat == nullptr)
+        return "\"" + rName + "\"";
+    // Didn't find the style, just keep the original name
+
+    return "\"" + m_pStyles->GetStyleWWName(pTextFormat) + "\"";
+}
+
 /* File CHRATR.HXX: */
 void WW8AttributeOutput::RTLAndCJKState( bool bIsRTL, sal_uInt16 nScript )
 {
@@ -3319,26 +3332,45 @@ void AttributeOutputBase::TextField( const 
SwFormatField& rField )
                     sStr = FieldString(eField)
                            + GetExport().GetBookmarkName(nSubType, nullptr, 
rRField.GetSeqNo());
                     break;
+                case REF_STYLE:
+                    sStr = FieldString(ww::eSTYLEREF)
+                           + GetExport().GetStyleRefName(pField->GetPar1());
+                    eField = ww::eSTYLEREF;
+                    break;
             }
 
-            if (eField != ww::eNONE)
+            OUString sExtraFlags = "\\h "; // by default, include a hyperlink
+
+            switch (eField)
             {
-                switch (pField->GetFormat())
-                {
-                    case REF_UPDOWN:
-                        sStr += " \\p \\h ";   // with hyperlink
-                        break;
-                    case REF_CHAPTER:
-                        sStr += " \\n \\h ";   // with hyperlink
-                        break;
-                    default:
-                        sStr += " \\h ";       // insert hyperlink
-                        break;
-                }
-                GetExport().OutputField(pField, eField, sStr);
+                case ww::eNONE:
+                    bWriteExpand = true;
+                    break;
+                case ww::eSTYLEREF:
+                    sExtraFlags = ""; // styleref fields do not work if they 
have a hyperlink
+                    [[fallthrough]];
+                default:
+                    switch (pField->GetFormat())
+                    {
+                        case REF_NUMBER:
+                            sStr += " \\r " + sExtraFlags;
+                            break;
+                        case REF_NUMBER_FULL_CONTEXT:
+                            sStr += " \\w " + sExtraFlags;
+                            break;
+                        case REF_UPDOWN:
+                            sStr += " \\p " + sExtraFlags;
+                            break;
+                        case REF_NUMBER_NO_CONTEXT:
+                        case REF_CHAPTER:
+                            sStr += " \\n " + sExtraFlags;
+                            break;
+                        default:
+                            sStr += " " + sExtraFlags;
+                            break;
+                    }
+                    GetExport().OutputField(pField, eField, sStr);
             }
-            else
-                bWriteExpand = true;
         }
         break;
     case SwFieldIds::CombinedChars:
@@ -3388,7 +3420,8 @@ void AttributeOutputBase::TextField( const SwFormatField& 
rField )
         break;
     case SwFieldIds::Chapter:
         bWriteExpand = true;
-        if (GetExport().m_bOutKF && rField.GetTextField())
+
+        if (rField.GetTextField())
         {
             const SwTextNode *pTextNd = GetExport().GetHdFtPageRoot();
             if (!pTextNd)
@@ -3400,10 +3433,22 @@ void AttributeOutputBase::TextField( const 
SwFormatField& rField )
             {
                 SwChapterField aCopy(*static_cast<const 
SwChapterField*>(pField));
                 aCopy.ChangeExpansion(*pTextNd, false);
-                const OUString sStr = FieldString(ww::eSTYLEREF)
-                    + " "
-                    + OUString::number(aCopy.GetLevel() + 1)
-                    + " \\* MERGEFORMAT ";
+
+                OUString sStr;
+                if (GetExport().m_bOutKF) {
+                    // In headers and footers, use the chapter number as the 
style name
+                    sStr = FieldString(ww::eSTYLEREF)
+                        + " "
+                        + OUString::number(aCopy.GetLevel() + 1)
+                        + " \\* MERGEFORMAT ";
+                } else {
+                    // Otherwise, get the style of the text and use it as the 
style name
+                    const SwTextNode* pOutlineNd = 
pTextNd->FindOutlineNodeOfLevel(aCopy.GetLevel());
+
+                    sStr = FieldString(ww::eSTYLEREF)
+                         + 
GetExport().GetStyleRefName(pOutlineNd->GetFormatColl()->GetName());
+                }
+
                 GetExport().OutputField(pField, ww::eSTYLEREF, sStr);
                 bWriteExpand = false;
             }
diff --git a/sw/source/filter/ww8/ww8par5.cxx b/sw/source/filter/ww8/ww8par5.cxx
index 894b76f94891..400b357009df 100644
--- a/sw/source/filter/ww8/ww8par5.cxx
+++ b/sw/source/filter/ww8/ww8par5.cxx
@@ -969,8 +969,7 @@ tools::Long SwWW8ImplReader::Read_Field(WW8PLCFManResult* 
pRes)
     bool bHasHandler = aWW8FieldTab[aF.nId] != nullptr;
     if (aF.nId == 10) // STYLEREF
     {
-        // STYLEREF, by default these are not handled.
-        bHasHandler = false;
+        bool bHandledByChapter = false;
         sal_uInt64 nOldPos = m_pStrm->Tell();
         OUString aStr;
         aF.nLCode = m_xSBase->WW8ReadString(*m_pStrm, aStr, 
m_xPlcxMan->GetCpOfs() + aF.nSCode, aF.nLCode, m_eTextCharSet);
@@ -980,9 +979,9 @@ tools::Long SwWW8ImplReader::Read_Field(WW8PLCFManResult* 
pRes)
         sal_Int32 nRet = aReadParam.SkipToNextToken();
         if (nRet == -2 && !aReadParam.GetResult().isEmpty())
             // Single numeric argument: this can be handled by SwChapterField.
-            bHasHandler = rtl::isAsciiDigit(aReadParam.GetResult()[0]);
+            bHandledByChapter = rtl::isAsciiDigit(aReadParam.GetResult()[0]);
 
-        if (bHasHandler)
+        if (bHandledByChapter)
         {
             nRet = aReadParam.SkipToNextToken();
             // Handle using SwChapterField only in case there is no \[a-z]
diff --git a/sw/source/ui/fldui/fldref.cxx b/sw/source/ui/fldui/fldref.cxx
index 54f9c9fc98dc..61083223eb3f 100644
--- a/sw/source/ui/fldui/fldref.cxx
+++ b/sw/source/ui/fldui/fldref.cxx
@@ -47,6 +47,9 @@
 // #i83479#
 #define REFFLDFLAG_HEADING  0x7100
 #define REFFLDFLAG_NUMITEM  0x7200
+#define REFFLDFLAG_STYLE    0xc000
+/* we skip past 0x8000, 0x9000, 0xa000 and 0xb000 as when we bitwise 'and'
+       with REFFLDFLAG they are false */
 
 static sal_uInt16 nFieldDlgFormatSel = 0;
 
@@ -82,6 +85,7 @@ SwFieldRefPage::SwFieldRefPage(weld::Container* pPage, 
weld::DialogController* p
     // #i83479#
     m_sHeadingText = m_xTypeLB->get_text(3);
     m_sNumItemText = m_xTypeLB->get_text(4);
+    m_sStyleText = m_xTypeLB->get_text(5);
 
     auto nHeight = m_xTypeLB->get_height_rows(8);
     auto nWidth = m_xTypeLB->get_approximate_digit_width() * 
FIELD_COLUMN_WIDTH;
@@ -239,6 +243,9 @@ void SwFieldRefPage::Reset(const SfxItemSet* )
         m_xTypeLB->append(OUString::number(REFFLDFLAG_ENDNOTE), 
m_sEndnoteText);
     }
 
+    // stylerefs
+    m_xTypeLB->append(OUString::number(REFFLDFLAG_STYLE), m_sStyleText);
+
     m_xTypeLB->thaw();
 
     // select old Pos
@@ -274,7 +281,7 @@ void SwFieldRefPage::Reset(const SfxItemSet* )
         }
     }
     TypeHdl(*m_xTypeLB);
-    if (nFormatBoxPosition < m_xFormatLB->n_children())
+    if (!IsFieldEdit() && nFormatBoxPosition < m_xFormatLB->n_children())
     {
         m_xFormatLB->select(nFormatBoxPosition);
     }
@@ -356,6 +363,17 @@ IMPL_LINK_NOARG(SwFieldRefPage, TypeHdl, weld::TreeView&, 
void)
                     nFlag = REFFLDFLAG;
                     break;
                 }
+
+                case REF_STYLE:
+                {
+                    SwGetRefField const*const 
pRefField(dynamic_cast<SwGetRefField*>(GetCurField()));
+                    if (pRefField)
+                    {
+                        sName = pRefField->GetPar1();
+                    }
+                    nFlag = REFFLDFLAG_STYLE;
+                    break;
+                }
             }
 
             if (m_xTypeLB->find_text(sName) == -1)   // reference to deleted 
mark
@@ -610,7 +628,7 @@ void SwFieldRefPage::UpdateSubType(const OUString& 
filterString)
                     m_xSelectionToolTipLB->append(sId,
                         pIDoc->getOutlineText(nOutlIdx, pSh->GetLayout(), 
true, true, false));
                     if ((IsFieldEdit() && pRefField
-                            && pRefField->GetReferencedTextNode() == 
maOutlineNodes[nOutlIdx])
+                            && pRefField->GetReferencedTextNode(nullptr, 
nullptr) == maOutlineNodes[nOutlIdx])
                         || mpSavedSelectedTextNode == maOutlineNodes[nOutlIdx])
                     {
                         m_sSelectionToolTipLBId = sId;
@@ -645,7 +663,7 @@ void SwFieldRefPage::UpdateSubType(const OUString& 
filterString)
                     m_xSelectionToolTipLB->append(sId,
                         pIDoc->getListItemText(*maNumItems[nNumItemIdx], 
*pSh->GetLayout()));
                     if ((IsFieldEdit() && pRefField
-                            && pRefField->GetReferencedTextNode() == 
maNumItems[nNumItemIdx]->GetTextNode())
+                            && pRefField->GetReferencedTextNode(nullptr, 
nullptr) == maNumItems[nNumItemIdx]->GetTextNode())
                         || mpSavedSelectedTextNode == 
maNumItems[nNumItemIdx]->GetTextNode())
                     {
                         m_sSelectionToolTipLBId = sId;
@@ -660,6 +678,32 @@ void SwFieldRefPage::UpdateSubType(const OUString& 
filterString)
                 }
             }
         }
+        else if (nTypeId == REFFLDFLAG_STYLE)
+        {
+            const IDocumentOutlineNodes* 
pIDoc(pSh->getIDocumentOutlineNodesAccess());
+            pIDoc->getOutlineNodes(maOutlineNodes);
+
+            SfxStyleSheetBasePool* pStyleSheetPool
+                = pSh->GetDoc()->GetDocShell()->GetStyleSheetPool();
+            auto stylesheetIterator
+                = pStyleSheetPool->CreateIterator(SfxStyleFamily::Para, 
SfxStyleSearchBits::Used);
+
+            SfxStyleSheetBase* pStyle = stylesheetIterator->First();
+            while (pStyle != nullptr)
+            {
+                bool isSubstring = MatchSubstring(pStyle->GetName(), 
filterString);
+
+                if (isSubstring)
+                {
+                    m_xSelectionLB->append_text(pStyle->GetName());
+                }
+
+                pStyle = stylesheetIterator->Next();
+            }
+
+            if (IsFieldEdit() && pRefField)
+                sOldSel = pRefField->GetPar1();
+        }
         else
         {
             // get the fields to Seq-FieldType:
@@ -803,6 +847,7 @@ sal_Int32 SwFieldRefPage::FillFormatLB(sal_uInt16 nTypeId)
 
     // reference has less that the annotation
     sal_uInt16 nSize( 0 );
+    sal_uInt16 nOffset( 0 );
     bool bAddCrossRefFormats( false );
     switch (nTypeId)
     {
@@ -818,6 +863,11 @@ sal_Int32 SwFieldRefPage::FillFormatLB(sal_uInt16 nTypeId)
         case REFFLDFLAG_ENDNOTE:
             nSize = FMT_REF_PAGE_PGDSC_IDX + 1;
             break;
+        case REFFLDFLAG_STYLE:
+            nOffset = FMT_REF_TEXT_IDX;
+            nSize = FMT_REF_UPDOWN_IDX + 1 - nOffset;
+            bAddCrossRefFormats = true;
+            break;
 
         default:
             // #i83479#
@@ -837,7 +887,7 @@ sal_Int32 SwFieldRefPage::FillFormatLB(sal_uInt16 nTypeId)
         nTypeId = static_cast<sal_uInt16>(SwFieldTypesEnum::GetRef);
 
     SwFieldTypesEnum nFieldType = static_cast<SwFieldTypesEnum>(nTypeId);
-    for (sal_uInt16 i = 0; i < nSize; i++)
+    for (sal_uInt16 i = nOffset; i < nSize + nOffset; i++)
     {
         OUString sId(OUString::number(GetFieldMgr().GetFormatId( nFieldType, i 
)));
         m_xFormatLB->append(sId, GetFieldMgr().GetFormatStr(nFieldType, i));
@@ -1077,6 +1127,18 @@ bool SwFieldRefPage::FillItemSet(SfxItemSet* )
                 }
             }
         }
+        else if (nTypeId == REFFLDFLAG_STYLE)
+        {
+            int nEntry = m_xSelectionLB->get_selected_index();
+            if (nEntry != -1)
+            {
+                aName = m_xSelectionLB->get_text(nEntry);
+                nTypeId = static_cast<sal_uInt16>(SwFieldTypesEnum::GetRef);
+                nSubType = REF_STYLE;
+            } else {
+                SAL_WARN("sw.ui", "<SwFieldRefPage::FillItemSet(..)> no entry 
selected in selection listbox!");
+            }
+        }
         else                                // SequenceFields
         {
             // get fields for Seq-FieldType:
diff --git a/sw/source/ui/fldui/fldref.hxx b/sw/source/ui/fldui/fldref.hxx
index 68dc6f6480be..872e6f526bb6 100644
--- a/sw/source/ui/fldui/fldref.hxx
+++ b/sw/source/ui/fldui/fldref.hxx
@@ -34,6 +34,7 @@ class SwFieldRefPage : public SwFieldPage
     // #i83479#
     OUString    m_sHeadingText;
     OUString    m_sNumItemText;
+    OUString    m_sStyleText;
 
     IDocumentOutlineNodes::tSortedOutlineNodeList maOutlineNodes;
     IDocumentListItems::tSortedNodeNumList maNumItems;
diff --git a/sw/source/uibase/docvw/edtwin2.cxx 
b/sw/source/uibase/docvw/edtwin2.cxx
index c3bea9094135..0c47b2ec5540 100644
--- a/sw/source/uibase/docvw/edtwin2.cxx
+++ b/sw/source/uibase/docvw/edtwin2.cxx
@@ -567,7 +567,7 @@ void SwEditWin::RequestHelp(const HelpEvent &rEvt)
                                 if ( 
pRefField->IsRefToHeadingCrossRefBookmark() ||
                                      
pRefField->IsRefToNumItemCrossRefBookmark() )
                                 {
-                                    sText = 
pRefField->GetExpandedTextOfReferencedTextNode(*rSh.GetLayout());
+                                    sText = 
pRefField->GetExpandedTextOfReferencedTextNode(*rSh.GetLayout(), nullptr, 
nullptr);
                                     if ( sText.getLength() > 80  )
                                     {
                                         sText = 
OUString::Concat(sText.subView(0, 80)) + "...";
diff --git a/sw/source/uibase/fldui/fldmgr.cxx 
b/sw/source/uibase/fldui/fldmgr.cxx
index bf53ae29b0a4..c61c9c26cba5 100644
--- a/sw/source/uibase/fldui/fldmgr.cxx
+++ b/sw/source/uibase/fldui/fldmgr.cxx
@@ -66,6 +66,8 @@
 #include <authfld.hxx>
 #include <flddat.hxx>
 #include <fldmgr.hxx>
+#include <ndtxt.hxx>
+#include <cntfrm.hxx>
 #include <flddropdown.hxx>
 #include <strings.hrc>
 #include <tox.hxx>
@@ -1132,6 +1134,7 @@ bool SwFieldMgr::InsertField(
                 }
                 nFormatId %= SAL_N_ELEMENTS(FMT_REF_ARY);
             }
+
             pField.reset(new SwGetRefField(pTyp, rData.m_sPar1, 
sReferenceLanguage, nSubType, nSeqNo, nFormatId));
             bExp = true;
             break;
diff --git a/sw/source/uibase/utlui/content.cxx 
b/sw/source/uibase/utlui/content.cxx
index 5d56eada213b..43bb9e78bb5f 100644
--- a/sw/source/uibase/utlui/content.cxx
+++ b/sw/source/uibase/utlui/content.cxx
@@ -707,7 +707,7 @@ void SwContentType::FillMemberList(bool* pbContentChanged)
                     {
                         OUString sExpandedTextOfReferencedTextNode =
                                 pRefField->GetExpandedTextOfReferencedTextNode(
-                                    *m_pWrtShell->GetLayout());
+                                    *m_pWrtShell->GetLayout(), nullptr, 
nullptr);
                         if (sExpandedTextOfReferencedTextNode.getLength() > 80)
                         {
                             sExpandedTextOfReferencedTextNode = 
OUString::Concat(
diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.cxx 
b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
index 67fe56280c18..fd27e92510d5 100644
--- a/writerfilter/source/dmapper/DomainMapper_Impl.cxx
+++ b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
@@ -5829,7 +5829,7 @@ static const FieldConversionMap_t & 
lcl_GetFieldConversion()
         {"SEQ",             {"SetExpression",           FIELD_SEQ           }},
         {"SET",             {"SetExpression",           FIELD_SET           }},
 //      {"SKIPIF",          {"",                        FIELD_SKIPIF        }},
-//      {"STYLEREF",        {"",                        FIELD_STYLEREF      }},
+        {"STYLEREF",        {"GetReference",            FIELD_STYLEREF      }},
         {"SUBJECT",         {"DocInfo.Subject",         FIELD_SUBJECT       }},
         {"SYMBOL",          {"",                        FIELD_SYMBOL        }},
         {"TEMPLATE",        {"TemplateName",            FIELD_TEMPLATE      }},
@@ -7519,9 +7519,11 @@ void DomainMapper_Impl::CloseFieldCommand()
                 break;
                 case FIELD_PAGEREF:
                 case FIELD_REF:
+                case FIELD_STYLEREF:
                 if (xFieldProperties.is() && !IsInTOC())
                 {
                     bool bPageRef = aIt->second.eFieldId == FIELD_PAGEREF;
+                    bool bStyleRef = aIt->second.eFieldId == FIELD_STYLEREF;
 
                     // Do we need a GetReference (default) or a GetExpression 
field?
                     uno::Reference< text::XTextFieldsSupplier > 
xFieldsSupplier( GetTextDocument(), uno::UNO_QUERY );
@@ -7531,12 +7533,50 @@ void DomainMapper_Impl::CloseFieldCommand()
                             "com.sun.star.text.FieldMaster.SetExpression."
                             + sFirstParam))
                     {
-                        xFieldProperties->setPropertyValue(
-                            getPropertyName(PROP_REFERENCE_FIELD_SOURCE),
-                            uno::Any( 
sal_Int16(text::ReferenceFieldSource::BOOKMARK)) );
-                        xFieldProperties->setPropertyValue(
-                            getPropertyName(PROP_SOURCE_NAME),
-                            uno::Any(sFirstParam) );
+                        if (bStyleRef)
+                        {
+                            xFieldProperties->setPropertyValue(
+                                getPropertyName(PROP_REFERENCE_FIELD_SOURCE),
+                                
uno::Any(sal_Int16(text::ReferenceFieldSource::STYLE)));
+
+                            OUString sStyleSheetName
+                                = 
GetStyleSheetTable()->ConvertStyleName(sFirstParam, true);
+
+                            uno::Any aStyleDisplayName;
+
+                            uno::Reference<style::XStyleFamiliesSupplier> 
xStylesSupplier(
+                                GetTextDocument(), uno::UNO_QUERY_THROW);
+                            uno::Reference<container::XNameAccess> 
xStyleFamilies
+                                = xStylesSupplier->getStyleFamilies();
+                            uno::Reference<container::XNameAccess> xStyles;
+                            
xStyleFamilies->getByName(getPropertyName(PROP_PARAGRAPH_STYLES))
+                                >>= xStyles;
+                            uno::Reference<css::beans::XPropertySet> xStyle;
+
+                            try
+                            {
+                                xStyles->getByName(sStyleSheetName) >>= xStyle;
+                                aStyleDisplayName = 
xStyle->getPropertyValue("DisplayName");
+                            }
+                            catch (css::container::NoSuchElementException)
+                            {
+                                aStyleDisplayName <<= sStyleSheetName;
+                            }
+
+                            xFieldProperties->setPropertyValue(
+                                getPropertyName(PROP_SOURCE_NAME), 
aStyleDisplayName);
+                        }
+                        else
+                        {
+                            xFieldProperties->setPropertyValue(
+                                getPropertyName(PROP_REFERENCE_FIELD_SOURCE),
+                                uno::Any( 
sal_Int16(text::ReferenceFieldSource::BOOKMARK)) );
+
+                            xFieldProperties->setPropertyValue(
+                                getPropertyName(PROP_SOURCE_NAME),
+                                uno::Any(sFirstParam));
+                        }
+
                         sal_Int16 nFieldPart = (bPageRef ? 
text::ReferenceFieldPart::PAGE : text::ReferenceFieldPart::TEXT);
                         OUString sValue;
                         if( lcl_FindInCommand( pContext->GetCommand(), 'p', 
sValue ))
@@ -7631,7 +7671,6 @@ void DomainMapper_Impl::CloseFieldCommand()
                     handleFieldSet(pContext, xFieldInterface, 
xFieldProperties);
                 break;
                 case FIELD_SKIPIF       : break;
-                case FIELD_STYLEREF     : break;
                 case FIELD_SUBJECT      :
                 {
                     if (!sFirstParam.isEmpty())
diff --git a/writerfilter/source/dmapper/FieldTypes.hxx 
b/writerfilter/source/dmapper/FieldTypes.hxx
index a907a7af6c22..144d1efe1370 100644
--- a/writerfilter/source/dmapper/FieldTypes.hxx
+++ b/writerfilter/source/dmapper/FieldTypes.hxx
@@ -209,8 +209,9 @@ enum FieldId
      */
     ,FIELD_SKIPIF
     /* STYLEREF stylename \* MERGEFORMAT ->
-     not imported in old ww8 filter
-     todo: add an equivalent field type
+     implemented using GetReference, but some switches are not implemented yet
+     \l isn't implemented
+     \t isn't implemented
      */
     ,FIELD_STYLEREF
     /* SUBJECT subject \* Defaultswitch \* MERGEFORMAT ->
diff --git a/xmloff/inc/txtflde.hxx b/xmloff/inc/txtflde.hxx
index 8670cac40cf6..459dea29f550 100644
--- a/xmloff/inc/txtflde.hxx
+++ b/xmloff/inc/txtflde.hxx
@@ -119,6 +119,7 @@ enum FieldIdEnum {
     FIELD_ID_REF_BOOKMARK,          // get reference field (bookmark)
     FIELD_ID_REF_FOOTNOTE,          // get reference field (footnote)
     FIELD_ID_REF_ENDNOTE,           // get reference field (endnote)
+    FIELD_ID_REF_STYLE,             // styleref field
     FIELD_ID_DDE,                   // DDE field
 
     FIELD_ID_BIBLIOGRAPHY,          // bibliography index entry
diff --git a/xmloff/source/core/xmltoken.cxx b/xmloff/source/core/xmltoken.cxx
index 38ee9bb853c3..6519570d6a03 100644
--- a/xmloff/source/core/xmltoken.cxx
+++ b/xmloff/source/core/xmltoken.cxx
@@ -1915,6 +1915,7 @@ namespace xmloff::token {
         TOKEN( "structure-protected",             XML_STRUCTURE_PROTECTED ),
         TOKEN( "style",                           XML_STYLE ),
         TOKEN( "style-name",                      XML_STYLE_NAME ),
+        TOKEN( "style-ref",                       XML_STYLE_REF ),
         TOKEN( "styles",                          XML_STYLES ),
         TOKEN( "stylesheet",                      XML_STYLESHEET ),
         TOKEN( "sub-table",                       XML_SUB_TABLE ),
diff --git a/xmloff/source/text/txtflde.cxx b/xmloff/source/text/txtflde.cxx
index 2299773206db..5a109cef0a43 100644
--- a/xmloff/source/text/txtflde.cxx
+++ b/xmloff/source/text/txtflde.cxx
@@ -563,6 +563,9 @@ enum FieldIdEnum XMLTextFieldExport::MapFieldName(
                 case ReferenceFieldSource::ENDNOTE:
                     nToken = FIELD_ID_REF_ENDNOTE;
                     break;
+                case ReferenceFieldSource::STYLE:
+                    nToken = FIELD_ID_REF_STYLE;
+                    break;
                 default:
                     nToken = FIELD_ID_UNKNOWN;
                     break;
@@ -703,6 +706,7 @@ bool XMLTextFieldExport::IsStringField(
     case FIELD_ID_REF_BOOKMARK:
     case FIELD_ID_REF_FOOTNOTE:
     case FIELD_ID_REF_ENDNOTE:
+    case FIELD_ID_REF_STYLE:
     case FIELD_ID_MACRO:
     case FIELD_ID_TEMPLATE_NAME:
     case FIELD_ID_CHAPTER:
@@ -914,6 +918,7 @@ void XMLTextFieldExport::ExportFieldAutoStyle(
     case FIELD_ID_REF_BOOKMARK:
     case FIELD_ID_REF_FOOTNOTE:
     case FIELD_ID_REF_ENDNOTE:
+    case FIELD_ID_REF_STYLE:
     case FIELD_ID_MACRO:
     case FIELD_ID_REFPAGE_SET:
     case FIELD_ID_REFPAGE_GET:
@@ -1646,6 +1651,30 @@ void XMLTextFieldExport::ExportFieldHelper(
             sPresentation);
         break;
 
+    case FIELD_ID_REF_STYLE:
+    {
+        ProcessString(XML_REFERENCE_FORMAT,
+                      
MapReferenceType(GetInt16Property(gsPropertyReferenceFieldPart, rPropSet)),
+                      XML_TEMPLATE);
+        ProcessString(XML_REF_NAME, GetStringProperty(gsPropertySourceName, 
rPropSet));
+        if (xPropSetInfo->hasPropertyByName(gsPropertyReferenceFieldLanguage)
+            && GetExport().getSaneDefaultVersion() & 
SvtSaveOptions::ODFSVER_EXTENDED)
+        {
+            // export text:reference-language attribute, if not empty
+            ProcessString(XML_REFERENCE_LANGUAGE,
+                          GetStringProperty(gsPropertyReferenceFieldLanguage, 
rPropSet), true,
+                          XML_NAMESPACE_LO_EXT);
+        }
+        SvXMLElementExport aElem(
+            GetExport(),
+            XML_NAMESPACE_LO_EXT,
+            
MapReferenceSource(GetInt16Property(gsPropertyReferenceFieldSource, rPropSet)),
+            false,
+            false);
+        GetExport().Characters(sPresentation);
+        break;
+    }
+
     case FIELD_ID_DDE:
         // name from field master
          ProcessString(XML_CONNECTION_NAME,
@@ -3160,6 +3189,9 @@ enum XMLTokenEnum 
XMLTextFieldExport::MapReferenceSource(sal_Int16 nType)
         case ReferenceFieldSource::ENDNOTE:
             eElement = XML_NOTE_REF;
             break;
+        case ReferenceFieldSource::STYLE:
+            eElement = XML_STYLE_REF;
+            break;
         default:
             OSL_FAIL("unknown reference source");
             break;
diff --git a/xmloff/source/text/txtfldi.cxx b/xmloff/source/text/txtfldi.cxx
index dc6fb6646857..05086325da2b 100644
--- a/xmloff/source/text/txtfldi.cxx
+++ b/xmloff/source/text/txtfldi.cxx
@@ -407,6 +407,7 @@ XMLTextFieldImportContext::CreateTextFieldImportContext(
         case XML_ELEMENT(TEXT, XML_BOOKMARK_REF):
         case XML_ELEMENT(TEXT, XML_NOTE_REF):
         case XML_ELEMENT(TEXT, XML_SEQUENCE_REF):
+        case XML_ELEMENT(LO_EXT, XML_STYLE_REF):
             pContext = new XMLReferenceFieldImportContext( rImport, rHlp, 
nToken );
             break;
 
@@ -2509,6 +2510,9 @@ void XMLReferenceFieldImportContext::startFastElement(
         case XML_ELEMENT(TEXT, XML_SEQUENCE_REF):
             nSource = ReferenceFieldSource::SEQUENCE_FIELD;
             break;
+        case XML_ELEMENT(LO_EXT, XML_STYLE_REF):
+            nSource = ReferenceFieldSource::STYLE;
+            break;
         default:
             XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElementToken);
             bTypeOK = false;
@@ -2577,6 +2581,7 @@ void XMLReferenceFieldImportContext::PrepareField(
     {
         case XML_ELEMENT(TEXT, XML_REFERENCE_REF):
         case XML_ELEMENT(TEXT, XML_BOOKMARK_REF):
+        case XML_ELEMENT(LO_EXT, XML_STYLE_REF):
             xPropertySet->setPropertyValue("SourceName", Any(sName));
             break;
 
diff --git a/xmloff/source/token/tokens.txt b/xmloff/source/token/tokens.txt
index 58f8ff8e8c4e..59ae40480d70 100644
--- a/xmloff/source/token/tokens.txt
+++ b/xmloff/source/token/tokens.txt
@@ -1815,6 +1815,7 @@ stroke-width
 structure-protected
 style
 style-name
+style-ref
 styles
 stylesheet
 sub-table

Reply via email to