vcl/qa/cppunit/pdfexport/data/PDF_export_with_formcontrol.fodt |  174 ++++++
 vcl/qa/cppunit/pdfexport/pdfexport.cxx                         |  257 
++++++++++
 vcl/source/gdi/pdfextoutdevdata.cxx                            |   20 
 3 files changed, 447 insertions(+), 4 deletions(-)

New commits:
commit 2e32aa1e9fc240c9cd9854655106d0decbd3694a
Author:     Michael Stahl <michael.st...@allotropia.de>
AuthorDate: Tue Oct 10 18:20:04 2023 +0200
Commit:     Michael Stahl <michael.st...@allotropia.de>
CommitDate: Thu Oct 12 11:06:10 2023 +0200

    tdf#157397 vcl: PDF export: fix CreateControl replay
    
    The problem is that the CreateLink and CreateControl actions are
    replayed in a different order than they are recorded, because CreateLink
    is a global action, and CreateControl a page action.
    
    This means that the mCurId at the time when
    PDFExtOutDevData::CreateControl() is called does not correspond to a
    position in mParaIds when CreateControl is replayed; it will be inserted
    too early and bump all the CreateLink ones to later indexes.
    
    Avoid this by adding another global action CreateControlLink that is
    added when CreateControl is being replayed, which appears to work.
    
    (Another subtle problem is that, in case of PDF/A-1, the page actions
    could be discarded completely; this should work in that case too.)
    
    (regression from commit d4d471fc88fe4fd14f44dfccdfe360dec327d4f0)
    
    Change-Id: I92d89ac08db6548e9f0d1480d984aeacb4d22262
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/157767
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>

diff --git a/vcl/qa/cppunit/pdfexport/data/PDF_export_with_formcontrol.fodt 
b/vcl/qa/cppunit/pdfexport/data/PDF_export_with_formcontrol.fodt
new file mode 100644
index 000000000000..4aa4a92b6710
--- /dev/null
+++ b/vcl/qa/cppunit/pdfexport/data/PDF_export_with_formcontrol.fodt
@@ -0,0 +1,174 @@
+<?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>A. 
Spielhoff</meta:initial-creator><meta:creation-date>2020-09-12T10:51:34.438117571</meta:creation-date><dc:date>2023-10-11T12:40:15.543658302</dc:date><meta:editing-duration>PT7H23M50S</meta:editing-duration><meta:editing-cycles>98</meta:editing-cycles><meta:generator>LibreOfficeDev/7.5.7.0.0$Linux_X86_64
 
LibreOffice_project/0325c0aa2d3e6df97ff554ca540d316273fd149a</meta:generator><meta:print-date>2023-09-23T14:07:35.317591779</meta:print-date><meta:printed-by>PDF-Dateien:
 A Spielhoff</meta:printed-by><meta:document-statistic meta:table-count="8" 
meta:image-count="0" meta:object-count="0" meta:page-count="1" 
meta:paragraph-count="15" meta:word-count="129" meta:character-count="882" 
meta:non-whitespace-character-count="767"/></office:meta>
+ <office:font-face-decls>
+  <style:font-face style:name="Arial" svg:font-family="Arial" 
style:font-family-generic="swiss"/>
+  <style:font-face style:name="Arial2" svg:font-family="Arial" 
style:font-adornments="Kursiv" style:font-family-generic="swiss"/>
+  <style:font-face style:name="SimSun" svg:font-family="SimSun" 
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.1181in" draw:shadow-offset-y="0.1181in" 
draw:start-line-spacing-horizontal="0.1114in" 
draw:start-line-spacing-vertical="0.1114in" 
draw:end-line-spacing-horizontal="0.1114in" 
draw:end-line-spacing-vertical="0.1114in" style:writing-mode="lr-tb" 
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="Arial" fo:font-size="11pt" fo:language="de" fo:country="DE" 
style:letter-kerning="true" style:font-name-asian="SimSun" 
style:font-size-asian="10.5pt" style:language-asian="zh" 
style:country-asian="CN" style:font-name-complex="Arial" 
style:font-size-complex="11pt" style:language-complex="hi" 
style:country-complex="IN"/>
+  </style:default-style>
+  <style:default-style style:family="paragraph">
+   <style:paragraph-properties fo:orphans="2" fo:widows="2" 
fo:hyphenation-ladder-count="no-limit" style:text-autospace="ideograph-alpha" 
style:punctuation-wrap="hanging" style:line-break="strict" 
style:tab-stop-distance="0.4925in" style:writing-mode="page"/>
+   <style:text-properties style:use-window-font-color="true" 
loext:opacity="0%" style:font-name="Arial" fo:font-size="11pt" fo:language="de" 
fo:country="DE" style:letter-kerning="true" style:font-name-asian="SimSun" 
style:font-size-asian="10.5pt" style:language-asian="zh" 
style:country-asian="CN" style:font-name-complex="Arial" 
style:font-size-complex="11pt" style:language-complex="hi" 
style:country-complex="IN" 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="no-limit" 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:style style:name="Text_20_body" style:display-name="Text body" 
style:family="paragraph" style:parent-style-name="Standard" style:class="text">
+   <style:paragraph-properties fo:margin-top="0in" fo:margin-bottom="0.0972in" 
style:contextual-spacing="false" fo:line-height="115%"/>
+  </style:style>
+  <style:style style:name="Footnote_20_Symbol" style:display-name="Footnote 
Symbol" style:family="text"/>
+  <style:style style:name="Footnote_20_anchor" style:display-name="Footnote 
anchor" style:family="text">
+   <style:text-properties style:text-position="super 58%"/>
+  </style:style>
+  <style:style style:name="Internet_20_link" style:display-name="Internet 
link" style:family="text">
+   <style:text-properties fo:color="#0000ff" loext:opacity="100%" 
style:text-underline-style="solid" style:text-underline-width="auto" 
style:text-underline-color="font-color"/>
+  </style:style>
+  <style:style style:name="Visited_20_Internet_20_Link" 
style:display-name="Visited Internet Link" style:family="text">
+   <style:text-properties fo:color="#954f72" loext:opacity="100%" 
style:text-underline-style="solid" style:text-underline-width="auto" 
style:text-underline-color="font-color"/>
+  </style:style>
+  <text:outline-style style:name="Outline">
+   <text:outline-level-style text:level="1" loext:num-list-format="%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" loext:num-list-format="%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" loext:num-list-format="%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" loext:num-list-format="%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" loext:num-list-format="%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" loext:num-list-format="%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" loext:num-list-format="%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" loext:num-list-format="%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" loext:num-list-format="%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" loext:num-list-format="%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" 
text:citation-style-name="Footnote_20_Symbol" 
text:citation-body-style-name="Footnote_20_anchor" 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.1965in" style:num-format="1" text:number-position="left" 
text:increment="5"/>
+ </office:styles>
+ <office:automatic-styles>
+  <style:style style:name="P13" style:family="paragraph" 
style:parent-style-name="Text_20_body">
+   <style:text-properties/>
+  </style:style>
+  <style:style style:name="P14" style:family="paragraph" 
style:parent-style-name="Text_20_body">
+   <style:text-properties/>
+  </style:style>
+  <style:style style:name="P15" style:family="paragraph" 
style:parent-style-name="Text_20_body" style:master-page-name="Standard">
+   <style:paragraph-properties style:page-number="auto"/>
+  </style:style>
+  <style:style style:name="P28" style:family="paragraph">
+   <style:paragraph-properties fo:text-align="start"/>
+   <style:text-properties fo:color="#3465a4" 
style:text-line-through-style="none" style:text-line-through-type="none" 
style:font-name="Arial2" fo:font-size="11pt" fo:font-style="italic" 
style:text-underline-style="none"/>
+  </style:style>
+  <style:style style:name="T1" style:family="text">
+   <style:text-properties/>
+  </style:style>
+  <style:style style:name="T5" style:family="text">
+   <style:text-properties/>
+  </style:style>
+  <style:style style:name="T6" style:family="text">
+   <style:text-properties/>
+  </style:style>
+  <style:style style:name="gr1" style:family="graphic">
+   <style:graphic-properties fo:background-color="#f5f5f5" fo:border="solid 
#3465a4" style:wrap="run-through" style:number-wrapped-paragraphs="no-limit" 
style:vertical-pos="from-top" style:horizontal-pos="from-left" 
style:horizontal-rel="paragraph" 
draw:wrap-influence-on-position="once-concurrent" loext:allow-overlap="true" 
style:flow-with-text="false"/>
+  </style:style>
+  <style:page-layout style:name="pm1">
+   <style:page-layout-properties fo:page-width="8.2681in" 
fo:page-height="11.6929in" style:num-format="1" 
style:print-orientation="portrait" fo:margin-top="0.3937in" 
fo:margin-bottom="0.3937in" fo:margin-left="0.7874in" 
fo:margin-right="0.7874in" style:writing-mode="lr-tb" 
style:layout-grid-color="#c0c0c0" style:layout-grid-lines="20" 
style:layout-grid-base-height="0.278in" style:layout-grid-ruby-height="0.139in" 
style:layout-grid-mode="none" style:layout-grid-ruby-below="false" 
style:layout-grid-print="false" style:layout-grid-display="false" 
style:footnote-max-height="0in" loext:margin-gutter="0in">
+    <style:columns fo:column-count="1" fo:column-gap="0in"/>
+    <style:footnote-sep style:width="0.0071in" 
style:distance-before-sep="0.0398in" style:distance-after-sep="0.0398in" 
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>
+   <office:forms form:automatic-focus="false" form:apply-design-mode="false">
+    <form:form form:name="Formular" form:apply-filter="true" 
form:command-type="table" 
form:control-implementation="ooo:com.sun.star.form.component.Form" 
office:target-frame="">
+     <form:properties>
+      <form:property form:property-name="PropertyChangeNotificationEnabled" 
office:value-type="boolean" office:boolean-value="true"/>
+      <form:property form:property-name="TargetURL" office:value-type="string" 
office:string-value=""/>
+     </form:properties>
+     <form:textarea form:name="XXXX-" 
form:control-implementation="ooo:com.sun.star.form.component.TextField" 
xml:id="control1" form:id="control1" form:tab-stop="false" 
form:input-required="false" form:convert-empty-to-null="true">
+      <form:properties>
+       <form:property form:property-name="ControlTypeinMSO" 
office:value-type="float" office:value="0"/>
+       <form:property form:property-name="DefaultControl" 
office:value-type="string" 
office:string-value="com.sun.star.form.control.TextField"/>
+       <form:property form:property-name="MultiLine" 
office:value-type="boolean" office:boolean-value="true"/>
+       <form:property form:property-name="ObjIDinMSO" 
office:value-type="float" office:value="65535"/>
+      </form:properties>
+     </form:textarea>
+    </form:form>
+   </office:forms>
+   <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="P15">This <text:span 
text:style-name="T1">t</text:span>ext document contains some links and a text 
control.</text:p>
+   <text:p text:style-name="P13"><text:span text:style-name="T1">When 
exporting the document to PDF in LO 7.5.</text:span><text:span 
text:style-name="T6">3.2</text:span><text:span text:style-name="T1"> or newer 
the links won't have the right target any more. First link to "Kläranlage" will 
open last link to "#pano=24", </text:span><text:span 
text:style-name="T5">second link wont open anything and third link will open 
"Mechanische Vorreinigung"</text:span></text:p>
+   <text:p text:style-name="Text_20_body"><text:a xlink:type="simple" 
xlink:href="https://klexikon.zum.de/wiki/Kläranlage"; 
text:style-name="Internet_20_link" 
text:visited-style-name="Visited_20_Internet_20_Link">https://klexikon.zum.de/wiki/Kläranlage</text:a></text:p>
+   <text:p text:style-name="Text_20_body"><text:a xlink:type="simple" 
xlink:href="https://de.wikipedia.org/wiki/Kläranlage#Mechanische_Vorreinigung"; 
text:style-name="Internet_20_link" 
text:visited-style-name="Visited_20_Internet_20_Link">https://de.wikipedia.org/wiki/Kläranlage#Mechanische_Vorreinigung</text:a></text:p>
+   <text:p text:style-name="Text_20_body"><text:a xlink:type="simple" 
xlink:href="https://vr-easy.com/tour/usr/220113-virtuellerschulausflug/#pano=24";
 text:style-name="Internet_20_link" 
text:visited-style-name="Visited_20_Internet_20_Link">https://vr-easy.com/tour/usr/220113-virtuellerschulausflug/#pano=24</text:a></text:p>
+   <text:p text:style-name="Text_20_body">Here a form control for getting 
possibility to input content.</text:p>
+   <text:p text:style-name="Text_20_body"><draw:control 
text:anchor-type="as-char" svg:y="-0.3146in" draw:z-index="0" draw:name="Form1" 
draw:style-name="gr1" draw:text-style-name="P28" svg:width="6.3776in" 
svg:height="1.7717in" draw:control="control1"/></text:p>
+   <text:p text:style-name="Text_20_body">When deleting the form control links 
will work as expected.</text:p>
+   <text:p text:style-name="P14">Up to LO 7.5.2.2 this bug won't 
appear.</text:p>
+  </office:text>
+ </office:body>
+</office:document>
\ No newline at end of file
diff --git a/vcl/qa/cppunit/pdfexport/pdfexport.cxx 
b/vcl/qa/cppunit/pdfexport/pdfexport.cxx
index f67deec04ae2..801a890c6c0b 100644
--- a/vcl/qa/cppunit/pdfexport/pdfexport.cxx
+++ b/vcl/qa/cppunit/pdfexport/pdfexport.cxx
@@ -4349,6 +4349,263 @@ CPPUNIT_TEST_FIXTURE(PdfExportTest, testTdf154982)
     CPPUNIT_ASSERT_EQUAL(int(2), nFigure);
 }
 
+CPPUNIT_TEST_FIXTURE(PdfExportTest, testTdf157397)
+{
+    aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export");
+
+    // Enable PDF/UA
+    uno::Sequence<beans::PropertyValue> aFilterData(
+        comphelper::InitPropertySequence({ { "PDFUACompliance", uno::Any(true) 
} }));
+    aMediaDescriptor["FilterData"] <<= aFilterData;
+    saveAsPDF(u"PDF_export_with_formcontrol.fodt");
+
+    vcl::filter::PDFDocument aDocument;
+    SvFileStream aStream(maTempFile.GetURL(), StreamMode::READ);
+    CPPUNIT_ASSERT(aDocument.Read(aStream));
+
+    // The document has one page.
+    std::vector<vcl::filter::PDFObjectElement*> aPages = aDocument.GetPages();
+    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), aPages.size());
+
+    vcl::filter::PDFObjectElement* pDocument(nullptr);
+    for (const auto& rDocElement : aDocument.GetElements())
+    {
+        auto pObject1 = 
dynamic_cast<vcl::filter::PDFObjectElement*>(rDocElement.get());
+        if (!pObject1)
+            continue;
+        auto pType1 = 
dynamic_cast<vcl::filter::PDFNameElement*>(pObject1->Lookup("Type"));
+        if (pType1 && pType1->GetValue() == "StructElem")
+        {
+            auto pS1 = 
dynamic_cast<vcl::filter::PDFNameElement*>(pObject1->Lookup("S"));
+            if (pS1 && pS1->GetValue() == "Document")
+            {
+                pDocument = pObject1;
+            }
+        }
+    }
+    CPPUNIT_ASSERT(pDocument);
+
+    auto pKids1 = 
dynamic_cast<vcl::filter::PDFArrayElement*>(pDocument->Lookup("K"));
+    CPPUNIT_ASSERT(pKids1);
+    // assume there are no MCID ref at this level
+    auto pKids1v = pKids1->GetElements();
+    auto pRefKid12 = 
dynamic_cast<vcl::filter::PDFReferenceElement*>(pKids1v[2]);
+    CPPUNIT_ASSERT(pRefKid12);
+    auto pObject12 = pRefKid12->LookupObject();
+    CPPUNIT_ASSERT(pObject12);
+    auto pType12 = 
dynamic_cast<vcl::filter::PDFNameElement*>(pObject12->Lookup("Type"));
+    CPPUNIT_ASSERT_EQUAL(OString("StructElem"), pType12->GetValue());
+    auto pS12 = 
dynamic_cast<vcl::filter::PDFNameElement*>(pObject12->Lookup("S"));
+    CPPUNIT_ASSERT_EQUAL(OString("Text#20body"), pS12->GetValue());
+
+    auto pKids12 = 
dynamic_cast<vcl::filter::PDFArrayElement*>(pObject12->Lookup("K"));
+    CPPUNIT_ASSERT(pKids12);
+    // assume there are no MCID ref at this level
+    auto pKids12v = pKids12->GetElements();
+    auto pRefKid120 = 
dynamic_cast<vcl::filter::PDFReferenceElement*>(pKids12v[0]);
+    CPPUNIT_ASSERT(pRefKid120);
+    auto pObject120 = pRefKid120->LookupObject();
+    CPPUNIT_ASSERT(pObject120);
+    auto pType120 = 
dynamic_cast<vcl::filter::PDFNameElement*>(pObject120->Lookup("Type"));
+    CPPUNIT_ASSERT_EQUAL(OString("StructElem"), pType120->GetValue());
+    auto pS120 = 
dynamic_cast<vcl::filter::PDFNameElement*>(pObject120->Lookup("S"));
+    CPPUNIT_ASSERT_EQUAL(OString("Link"), pS120->GetValue());
+
+    {
+        auto pKids = 
dynamic_cast<vcl::filter::PDFArrayElement*>(pObject120->Lookup("K"));
+        auto nMCID(0);
+        auto nRef(0);
+        for (size_t i = 0; i < pKids->GetElements().size(); ++i)
+        {
+            auto pNum = 
dynamic_cast<vcl::filter::PDFNumberElement*>(pKids->GetElement(i));
+            auto pRef = 
dynamic_cast<vcl::filter::PDFReferenceElement*>(pKids->GetElement(i));
+            if (pNum)
+            {
+                ++nMCID;
+            }
+            if (pRef)
+            {
+                ++nRef;
+                auto pObjR = pRef->LookupObject();
+                auto pOType = 
dynamic_cast<vcl::filter::PDFNameElement*>(pObjR->Lookup("Type"));
+                CPPUNIT_ASSERT_EQUAL(OString("OBJR"), pOType->GetValue());
+                auto pAnnotRef
+                    = 
dynamic_cast<vcl::filter::PDFReferenceElement*>(pObjR->Lookup("Obj"));
+                auto pAnnot = pAnnotRef->LookupObject();
+                auto pAType = 
dynamic_cast<vcl::filter::PDFNameElement*>(pAnnot->Lookup("Type"));
+                CPPUNIT_ASSERT_EQUAL(OString("Annot"), pAType->GetValue());
+                auto pASubtype
+                    = 
dynamic_cast<vcl::filter::PDFNameElement*>(pAnnot->Lookup("Subtype"));
+                CPPUNIT_ASSERT_EQUAL(OString("Link"), pASubtype->GetValue());
+                auto pAContents
+                    = 
dynamic_cast<vcl::filter::PDFHexStringElement*>(pAnnot->Lookup("Contents"));
+                CPPUNIT_ASSERT_EQUAL(
+                    u"https://klexikon.zum.de/wiki/Kläranlage"_ustr,
+                    
::vcl::filter::PDFDocument::DecodeHexStringUTF16BE(*pAContents));
+                CPPUNIT_ASSERT_EQUAL(OString("Link"), pASubtype->GetValue());
+                auto pAA = 
dynamic_cast<vcl::filter::PDFDictionaryElement*>(pAnnot->Lookup("A"));
+                CPPUNIT_ASSERT(pAA);
+                auto pAAType
+                    = 
dynamic_cast<vcl::filter::PDFNameElement*>(pAA->LookupElement("Type"));
+                CPPUNIT_ASSERT_EQUAL(OString("Action"), pAAType->GetValue());
+                auto pAAS = 
dynamic_cast<vcl::filter::PDFNameElement*>(pAA->LookupElement("S"));
+                CPPUNIT_ASSERT_EQUAL(OString("URI"), pAAS->GetValue());
+                auto pAAURI = 
dynamic_cast<vcl::filter::PDFLiteralStringElement*>(
+                    pAA->LookupElement("URI"));
+                
CPPUNIT_ASSERT_EQUAL(OString("https://klexikon.zum.de/wiki/Kl%C3%A4ranlage";),
+                                     pAAURI->GetValue());
+            }
+        }
+        CPPUNIT_ASSERT_EQUAL(static_cast<decltype(nMCID)>(1), nMCID);
+        CPPUNIT_ASSERT_EQUAL(static_cast<decltype(nRef)>(1), nRef);
+    }
+
+    auto pRefKid13 = 
dynamic_cast<vcl::filter::PDFReferenceElement*>(pKids1v[3]);
+    CPPUNIT_ASSERT(pRefKid13);
+    auto pObject13 = pRefKid13->LookupObject();
+    CPPUNIT_ASSERT(pObject13);
+    auto pType13 = 
dynamic_cast<vcl::filter::PDFNameElement*>(pObject13->Lookup("Type"));
+    CPPUNIT_ASSERT_EQUAL(OString("StructElem"), pType13->GetValue());
+    auto pS13 = 
dynamic_cast<vcl::filter::PDFNameElement*>(pObject13->Lookup("S"));
+    CPPUNIT_ASSERT_EQUAL(OString("Text#20body"), pS13->GetValue());
+
+    auto pKids13 = 
dynamic_cast<vcl::filter::PDFArrayElement*>(pObject13->Lookup("K"));
+    CPPUNIT_ASSERT(pKids13);
+    // assume there are no MCID ref at this level
+    auto pKids13v = pKids13->GetElements();
+    auto pRefKid130 = 
dynamic_cast<vcl::filter::PDFReferenceElement*>(pKids13v[0]);
+    CPPUNIT_ASSERT(pRefKid130);
+    auto pObject130 = pRefKid130->LookupObject();
+    CPPUNIT_ASSERT(pObject130);
+    auto pType130 = 
dynamic_cast<vcl::filter::PDFNameElement*>(pObject130->Lookup("Type"));
+    CPPUNIT_ASSERT_EQUAL(OString("StructElem"), pType130->GetValue());
+    auto pS130 = 
dynamic_cast<vcl::filter::PDFNameElement*>(pObject130->Lookup("S"));
+    CPPUNIT_ASSERT_EQUAL(OString("Link"), pS130->GetValue());
+
+    {
+        auto pKids = 
dynamic_cast<vcl::filter::PDFArrayElement*>(pObject130->Lookup("K"));
+        auto nMCID(0);
+        auto nRef(0);
+        for (size_t i = 0; i < pKids->GetElements().size(); ++i)
+        {
+            auto pNum = 
dynamic_cast<vcl::filter::PDFNumberElement*>(pKids->GetElement(i));
+            auto pRef = 
dynamic_cast<vcl::filter::PDFReferenceElement*>(pKids->GetElement(i));
+            if (pNum)
+            {
+                ++nMCID;
+            }
+            if (pRef)
+            {
+                ++nRef;
+                auto pObjR = pRef->LookupObject();
+                auto pOType = 
dynamic_cast<vcl::filter::PDFNameElement*>(pObjR->Lookup("Type"));
+                CPPUNIT_ASSERT_EQUAL(OString("OBJR"), pOType->GetValue());
+                auto pAnnotRef
+                    = 
dynamic_cast<vcl::filter::PDFReferenceElement*>(pObjR->Lookup("Obj"));
+                auto pAnnot = pAnnotRef->LookupObject();
+                auto pAType = 
dynamic_cast<vcl::filter::PDFNameElement*>(pAnnot->Lookup("Type"));
+                CPPUNIT_ASSERT_EQUAL(OString("Annot"), pAType->GetValue());
+                auto pASubtype
+                    = 
dynamic_cast<vcl::filter::PDFNameElement*>(pAnnot->Lookup("Subtype"));
+                CPPUNIT_ASSERT_EQUAL(OString("Link"), pASubtype->GetValue());
+                auto pAContents
+                    = 
dynamic_cast<vcl::filter::PDFHexStringElement*>(pAnnot->Lookup("Contents"));
+                CPPUNIT_ASSERT_EQUAL(
+                    
u"https://de.wikipedia.org/wiki/Kläranlage#Mechanische_Vorreinigung"_ustr,
+                    
::vcl::filter::PDFDocument::DecodeHexStringUTF16BE(*pAContents));
+                CPPUNIT_ASSERT_EQUAL(OString("Link"), pASubtype->GetValue());
+                auto pAA = 
dynamic_cast<vcl::filter::PDFDictionaryElement*>(pAnnot->Lookup("A"));
+                CPPUNIT_ASSERT(pAA);
+                auto pAAType
+                    = 
dynamic_cast<vcl::filter::PDFNameElement*>(pAA->LookupElement("Type"));
+                CPPUNIT_ASSERT_EQUAL(OString("Action"), pAAType->GetValue());
+                auto pAAS = 
dynamic_cast<vcl::filter::PDFNameElement*>(pAA->LookupElement("S"));
+                CPPUNIT_ASSERT_EQUAL(OString("URI"), pAAS->GetValue());
+                auto pAAURI = 
dynamic_cast<vcl::filter::PDFLiteralStringElement*>(
+                    pAA->LookupElement("URI"));
+                CPPUNIT_ASSERT_EQUAL(
+                    OString(
+                        
"https://de.wikipedia.org/wiki/Kl%C3%A4ranlage#Mechanische_Vorreinigung";),
+                    pAAURI->GetValue());
+            }
+        }
+        CPPUNIT_ASSERT_EQUAL(static_cast<decltype(nMCID)>(1), nMCID);
+        CPPUNIT_ASSERT_EQUAL(static_cast<decltype(nRef)>(1), nRef);
+    }
+
+    auto pRefKid14 = 
dynamic_cast<vcl::filter::PDFReferenceElement*>(pKids1v[4]);
+    CPPUNIT_ASSERT(pRefKid14);
+    auto pObject14 = pRefKid14->LookupObject();
+    CPPUNIT_ASSERT(pObject14);
+    auto pType14 = 
dynamic_cast<vcl::filter::PDFNameElement*>(pObject14->Lookup("Type"));
+    CPPUNIT_ASSERT_EQUAL(OString("StructElem"), pType14->GetValue());
+    auto pS14 = 
dynamic_cast<vcl::filter::PDFNameElement*>(pObject14->Lookup("S"));
+    CPPUNIT_ASSERT_EQUAL(OString("Text#20body"), pS14->GetValue());
+
+    auto pKids14 = 
dynamic_cast<vcl::filter::PDFArrayElement*>(pObject14->Lookup("K"));
+    CPPUNIT_ASSERT(pKids14);
+    // assume there are no MCID ref at this level
+    auto pKids14v = pKids14->GetElements();
+    auto pRefKid140 = 
dynamic_cast<vcl::filter::PDFReferenceElement*>(pKids14v[0]);
+    CPPUNIT_ASSERT(pRefKid140);
+    auto pObject140 = pRefKid140->LookupObject();
+    CPPUNIT_ASSERT(pObject140);
+    auto pType140 = 
dynamic_cast<vcl::filter::PDFNameElement*>(pObject140->Lookup("Type"));
+    CPPUNIT_ASSERT_EQUAL(OString("StructElem"), pType140->GetValue());
+    auto pS140 = 
dynamic_cast<vcl::filter::PDFNameElement*>(pObject140->Lookup("S"));
+    CPPUNIT_ASSERT_EQUAL(OString("Link"), pS140->GetValue());
+
+    {
+        auto pKids = 
dynamic_cast<vcl::filter::PDFArrayElement*>(pObject140->Lookup("K"));
+        auto nMCID(0);
+        auto nRef(0);
+        for (size_t i = 0; i < pKids->GetElements().size(); ++i)
+        {
+            auto pNum = 
dynamic_cast<vcl::filter::PDFNumberElement*>(pKids->GetElement(i));
+            auto pRef = 
dynamic_cast<vcl::filter::PDFReferenceElement*>(pKids->GetElement(i));
+            if (pNum)
+            {
+                ++nMCID;
+            }
+            if (pRef)
+            {
+                ++nRef;
+                auto pObjR = pRef->LookupObject();
+                auto pOType = 
dynamic_cast<vcl::filter::PDFNameElement*>(pObjR->Lookup("Type"));
+                CPPUNIT_ASSERT_EQUAL(OString("OBJR"), pOType->GetValue());
+                auto pAnnotRef
+                    = 
dynamic_cast<vcl::filter::PDFReferenceElement*>(pObjR->Lookup("Obj"));
+                auto pAnnot = pAnnotRef->LookupObject();
+                auto pAType = 
dynamic_cast<vcl::filter::PDFNameElement*>(pAnnot->Lookup("Type"));
+                CPPUNIT_ASSERT_EQUAL(OString("Annot"), pAType->GetValue());
+                auto pASubtype
+                    = 
dynamic_cast<vcl::filter::PDFNameElement*>(pAnnot->Lookup("Subtype"));
+                CPPUNIT_ASSERT_EQUAL(OString("Link"), pASubtype->GetValue());
+                auto pAContents
+                    = 
dynamic_cast<vcl::filter::PDFHexStringElement*>(pAnnot->Lookup("Contents"));
+                CPPUNIT_ASSERT_EQUAL(
+                    
u"https://vr-easy.com/tour/usr/220113-virtuellerschulausflug/#pano=24"_ustr,
+                    
::vcl::filter::PDFDocument::DecodeHexStringUTF16BE(*pAContents));
+                CPPUNIT_ASSERT_EQUAL(OString("Link"), pASubtype->GetValue());
+                auto pAA = 
dynamic_cast<vcl::filter::PDFDictionaryElement*>(pAnnot->Lookup("A"));
+                CPPUNIT_ASSERT(pAA);
+                auto pAAType
+                    = 
dynamic_cast<vcl::filter::PDFNameElement*>(pAA->LookupElement("Type"));
+                CPPUNIT_ASSERT_EQUAL(OString("Action"), pAAType->GetValue());
+                auto pAAS = 
dynamic_cast<vcl::filter::PDFNameElement*>(pAA->LookupElement("S"));
+                CPPUNIT_ASSERT_EQUAL(OString("URI"), pAAS->GetValue());
+                auto pAAURI = 
dynamic_cast<vcl::filter::PDFLiteralStringElement*>(
+                    pAA->LookupElement("URI"));
+                CPPUNIT_ASSERT_EQUAL(
+                    
OString("https://vr-easy.com/tour/usr/220113-virtuellerschulausflug/#pano=24";),
+                    pAAURI->GetValue());
+            }
+        }
+        CPPUNIT_ASSERT_EQUAL(static_cast<decltype(nMCID)>(1), nMCID);
+        CPPUNIT_ASSERT_EQUAL(static_cast<decltype(nRef)>(1), nRef);
+    }
+}
+
 CPPUNIT_TEST_FIXTURE(PdfExportTest, testTdf135192)
 {
     aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export");
diff --git a/vcl/source/gdi/pdfextoutdevdata.cxx 
b/vcl/source/gdi/pdfextoutdevdata.cxx
index a4184c8cefa7..8bc7e044002e 100644
--- a/vcl/source/gdi/pdfextoutdevdata.cxx
+++ b/vcl/source/gdi/pdfextoutdevdata.cxx
@@ -42,6 +42,7 @@ struct PDFExtOutDevDataSync
 {
     enum Action{    CreateNamedDest,
                     CreateDest,
+                    CreateControlLink,
                     CreateLink,
                     CreateScreen,
                     SetLinkDest,
@@ -95,6 +96,7 @@ struct GlobalSyncData
     std::deque< PDFNote >                       mParaPDFNotes;
     std::deque< PDFWriter::PageTransition >     mParaPageTransitions;
     ::std::map< sal_Int32, PDFLinkDestination > mFutureDestinations;
+    ::std::deque<sal_Int32>                     mControlIds;
 
     sal_Int32 GetMappedId();
 
@@ -169,6 +171,14 @@ void GlobalSyncData::PlayGlobalActions( PDFWriter& rWriter 
)
                 rWriter.Pop();
             }
             break;
+            case PDFExtOutDevDataSync::CreateControlLink:
+            {
+                // tdf#157397: this must be called *in order* with CreateLink 
etc.
+                rWriter.SetLinkPropertyID(mControlIds.front(), 
sal_Int32(mParaIds.size()));
+                mParaIds.push_back(mControlIds.front());
+                mControlIds.pop_front();
+            }
+            break;
             case PDFExtOutDevDataSync::CreateLink :
             {
                 rWriter.Push( PushFlags::MAPMODE );
@@ -426,10 +436,12 @@ bool PageSyncData::PlaySyncPageAct( PDFWriter& rWriter, 
sal_uInt32& rCurGDIMtfAc
                 {
                     sal_Int32 const n = rWriter.CreateControl(*pControl);
                     // resolve AnnotIds structural attribute
-                    ::std::vector<sal_Int32> const annotIds{ 
sal_Int32(mpGlobalData->mParaIds.size()) };
+                    ::std::vector<sal_Int32> const annotIds{ 
sal_Int32(mpGlobalData->mCurId) };
                     rWriter.SetStructureAnnotIds(annotIds);
-                    rWriter.SetLinkPropertyID(n, 
sal_Int32(mpGlobalData->mParaIds.size()));
-                    mpGlobalData->mParaIds.push_back(n);
+                    // tdf#157397: this must be called *in order* with 
CreateLink etc.
+                    
mpGlobalData->mActions.push_back(PDFExtOutDevDataSync::CreateControlLink);
+                    mpGlobalData->mControlIds.push_back(n);
+                    mpGlobalData->mCurId++;
                 }
                 mControls.pop_front();
             }
@@ -534,6 +546,7 @@ bool PageSyncData::PlaySyncPageAct( PDFWriter& rWriter, 
sal_uInt32& rCurGDIMtfAc
             break;
             case PDFExtOutDevDataSync::CreateNamedDest:
             case PDFExtOutDevDataSync::CreateDest:
+            case PDFExtOutDevDataSync::CreateControlLink:
             case PDFExtOutDevDataSync::CreateLink:
             case PDFExtOutDevDataSync::CreateScreen:
             case PDFExtOutDevDataSync::SetLinkDest:
@@ -926,7 +939,6 @@ void PDFExtOutDevData::CreateControl( const 
PDFWriter::AnyWidget& rControlType )
 
     std::shared_ptr< PDFWriter::AnyWidget > pClone( rControlType.Clone() );
     mpPageSyncData->mControls.push_back( pClone );
-    mpGlobalSyncData->mCurId++;
 }
 
 void PDFExtOutDevData::BeginGroup()

Reply via email to