include/xmloff/txtimp.hxx                                   |    4 
 include/xmloff/xmltoken.hxx                                 |    1 
 schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng |    6 
 sw/qa/extras/globalfilter/data/fieldmark_QUOTE_nest.fodt    |  133 ++++++++++++
 sw/qa/extras/globalfilter/globalfilter.cxx                  |   13 -
 sw/source/core/inc/unobookmark.hxx                          |    4 
 sw/source/core/unocore/unobkm.cxx                           |   19 +
 xmloff/source/core/xmltoken.cxx                             |    1 
 xmloff/source/text/XMLTextMarkImportContext.cxx             |   46 +++-
 xmloff/source/text/XMLTextMarkImportContext.hxx             |    3 
 xmloff/source/text/txtimp.cxx                               |   36 ++-
 xmloff/source/text/txtparae.cxx                             |   14 +
 xmloff/source/text/txtparai.cxx                             |    1 
 xmloff/source/token/tokens.txt                              |    1 
 14 files changed, 260 insertions(+), 22 deletions(-)

New commits:
commit 62fe215562fd853459e5cf7bfba7f51cb7b3df53
Author:     Michael Stahl <michael.st...@allotropia.de>
AuthorDate: Mon Jun 27 19:45:53 2022 +0200
Commit:     Thorsten Behrens <thorsten.behr...@allotropia.de>
CommitDate: Mon Jul 11 16:34:29 2022 +0200

    xmloff, sw: ODF import/export of fieldmark separator
    
    Previously there were only the fieldmark-start and fieldmark-end
    elements; now add a fieldmark-separator, so that the field command can
    be stored as character data (and elements if there is any formatting)
    instead of attribute value.
    
    The import is a bit more complicated because there are already existing
    documents that are missing the separator; it's not possible to predict
    if there will be a separator at the time when the start element is seen,
    so add some hack to toggle inserting the SwXFieldmark with separator
    at the end (when the document contains a separator, i.e. after the
    command) or separator at the start (when the document is missing a
    separator, i.e.  after the result).
    
    Change-Id: I14d2f50f57d690e75643df5d14fd881ebc759a41
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/136513
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>
    (cherry picked from commit 463178fef5c22f1a04d10e54491852d56e2038b0)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/136915
    Reviewed-by: Thorsten Behrens <thorsten.behr...@allotropia.de>

diff --git a/include/xmloff/txtimp.hxx b/include/xmloff/txtimp.hxx
index 9259747bd94d..0124bc8eb2c2 100644
--- a/include/xmloff/txtimp.hxx
+++ b/include/xmloff/txtimp.hxx
@@ -289,7 +289,9 @@ public:
     css::uno::Reference<css::text::XFormField> popFieldCtx();
     void addFieldParam( const OUString& name, const OUString& value );
     void setCurrentFieldParamsTo(css::uno::Reference< css::text::XFormField> 
const &xFormField);
-    OUString getCurrentFieldType();
+    ::std::pair<OUString, OUString> getCurrentFieldType() const;
+    css::uno::Reference<css::text::XTextRange> getCurrentFieldStart() const;
+    bool hasCurrentFieldSeparator() const;
     bool hasCurrentFieldCtx() const;
 
 
diff --git a/include/xmloff/xmltoken.hxx b/include/xmloff/xmltoken.hxx
index 58b6329ec71a..77f9c605b707 100644
--- a/include/xmloff/xmltoken.hxx
+++ b/include/xmloff/xmltoken.hxx
@@ -3308,6 +3308,7 @@ namespace xmloff::token {
         // enhanced fields
         XML_FIELDMARK,
         XML_FIELDMARK_START,
+        XML_FIELDMARK_SEPARATOR,
         XML_FIELDMARK_END,
 
         XML_IMAGE_SCALE,
diff --git a/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng 
b/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng
index 9d84b4ee2343..b6cf6ac26f92 100644
--- a/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng
+++ b/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng
@@ -2806,6 +2806,12 @@ 
xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.
       </rng:zeroOrMore>
     </rng:element>
   </rng:define>
+  <rng:define name="paragraph-content" combine="choice"
+   
xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0">
+    <rng:element name="field:fieldmark-separator">
+      <rng:empty/>
+    </rng:element>
+  </rng:define>
   <rng:define name="paragraph-content" combine="choice"
    
xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0">
     <rng:element name="field:fieldmark-end">
diff --git a/sw/qa/extras/globalfilter/data/fieldmark_QUOTE_nest.fodt 
b/sw/qa/extras/globalfilter/data/fieldmark_QUOTE_nest.fodt
new file mode 100644
index 000000000000..86b17a15bbce
--- /dev/null
+++ b/sw/qa/extras/globalfilter/data/fieldmark_QUOTE_nest.fodt
@@ -0,0 +1,133 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<office:document xmlns:css3t="http://www.w3.org/TR/css3-text/"; 
xmlns:grddl="http://www.w3.org/2003/g/data-view#"; 
xmlns:xhtml="http://www.w3.org/1999/xhtml"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xmlns:xsd="http://www.w3.org/2001/XMLSchema"; 
xmlns:xforms="http://www.w3.org/2002/xforms"; 
xmlns:dom="http://www.w3.org/2001/xml-events"; 
xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" 
xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" 
xmlns:math="http://www.w3.org/1998/Math/MathML"; 
xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" 
xmlns:ooo="http://openoffice.org/2004/office"; 
xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" 
xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0" 
xmlns:ooow="http://openoffice.org/2004/writer"; 
xmlns:xlink="http://www.w3.org/1999/xlink"; 
xmlns:drawooo="http://openoffice.org/2010/draw"; 
xmlns:oooc="http://openoffice.org/2004/calc"; 
xmlns:dc="http://purl.org/dc/elements/1.1/"; xmlns:c
 alcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0" 
xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" 
xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" 
xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" 
xmlns:tableooo="http://openoffice.org/2009/table"; 
xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" 
xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" 
xmlns:rpt="http://openoffice.org/2005/report"; 
xmlns:formx="urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0"
 xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" 
xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" 
xmlns:officeooo="http://openoffice.org/2009/office"; 
xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" 
xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0" 
xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" 
xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:
 meta:1.0" 
xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0"
 office:version="1.3" office:mimetype="application/vnd.oasis.opendocument.text">
+ <office:meta><meta:initial-creator>Michael 
Stahl</meta:initial-creator><dc:creator>Michael 
Stahl</dc:creator><meta:editing-cycles>2</meta:editing-cycles><meta:creation-date>2019-01-24T14:48:00</meta:creation-date><dc:date>2019-01-24T14:48:00</dc:date><meta:editing-duration>P0D</meta:editing-duration><meta:generator>LibreOfficeDev/7.5.0.0.alpha0$Linux_X86_64
 
LibreOffice_project/be346d6cdc87b18dc861279187915de42722e970</meta:generator><meta:document-statistic
 meta:table-count="0" meta:image-count="0" meta:object-count="0" 
meta:page-count="1" meta:paragraph-count="13" meta:word-count="6" 
meta:character-count="24" 
meta:non-whitespace-character-count="18"/><meta:user-defined 
meta:name="AppVersion">15.0000</meta:user-defined><meta:template 
xlink:type="simple" xlink:actuate="onRequest" xlink:title="Normal.dotm" 
xlink:href=""/></office:meta>
+ <office:font-face-decls>
+  <style:font-face style:name="Calibri" svg:font-family="Calibri" 
style:font-family-generic="roman" style:font-pitch="variable"/>
+  <style:font-face style:name="Calibri1" svg:font-family="Calibri" 
style:font-family-generic="system" style:font-pitch="variable"/>
+  <style:font-face style:name="Times New Roman" svg:font-family="'Times New 
Roman'" style:font-family-generic="system" style:font-pitch="variable"/>
+ </office:font-face-decls>
+ <office:styles>
+  <style:default-style style:family="graphic">
+   <style:graphic-properties svg:stroke-color="#3465a4" 
draw:fill-color="#729fcf" fo:wrap-option="no-wrap" draw:shadow-offset-x="0.3cm" 
draw:shadow-offset-y="0.3cm" draw:start-line-spacing-horizontal="0.283cm" 
draw:start-line-spacing-vertical="0.283cm" 
draw:end-line-spacing-horizontal="0.283cm" 
draw:end-line-spacing-vertical="0.283cm" style:flow-with-text="false"/>
+   <style:paragraph-properties style:text-autospace="ideograph-alpha" 
style:line-break="strict" style:writing-mode="lr-tb" 
style:font-independent-line-spacing="false">
+    <style:tab-stops/>
+   </style:paragraph-properties>
+   <style:text-properties style:use-window-font-color="true" 
loext:opacity="0%" loext:color-lum-mod="100%" loext:color-lum-off="0%" 
style:font-name="Calibri" fo:font-size="10pt" fo:language="de" fo:country="DE" 
style:letter-kerning="false" style:font-name-asian="Calibri1" 
style:font-size-asian="10pt" style:language-asian="de" style:country-asian="DE" 
style:font-name-complex="Times New Roman" style:font-size-complex="10pt" 
style:language-complex="ar" style:country-complex="SA"/>
+  </style:default-style>
+  <style:default-style style:family="paragraph">
+   <style:paragraph-properties fo:hyphenation-ladder-count="no-limit" 
style:text-autospace="ideograph-alpha" style:punctuation-wrap="hanging" 
style:line-break="strict" style:tab-stop-distance="1.249cm" 
style:writing-mode="page"/>
+   <style:text-properties style:use-window-font-color="true" 
loext:opacity="0%" style:font-name="Calibri" fo:font-size="10pt" 
fo:language="de" fo:country="DE" style:letter-kerning="false" 
style:font-name-asian="Calibri1" style:font-size-asian="10pt" 
style:language-asian="de" style:country-asian="DE" 
style:font-name-complex="Times New Roman" style:font-size-complex="10pt" 
style:language-complex="ar" style:country-complex="SA" fo:hyphenate="false" 
fo:hyphenation-remain-char-count="2" fo:hyphenation-push-char-count="2" 
loext:hyphenation-no-caps="false" loext:hyphenation-no-last-word="false" 
loext:hyphenation-word-char-count="5" loext:hyphenation-zone="no-limit"/>
+  </style:default-style>
+  <style:default-style style:family="table">
+   <style:table-properties table:border-model="collapsing"/>
+  </style:default-style>
+  <style:default-style style:family="table-row">
+   <style:table-row-properties fo:keep-together="auto"/>
+  </style:default-style>
+  <style:style style:name="Standard" style:family="paragraph" 
style:class="text">
+   <style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0.282cm" 
style:contextual-spacing="false" fo:line-height="108%" fo:text-align="start" 
style:justify-single-word="false" fo:orphans="2" fo:widows="2" 
style:writing-mode="lr-tb"/>
+   <style:text-properties fo:font-size="11pt" style:font-size-asian="11pt" 
style:language-asian="en" style:country-asian="US" 
style:font-size-complex="11pt"/>
+  </style:style>
+  <text:outline-style style:name="Outline">
+   <text:outline-level-style text:level="1" style:num-format="">
+    <style:list-level-properties 
text:list-level-position-and-space-mode="label-alignment">
+     <style:list-level-label-alignment text:label-followed-by="listtab"/>
+    </style:list-level-properties>
+   </text:outline-level-style>
+   <text:outline-level-style text:level="2" style:num-format="">
+    <style:list-level-properties 
text:list-level-position-and-space-mode="label-alignment">
+     <style:list-level-label-alignment text:label-followed-by="listtab"/>
+    </style:list-level-properties>
+   </text:outline-level-style>
+   <text:outline-level-style text:level="3" style:num-format="">
+    <style:list-level-properties 
text:list-level-position-and-space-mode="label-alignment">
+     <style:list-level-label-alignment text:label-followed-by="listtab"/>
+    </style:list-level-properties>
+   </text:outline-level-style>
+   <text:outline-level-style text:level="4" style:num-format="">
+    <style:list-level-properties 
text:list-level-position-and-space-mode="label-alignment">
+     <style:list-level-label-alignment text:label-followed-by="listtab"/>
+    </style:list-level-properties>
+   </text:outline-level-style>
+   <text:outline-level-style text:level="5" style:num-format="">
+    <style:list-level-properties 
text:list-level-position-and-space-mode="label-alignment">
+     <style:list-level-label-alignment text:label-followed-by="listtab"/>
+    </style:list-level-properties>
+   </text:outline-level-style>
+   <text:outline-level-style text:level="6" style:num-format="">
+    <style:list-level-properties 
text:list-level-position-and-space-mode="label-alignment">
+     <style:list-level-label-alignment text:label-followed-by="listtab"/>
+    </style:list-level-properties>
+   </text:outline-level-style>
+   <text:outline-level-style text:level="7" style:num-format="">
+    <style:list-level-properties 
text:list-level-position-and-space-mode="label-alignment">
+     <style:list-level-label-alignment text:label-followed-by="listtab"/>
+    </style:list-level-properties>
+   </text:outline-level-style>
+   <text:outline-level-style text:level="8" style:num-format="">
+    <style:list-level-properties 
text:list-level-position-and-space-mode="label-alignment">
+     <style:list-level-label-alignment text:label-followed-by="listtab"/>
+    </style:list-level-properties>
+   </text:outline-level-style>
+   <text:outline-level-style text:level="9" style:num-format="">
+    <style:list-level-properties 
text:list-level-position-and-space-mode="label-alignment">
+     <style:list-level-label-alignment text:label-followed-by="listtab"/>
+    </style:list-level-properties>
+   </text:outline-level-style>
+   <text:outline-level-style text:level="10" style:num-format="">
+    <style:list-level-properties 
text:list-level-position-and-space-mode="label-alignment">
+     <style:list-level-label-alignment text:label-followed-by="listtab"/>
+    </style:list-level-properties>
+   </text:outline-level-style>
+  </text:outline-style>
+  <text:notes-configuration text:note-class="footnote" style:num-format="1" 
text:start-value="0" text:footnotes-position="page" 
text:start-numbering-at="document"/>
+  <text:notes-configuration text:note-class="endnote" style:num-format="i" 
text:start-value="0"/>
+  <text:linenumbering-configuration text:number-lines="false" 
text:offset="0.499cm" style:num-format="1" text:number-position="left" 
text:increment="5"/>
+  <style:default-page-layout>
+   <style:page-layout-properties style:layout-grid-standard-mode="true"/>
+  </style:default-page-layout>
+ </office:styles>
+ <office:automatic-styles>
+  <style:style style:name="T1" style:family="text">
+   <style:text-properties fo:language="en" fo:country="IE"/>
+  </style:style>
+  <style:page-layout style:name="pm1">
+   <style:page-layout-properties fo:page-width="21.001cm" 
fo:page-height="29.7cm" style:num-format="1" style:print-orientation="portrait" 
fo:margin-top="2.499cm" fo:margin-bottom="2cm" fo:margin-left="2.499cm" 
fo:margin-right="2.499cm" style:writing-mode="lr-tb" 
style:layout-grid-color="#c0c0c0" style:layout-grid-lines="39" 
style:layout-grid-base-height="0.635cm" style:layout-grid-ruby-height="0cm" 
style:layout-grid-mode="none" style:layout-grid-ruby-below="false" 
style:layout-grid-print="false" style:layout-grid-display="false" 
style:layout-grid-base-width="0.388cm" style:layout-grid-snap-to="true" 
style:footnote-max-height="0cm" loext:margin-gutter="0cm">
+    <style:footnote-sep style:width="0.018cm" 
style:distance-before-sep="0.101cm" style:distance-after-sep="0.101cm" 
style:line-style="solid" style:adjustment="left" style:rel-width="25%" 
style:color="#000000"/>
+   </style:page-layout-properties>
+   <style:header-style/>
+   <style:footer-style/>
+  </style:page-layout>
+  <style:style style:name="dp1" style:family="drawing-page">
+   <style:drawing-page-properties draw:background-size="full"/>
+  </style:style>
+ </office:automatic-styles>
+ <office:master-styles>
+  <style:master-page style:name="Standard" style:page-layout-name="pm1" 
draw:style-name="dp1"/>
+ </office:master-styles>
+ <office:body>
+  <office:text>
+   <text:sequence-decls>
+    <text:sequence-decl text:display-outline-level="0" 
text:name="Illustration"/>
+    <text:sequence-decl text:display-outline-level="0" text:name="Table"/>
+    <text:sequence-decl text:display-outline-level="0" text:name="Text"/>
+    <text:sequence-decl text:display-outline-level="0" text:name="Drawing"/>
+    <text:sequence-decl text:display-outline-level="0" text:name="Figure"/>
+   </text:sequence-decls>
+   <text:p text:style-name="Standard"><field:fieldmark-start 
text:name="Bookmark1" 
field:type="vnd.oasis.opendocument.field.UNHANDLED"><field:param 
field:name="vnd.oasis.opendocument.field.code" 
field:value=""/></field:fieldmark-start><text:s/>QUOTE <text:s/>"foo </text:p>
+   <text:p text:style-name="Standard"><text:s/><field:fieldmark-start 
text:name="Bookmark" 
field:type="vnd.oasis.opendocument.field.UNHANDLED"><field:param 
field:name="vnd.oasis.opendocument.field.code" 
field:value=""/></field:fieldmark-start><text:s/>QUOTE <text:s/>"foo </text:p>
+   <text:p text:style-name="Standard"><text:s/>bar </text:p>
+   <text:p text:style-name="Standard">baz" <field:fieldmark-separator/>foo 
</text:p>
+   <text:p text:style-name="Standard"><text:s/>bar </text:p>
+   <text:p text:style-name="Standard">baz<field:fieldmark-end/></text:p>
+   <text:p text:style-name="Standard">bar </text:p>
+   <text:p text:style-name="Standard"><text:span text:style-name="T1">baz" 
</text:span><field:fieldmark-separator/><text:span text:style-name="T1">foo 
</text:span></text:p>
+   <text:p text:style-name="Standard"><text:span 
text:style-name="T1"><text:s/>foo </text:span></text:p>
+   <text:p text:style-name="Standard"><text:span 
text:style-name="T1"><text:s/>bar </text:span></text:p>
+   <text:p text:style-name="Standard"><text:span 
text:style-name="T1">baz</text:span></text:p>
+   <text:p text:style-name="Standard"><text:span text:style-name="T1">bar 
</text:span></text:p>
+   <text:p text:style-name="Standard"><text:span 
text:style-name="T1">baz</text:span><field:fieldmark-end/></text:p>
+   <text:p text:style-name="Standard"/>
+  </office:text>
+ </office:body>
+</office:document>
\ No newline at end of file
diff --git a/sw/qa/extras/globalfilter/globalfilter.cxx 
b/sw/qa/extras/globalfilter/globalfilter.cxx
index ebe5abb81804..fefc1fbda8ee 100644
--- a/sw/qa/extras/globalfilter/globalfilter.cxx
+++ b/sw/qa/extras/globalfilter/globalfilter.cxx
@@ -1041,6 +1041,7 @@ void Test::testNestedFieldmark()
     pBatch->commit();
 
     std::pair<OUString, OUString> const aFilterNames[] = {
+        {"writer8", "fieldmark_QUOTE_nest.fodt"},
         {"Office Open XML Text", "fieldmark_QUOTE_nest.docx"},
         {"Rich Text Format", "fieldmark_QUOTE_nest.rtf"},
     };
@@ -1465,12 +1466,20 @@ void Test::testTextFormField()
 
         // In the first paragraph we have an empty text form field with the 
placeholder spaces
         const uno::Reference< text::XTextRange > xPara = getParagraph(1);
+        CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), 
OUString("TextFieldStart"), getProperty<OUString>(getRun(xPara, 1), 
"TextPortionType"));
+        CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), 
OUString("TextFieldSeparator"), getProperty<OUString>(getRun(xPara, 2), 
"TextPortionType"));
+        CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), 
OUString("Text"), getProperty<OUString>(getRun(xPara, 3), "TextPortionType"));
         sal_Unicode vEnSpaces[5] = {8194, 8194, 8194, 8194, 8194};
-        CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), 
OUString(vEnSpaces, 5), xPara->getString());
+        CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), 
OUString(vEnSpaces, 5), getRun(xPara, 3)->getString());
+        CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), 
OUString("TextFieldEnd"), getProperty<OUString>(getRun(xPara, 4), 
"TextPortionType"));
 
         // In the second paragraph we have a set text
         const uno::Reference< text::XTextRange > xPara2 = getParagraph(2);
-        CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), 
OUString("xxxxx"), xPara2->getString());
+        CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), 
OUString("TextFieldStart"), getProperty<OUString>(getRun(xPara2, 1), 
"TextPortionType"));
+        CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), 
OUString("TextFieldSeparator"), getProperty<OUString>(getRun(xPara2, 2), 
"TextPortionType"));
+        CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), 
OUString("Text"), getProperty<OUString>(getRun(xPara2, 3), "TextPortionType"));
+        CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), 
OUString("xxxxx"), getRun(xPara2, 3)->getString());
+        CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), 
OUString("TextFieldEnd"), getProperty<OUString>(getRun(xPara2, 4), 
"TextPortionType"));
     }
 }
 
diff --git a/sw/source/core/inc/unobookmark.hxx 
b/sw/source/core/inc/unobookmark.hxx
index 57b2d1d9a5b2..09ccb69e6da4 100644
--- a/sw/source/core/inc/unobookmark.hxx
+++ b/sw/source/core/inc/unobookmark.hxx
@@ -61,7 +61,8 @@ protected:
     /// @throws css::uno::RuntimeException
     void attachToRangeEx(
             const css::uno::Reference< css::text::XTextRange > & xTextRange,
-            IDocumentMarkAccess::MarkType eType);
+            IDocumentMarkAccess::MarkType eType,
+            bool isFieldmarkSeparatorAtStart = false);
     /// @throws css::lang::IllegalArgumentException
     /// @throws css::uno::RuntimeException
     virtual void attachToRange(
@@ -190,6 +191,7 @@ class SwXFieldmark final
 {
     ::sw::mark::ICheckboxFieldmark* getCheckboxFieldmark();
     bool const m_bReplacementObject;
+    bool m_isFieldmarkSeparatorAtStart = false;
 
     css::uno::Reference<css::text::XTextRange>
         GetCommand(::sw::mark::IFieldmark const& rMark);
diff --git a/sw/source/core/unocore/unobkm.cxx 
b/sw/source/core/unocore/unobkm.cxx
index a98956749713..456325d5f575 100644
--- a/sw/source/core/unocore/unobkm.cxx
+++ b/sw/source/core/unocore/unobkm.cxx
@@ -206,7 +206,8 @@ sal_Int64 SAL_CALL SwXBookmark::getSomething( const 
uno::Sequence< sal_Int8 >& r
 
 void SwXBookmark::attachToRangeEx(
     const uno::Reference< text::XTextRange > & xTextRange,
-    IDocumentMarkAccess::MarkType eType)
+    IDocumentMarkAccess::MarkType eType,
+    bool const isFieldmarkSeparatorAtStart)
 {
     if (m_pImpl->m_pRegisteredBookmark)
     {
@@ -247,7 +248,10 @@ void SwXBookmark::attachToRangeEx(
     }
     m_pImpl->registerInMark(*this,
         m_pImpl->m_pDoc->getIDocumentMarkAccess()->makeMark(
-            aPam, m_pImpl->m_sMarkName, eType, ::sw::mark::InsertMode::New));
+            aPam, m_pImpl->m_sMarkName, eType, ::sw::mark::InsertMode::New,
+            // note: aPam will be moved fwd by inserting start char, so sep
+            // will be directly following start
+            isFieldmarkSeparatorAtStart ? aPam.Start() : nullptr));
     // #i81002#
     // Check, if bookmark has been created.
     // E.g., the creation of a cross-reference bookmark is suppress,
@@ -622,7 +626,8 @@ void SwXFieldmark::attachToRange( const uno::Reference < 
text::XTextRange >& xTe
 {
 
     attachToRangeEx( xTextRange,
-                     ( m_bReplacementObject ? 
IDocumentMarkAccess::MarkType::CHECKBOX_FIELDMARK : 
IDocumentMarkAccess::MarkType::TEXT_FIELDMARK ) );
+         (m_bReplacementObject ? 
IDocumentMarkAccess::MarkType::CHECKBOX_FIELDMARK : 
IDocumentMarkAccess::MarkType::TEXT_FIELDMARK),
+         m_isFieldmarkSeparatorAtStart);
 }
 
 OUString SwXFieldmark::getFieldType()
@@ -743,6 +748,14 @@ SwXFieldmark::setPropertyValue(const OUString& 
PropertyName,
 
         pCheckboxFm->SetChecked( bChecked );
     }
+    else if (PropertyName == "PrivateSeparatorAtStart")
+    {
+        bool isFieldmarkSeparatorAtStart{};
+        if (rValue >>= isFieldmarkSeparatorAtStart)
+        {
+            m_isFieldmarkSeparatorAtStart = isFieldmarkSeparatorAtStart;
+        }
+    }
     // this doesn't support any SwXBookmark property
 }
 
diff --git a/xmloff/source/core/xmltoken.cxx b/xmloff/source/core/xmltoken.cxx
index a996c4e9fb54..1606dbc68ab3 100644
--- a/xmloff/source/core/xmltoken.cxx
+++ b/xmloff/source/core/xmltoken.cxx
@@ -3318,6 +3318,7 @@ namespace xmloff::token {
         // enhanced fields
         TOKEN( "fieldmark",             XML_FIELDMARK ),
         TOKEN( "fieldmark-start",       XML_FIELDMARK_START ),
+        TOKEN( "fieldmark-separator",   XML_FIELDMARK_SEPARATOR ),
         TOKEN( "fieldmark-end",         XML_FIELDMARK_END ),
 
         TOKEN( "image-scale",           XML_IMAGE_SCALE  ),
diff --git a/xmloff/source/text/XMLTextMarkImportContext.cxx 
b/xmloff/source/text/XMLTextMarkImportContext.cxx
index 8e823d6c1757..4e42899e709c 100644
--- a/xmloff/source/text/XMLTextMarkImportContext.cxx
+++ b/xmloff/source/text/XMLTextMarkImportContext.cxx
@@ -35,6 +35,7 @@
 #include <com/sun/star/xml/sax/XAttributeList.hpp>
 #include <com/sun/star/text/ControlCharacter.hpp>
 #include <com/sun/star/text/XTextContent.hpp>
+#include <com/sun/star/text/XTextRangeCompare.hpp>
 #include <com/sun/star/beans/XPropertySet.hpp>
 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
 #include <com/sun/star/container/XNamed.hpp>
@@ -105,7 +106,7 @@ namespace {
 
 enum lcl_MarkType { TypeReference, TypeReferenceStart, TypeReferenceEnd,
                     TypeBookmark, TypeBookmarkStart, TypeBookmarkEnd,
-                    TypeFieldmark, TypeFieldmarkStart, TypeFieldmarkEnd
+                    TypeFieldmark, TypeFieldmarkStart, TypeFieldmarkSeparator, 
TypeFieldmarkEnd
                   };
 
 }
@@ -120,6 +121,7 @@ SvXMLEnumMapEntry<lcl_MarkType> const lcl_aMarkTypeMap[] =
     { XML_BOOKMARK_END,           TypeBookmarkEnd },
     { XML_FIELDMARK,              TypeFieldmark },
     { XML_FIELDMARK_START,        TypeFieldmarkStart },
+    { XML_FIELDMARK_SEPARATOR,    TypeFieldmarkSeparator },
     { XML_FIELDMARK_END,          TypeFieldmarkEnd },
     { XML_TOKEN_INVALID,          lcl_MarkType(0) },
 };
@@ -173,12 +175,12 @@ void XMLTextMarkImportContext::startFastElement( 
sal_Int32 nElement,
 }
 
 static auto InsertFieldmark(SvXMLImport & rImport,
-        XMLTextImportHelper & rHelper, OUString const& rName) -> void
+        XMLTextImportHelper & rHelper, bool const isFieldmarkSeparatorMissing) 
-> void
 {
     assert(rHelper.hasCurrentFieldCtx()); // was set up in StartElement()
 
     // fdo#86795 check if it's actually a checkbox first
-    OUString const type(rHelper.getCurrentFieldType());
+    auto const [ name, type ] = rHelper.getCurrentFieldType();
     OUString const fieldmarkTypeName = lcl_getFieldmarkName(type);
     if (fieldmarkTypeName == ODF_FORMCHECKBOX ||
         fieldmarkTypeName == ODF_FORMDROPDOWN)
@@ -187,9 +189,20 @@ static auto InsertFieldmark(SvXMLImport & rImport,
         return;
     }
 
+    uno::Reference<text::XTextRange> const 
xStartRange(rHelper.getCurrentFieldStart());
+    uno::Reference<text::XTextCursor> const xCursor(
+        rHelper.GetText()->createTextCursorByRange(xStartRange));
+    uno::Reference<text::XTextRangeCompare> const xCompare(rHelper.GetText(), 
uno::UNO_QUERY);
+    if (xCompare->compareRegionStarts(xStartRange, rHelper.GetCursorAsRange()) 
< 0)
+    {
+        SAL_WARN("xmloff.text", "invalid field mark positions");
+        assert(false);
+    }
+    xCursor->gotoRange(rHelper.GetCursorAsRange(), true);
+
     Reference<XTextContent> const xContent = 
XMLTextMarkImportContext::CreateAndInsertMark(
-            rImport, "com.sun.star.text.Fieldmark",
-            rName, rHelper.GetCursorAsRange());
+            rImport, "com.sun.star.text.Fieldmark", name, xCursor,
+            OUString(), isFieldmarkSeparatorMissing);
 
     if (!xContent.is())
         return;
@@ -256,7 +269,7 @@ void XMLTextMarkImportContext::endFastElement(sal_Int32 
nElement)
     if (!SvXMLUnitConverter::convertEnum(nTmp, 
SvXMLImport::getNameFromToken(nElement), lcl_aMarkTypeMap))
         return;
 
-    if (m_sBookmarkName.isEmpty() && TypeFieldmarkEnd != nTmp)
+    if (m_sBookmarkName.isEmpty() && TypeFieldmarkEnd != nTmp && 
TypeFieldmarkSeparator != nTmp)
         return;
 
     switch (nTmp)
@@ -412,13 +425,21 @@ void XMLTextMarkImportContext::endFastElement(sal_Int32 
nElement)
             // else: no start found -> ignore!
             break;
         }
-        case TypeFieldmarkStart: // no separator, so insert at start
+        case TypeFieldmarkStart:
+        {
+            break;
+        }
+        case TypeFieldmarkSeparator:
         {
-            InsertFieldmark(GetImport(), m_rHelper, m_sBookmarkName);
+            InsertFieldmark(GetImport(), m_rHelper, false);
             break;
         }
         case TypeFieldmarkEnd:
         {
+            if (!m_rHelper.hasCurrentFieldSeparator())
+            {   // backward compat for old files without separator
+                InsertFieldmark(GetImport(), m_rHelper, true);
+            }
             PopFieldmark(m_rHelper);
             break;
         }
@@ -446,7 +467,8 @@ Reference<XTextContent> 
XMLTextMarkImportContext::CreateAndInsertMark(
     const OUString& sServiceName,
     const OUString& sMarkName,
     const Reference<XTextRange> & rRange,
-    const OUString& i_rXmlId)
+    const OUString& i_rXmlId,
+    bool const isFieldmarkSeparatorMissing)
 {
     // create mark
     const Reference<XMultiServiceFactory> xFactory(rImport.GetModel(),
@@ -478,6 +500,12 @@ Reference<XTextContent> 
XMLTextMarkImportContext::CreateAndInsertMark(
             }
         }
 
+        if (isFieldmarkSeparatorMissing)
+        {
+            uno::Reference<beans::XPropertySet> const xProps(xIfc, 
uno::UNO_QUERY_THROW);
+            xProps->setPropertyValue("PrivateSeparatorAtStart", 
uno::Any(true));
+        }
+
         // cast to XTextContent and attach to document
         const Reference<XTextContent> xTextContent(xIfc, UNO_QUERY);
         if (xTextContent.is())
diff --git a/xmloff/source/text/XMLTextMarkImportContext.hxx 
b/xmloff/source/text/XMLTextMarkImportContext.hxx
index 407cddbadf7f..da05f524083e 100644
--- a/xmloff/source/text/XMLTextMarkImportContext.hxx
+++ b/xmloff/source/text/XMLTextMarkImportContext.hxx
@@ -96,7 +96,8 @@ public:
         const OUString& sServiceName,
         const OUString& sMarkName,
         const css::uno::Reference<css::text::XTextRange> & rRange,
-        const OUString& i_rXmlId = OUString());
+        const OUString& i_rXmlId = OUString(),
+        bool const isFieldmarkSeparatorMissing = false);
 
     bool FindName(
         const css::uno::Reference<css::xml::sax::XFastAttributeList> & 
xAttrList);
diff --git a/xmloff/source/text/txtimp.cxx b/xmloff/source/text/txtimp.cxx
index 079e8df8d82d..f26ce21e66ab 100644
--- a/xmloff/source/text/txtimp.cxx
+++ b/xmloff/source/text/txtimp.cxx
@@ -166,7 +166,7 @@ struct XMLTextImportHelper::Impl
     typedef ::std::pair< OUString, OUString> field_name_type_t;
     typedef ::std::pair< OUString, OUString > field_param_t;
     typedef ::std::vector< field_param_t > field_params_t;
-    typedef ::std::tuple<field_name_type_t, field_params_t, 
uno::Reference<text::XFormField>> field_stack_item_t;
+    typedef ::std::tuple<field_name_type_t, field_params_t, 
uno::Reference<text::XFormField>, uno::Reference<text::XTextRange>> 
field_stack_item_t;
     typedef ::std::stack< field_stack_item_t > field_stack_t;
 
     field_stack_t m_FieldStack;
@@ -2105,7 +2105,7 @@ bool XMLTextImportHelper::FindAndRemoveBookmarkStartRange(
 void XMLTextImportHelper::pushFieldCtx( const OUString& name, const OUString& 
type )
 {
     m_xImpl->m_FieldStack.push(Impl::field_stack_item_t(
-        Impl::field_name_type_t(name, type), Impl::field_params_t(), 
uno::Reference<text::XFormField>{}));
+        Impl::field_name_type_t(name, type), Impl::field_params_t(), 
uno::Reference<text::XFormField>{}, GetCursor()->getStart()));
 }
 
 uno::Reference<text::XFormField>
@@ -2133,16 +2133,42 @@ void XMLTextImportHelper::addFieldParam( const 
OUString& name, const OUString& v
     }
 }
 
-OUString XMLTextImportHelper::getCurrentFieldType()
+::std::pair<OUString, OUString> XMLTextImportHelper::getCurrentFieldType() 
const
 {
     assert(!m_xImpl->m_FieldStack.empty());
     if (!m_xImpl->m_FieldStack.empty())
     {
-        return std::get<0>(m_xImpl->m_FieldStack.top()).second;
+        return std::get<0>(m_xImpl->m_FieldStack.top());
     }
     else
     {
-        return OUString();
+        return {};
+    }
+}
+
+uno::Reference<text::XTextRange> XMLTextImportHelper::getCurrentFieldStart() 
const
+{
+    assert(!m_xImpl->m_FieldStack.empty());
+    if (!m_xImpl->m_FieldStack.empty())
+    {
+        return std::get<3>(m_xImpl->m_FieldStack.top());
+    }
+    else
+    {
+        return {};
+    }
+}
+
+bool XMLTextImportHelper::hasCurrentFieldSeparator() const
+{
+    assert(!m_xImpl->m_FieldStack.empty());
+    if (!m_xImpl->m_FieldStack.empty())
+    {
+        return std::get<2>(m_xImpl->m_FieldStack.top()).is();
+    }
+    else
+    {
+        return {};
     }
 }
 
diff --git a/xmloff/source/text/txtparae.cxx b/xmloff/source/text/txtparae.cxx
index 5d9bd3768d01..63232f8b2822 100644
--- a/xmloff/source/text/txtparae.cxx
+++ b/xmloff/source/text/txtparae.cxx
@@ -181,6 +181,7 @@ constexpr OUStringLiteral 
gsVisitedCharStyleName(u"VisitedCharStyleName");
 constexpr OUStringLiteral gsWidth(u"Width");
 constexpr OUStringLiteral gsWidthType( u"WidthType"  );
 constexpr OUStringLiteral gsTextFieldStart( u"TextFieldStart"  );
+constexpr OUStringLiteral gsTextFieldSep(u"TextFieldSeparator");
 constexpr OUStringLiteral gsTextFieldEnd( u"TextFieldEnd"  );
 constexpr OUStringLiteral gsTextFieldStartEnd( u"TextFieldStartEnd"  );
 
@@ -2284,6 +2285,19 @@ void XMLTextParagraphExport::exportTextRangeEnumeration(
                     }
                 }
             }
+            else if (sType == gsTextFieldSep)
+            {
+                Reference<text::XFormField> const 
xFormField(xPropSet->getPropertyValue(gsBookmark), UNO_QUERY);
+                if (!bAutoStyles)
+                {
+                    if (GetExport().getSaneDefaultVersion() & 
SvtSaveOptions::ODFSVER_EXTENDED)
+                    {
+                        SvXMLElementExport aElem( GetExport(), !bAutoStyles,
+                            XML_NAMESPACE_FIELD, XML_FIELDMARK_SEPARATOR,
+                            false, false );
+                    }
+                }
+            }
             else if (sType == gsTextFieldEnd)
             {
                 if (!bAutoStyles)
diff --git a/xmloff/source/text/txtparai.cxx b/xmloff/source/text/txtparai.cxx
index 3641d7e1af20..5a37d1e46894 100644
--- a/xmloff/source/text/txtparai.cxx
+++ b/xmloff/source/text/txtparai.cxx
@@ -1433,6 +1433,7 @@ css::uno::Reference< css::xml::sax::XFastContextHandler > 
XMLImpSpanContext_Impl
 
     case XML_ELEMENT(FIELD, XML_FIELDMARK):
     case XML_ELEMENT(FIELD, XML_FIELDMARK_START):
+    case XML_ELEMENT(FIELD, XML_FIELDMARK_SEPARATOR):
     case XML_ELEMENT(FIELD, XML_FIELDMARK_END):
         pContext = new XMLTextMarkImportContext(rImport, 
*rImport.GetTextImport(),
                                                 
rHints.GetCrossRefHeadingBookmark());
diff --git a/xmloff/source/token/tokens.txt b/xmloff/source/token/tokens.txt
index 849802878614..568122e0f582 100644
--- a/xmloff/source/token/tokens.txt
+++ b/xmloff/source/token/tokens.txt
@@ -3093,6 +3093,7 @@ use-zero
 ignore
 fieldmark
 fieldmark-start
+fieldmark-separator
 fieldmark-end
 image-scale
 isotropic

Reply via email to