sw/source/core/crsr/viscrs.cxx                  |    4 
 sw/source/core/inc/rootfrm.hxx                  |    4 
 sw/source/core/layout/trvlfrm.cxx               |   49 +++
 sw/source/core/text/EnhancedPDFExportHelper.cxx |   18 +
 vcl/qa/cppunit/pdfexport/data/LinkWithFly.fodt  |  137 +++++++++
 vcl/qa/cppunit/pdfexport/pdfexport.cxx          |  348 +++++++++++++++++++++++-
 6 files changed, 548 insertions(+), 12 deletions(-)

New commits:
commit 5726be1314517d47dd733aabe64a3d85cce094c5
Author:     Michael Stahl <michael.st...@allotropia.de>
AuthorDate: Fri Oct 27 19:45:09 2023 +0200
Commit:     Michael Stahl <michael.st...@allotropia.de>
CommitDate: Thu Nov 2 10:47:20 2023 +0100

    tdf#157816 sw: PDF export: filter out links on empty space, INetAttrs
    
    Several problems here:
    * As with fields, there may be selection rectangles with no text
    * SwRootFrame::CalcFrameRects() adds flys that are anchored in the
      selection to the selection
    * A fly text portion causes Link annotations to split, but not Link SE
    * If a fly only partially overlaps a line vertically, then
      CalcFrameRects() produces a full-width half-height rectangle and
      another 2 half-width half-height rectangles on both sides.
      This is useless, the rectangles must be full line height.
      Add some code in CalcFrameRects() to use the fly portions in the
      SwParaPortion instead of the fly frame areas.
    
    Change-Id: I93f0c12a5e5a3d5f51fcc4b33052a112e9174863
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/158576
    Tested-by: Michael Stahl <michael.st...@allotropia.de>
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>

diff --git a/sw/source/core/crsr/viscrs.cxx b/sw/source/core/crsr/viscrs.cxx
index da9c043c6581..f681f3a32815 100644
--- a/sw/source/core/crsr/viscrs.cxx
+++ b/sw/source/core/crsr/viscrs.cxx
@@ -954,7 +954,9 @@ void SwShellCursor::FillRects()
         (GetMark()->GetNode() == GetPoint()->GetNode() ||
         (GetMark()->GetNode().IsContentNode() &&
          GetMark()->GetNode().GetContentNode()->getLayoutFrame( 
GetShell()->GetLayout() ) )   ))
-        GetShell()->GetLayout()->CalcFrameRects( *this );
+    {
+        GetShell()->GetLayout()->CalcFrameRects(*this, *this);
+    }
 }
 
 void SwShellCursor::Show(SfxViewShell const * pViewShell)
diff --git a/sw/source/core/inc/rootfrm.hxx b/sw/source/core/inc/rootfrm.hxx
index 29f813360d82..90d18fcf0ee4 100644
--- a/sw/source/core/inc/rootfrm.hxx
+++ b/sw/source/core/inc/rootfrm.hxx
@@ -20,6 +20,7 @@
 #define INCLUDED_SW_SOURCE_CORE_INC_ROOTFRM_HXX
 
 #include "layfrm.hxx"
+#include <swregion.hxx>
 #include <viewsh.hxx>
 #include <doc.hxx>
 #include <IDocumentTimerAccess.hxx>
@@ -343,7 +344,8 @@ public:
     */
     bool IsBetweenPages(const Point& rPt) const;
 
-    void CalcFrameRects( SwShellCursor& );
+    enum class RectsMode { Default, NoAnchoredFlys };
+    void CalcFrameRects(SwShellCursor const&, SwRects &, RectsMode eMode = 
RectsMode::Default);
 
     /**
      * Calculates the cells included from the current selection
diff --git a/sw/source/core/layout/trvlfrm.cxx 
b/sw/source/core/layout/trvlfrm.cxx
index fab57c35c24b..d79ffab813aa 100644
--- a/sw/source/core/layout/trvlfrm.cxx
+++ b/sw/source/core/layout/trvlfrm.cxx
@@ -47,6 +47,8 @@
 #include <fldbas.hxx>
 #include <frmatr.hxx>
 #include <frmtool.hxx>
+#include "../text/inftxt.hxx"
+#include "../text/itrpaint.hxx"
 #include <ndtxt.hxx>
 #include <undobj.hxx>
 
@@ -2016,7 +2018,7 @@ static void Add( SwRegionRects& rRegion, const SwRect& 
rRect )
  *              rectangles are available for highlighting.
  *              In the end the Flys are cut out of the region.
  */
-void SwRootFrame::CalcFrameRects(SwShellCursor &rCursor)
+void SwRootFrame::CalcFrameRects(SwShellCursor const& rCursor, SwRects & 
rRects, RectsMode const eMode)
 {
     auto [pStartPos, pEndPos] = rCursor.StartEnd(); // SwPosition*
 
@@ -2570,7 +2572,46 @@ void SwRootFrame::CalcFrameRects(SwShellCursor &rCursor)
     const SwPageFrame *pPage      = pStartFrame->FindPageFrame();
     const SwPageFrame *pEndPage   = pEndFrame->FindPageFrame();
 
-    while ( pPage )
+    // for link rectangles: just remove all the fly portions - this prevents
+    // splitting of portions vertically (causes spurious extra PDF annotations)
+    if (eMode == RectsMode::NoAnchoredFlys)
+    {
+        assert(pStartFrame == pEndFrame); // link or field all in 1 frame
+        assert(pStartFrame->IsTextFrame());
+        SwTextGridItem const*const 
pGrid(GetGridItem(pStartFrame->FindPageFrame()));
+        SwTextPaintInfo info(static_cast<SwTextFrame*>(pStartFrame), 
pStartFrame->FindPageFrame()->getFrameArea());
+        SwTextPainter painter(static_cast<SwTextFrame*>(pStartFrame), &info);
+        // because nothing outside the start/end has been added, it doesn't
+        // matter to match exactly the start/end, subtracting outside is no-op
+        
painter.CharToLine(static_cast<SwTextFrame*>(pStartFrame)->MapModelToViewPos(*pStartPos));
+        do
+        {
+            info.SetPos(painter.GetTopLeft());
+            bool const bAdjustBaseLine(
+                
painter.GetLineInfo().HasSpecialAlign(pStartFrame->IsVertical())
+                || nullptr != pGrid || 
painter.GetCurr()->GetHangingBaseline());
+            SwTwips nAscent, nHeight;
+            painter.CalcAscentAndHeight(nAscent, nHeight);
+            SwTwips const nOldY(info.Y());
+            for (SwLinePortion const* pLP = 
painter.GetCurr()->GetFirstPortion();
+                    pLP; pLP = pLP->GetNextPortion())
+            {
+                if (pLP->IsFlyPortion())
+                {
+                    info.Y(info.Y() + (bAdjustBaseLine
+                            ? painter.AdjustBaseLine(*painter.GetCurr(), pLP)
+                            : nAscent));
+                    SwRect flyPortion;
+                    info.CalcRect(*pLP, &flyPortion);
+                    Sub(aRegion, flyPortion);
+                    info.Y(nOldY);
+                }
+                pLP->Move(info);
+            }
+        }
+        while (painter.Next());
+    }
+    else while (pPage)
     {
         if ( pPage->GetSortedObjs() )
         {
@@ -2590,7 +2631,7 @@ void SwRootFrame::CalcFrameRects(SwShellCursor &rCursor)
                                 && IsDestroyFrameAnchoredAtChar(*anchoredAt, 
*pStartPos, *pEndPos))
                             || (rAnchor.GetAnchorId() == RndStdIds::FLY_AT_PARA
                                 && IsSelectFrameAnchoredAtPara(*anchoredAt, 
*pStartPos, *pEndPos))));
-                if( inSelection )
+                if (eMode != RectsMode::NoAnchoredFlys && inSelection)
                         Add( aRegion, pFly->getFrameArea() );
                 else if ( !pFly->IsAnLower( pStartFrame ) &&
                     (rSur.GetSurround() != css::text::WrapTextMode_THROUGH &&
@@ -2642,7 +2683,7 @@ void SwRootFrame::CalcFrameRects(SwShellCursor &rCursor)
             Sub( aRegion, aDropRect );
     }
 
-    rCursor.assign( aRegion.begin(), aRegion.end() );
+    rRects.assign( aRegion.begin(), aRegion.end() );
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/text/EnhancedPDFExportHelper.cxx 
b/sw/source/core/text/EnhancedPDFExportHelper.cxx
index 946def82f719..e224d33901a4 100644
--- a/sw/source/core/text/EnhancedPDFExportHelper.cxx
+++ b/sw/source/core/text/EnhancedPDFExportHelper.cxx
@@ -349,7 +349,9 @@ bool lcl_TryMoveToNonHiddenField(SwEditShell& rShell, const 
SwTextNode& rNd, con
 ::std::vector<SwRect> GetCursorRectsContainingText(SwCursorShell const& rShell)
 {
     ::std::vector<SwRect> ret;
-    for (SwRect const& rRect : *rShell.GetCursor_())
+    SwRects rects;
+    rShell.GetLayout()->CalcFrameRects(*rShell.GetCursor_(), rects, 
SwRootFrame::RectsMode::NoAnchoredFlys);
+    for (SwRect const& rRect : rects)
     {
         Point center(rRect.Center());
         SwSpecialPos special;
@@ -1824,6 +1826,17 @@ void SwTaggedPDFHelper::BeginInlineStructureElements()
             aPDFType = aSpanString;
             break;
 
+        case PortionType::Fly:
+            // if a link is split by a fly overlap, then there will be multiple
+            // annotations for the link, and hence there must be multiple SEs,
+            // so every annotation has its own SE.
+            if (mpPDFExtOutDevData->GetSwPDFState()->m_oCurrentLink)
+            {
+                mpPDFExtOutDevData->GetSwPDFState()->m_oCurrentLink.reset();
+                EndTag();
+            }
+            break;
+
         case PortionType::Lay :
         case PortionType::Text :
         case PortionType::Para :
@@ -2193,8 +2206,7 @@ void 
SwEnhancedPDFExportHelper::EnhancedPDFExport(LanguageType const eLanguageDe
                     // selection can be easily obtained:
                     // Note: We make a copy of the rectangles, because they may
                     // be deleted again in JumpToSwMark.
-                    SwRects aTmp;
-                    aTmp.insert( aTmp.begin(), 
mrSh.SwCursorShell::GetCursor_()->begin(), 
mrSh.SwCursorShell::GetCursor_()->end() );
+                    SwRects const aTmp(GetCursorRectsContainingText(mrSh));
                     OSL_ENSURE( !aTmp.empty(), "Enhanced pdf export - 
rectangles are missing" );
                     OUString const altText(mrSh.GetSelText());
 
diff --git a/vcl/qa/cppunit/pdfexport/data/LinkWithFly.fodt 
b/vcl/qa/cppunit/pdfexport/data/LinkWithFly.fodt
new file mode 100644
index 000000000000..5c14cee1f28c
--- /dev/null
+++ b/vcl/qa/cppunit/pdfexport/data/LinkWithFly.fodt
@@ -0,0 +1,137 @@
+<?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:creation-date>2023-10-25T14:48:54.649558008</meta:creation-date><dc:title>test</dc:title><meta:print-date>2023-10-25T14:49:57.194410546</meta:print-date><meta:printed-by>PDF
 
files</meta:printed-by><dc:date>2023-10-25T14:54:03.818423519</dc:date><meta:editing-duration>PT4M6S</meta:editing-duration><meta:editing-cycles>2</meta:editing-cycles><meta:generator>LibreOfficeDev/24.2.0.0.alpha0$Linux_X86_64
 
LibreOffice_project/70bf29987ceb90cd3988fc2dfc4cad2a0163fe17</meta:generator><meta:document-statistic
 meta:table-count="0" meta:image-count="1" meta:object-count="0" 
meta:page-count="1" meta:paragraph-count="2" meta:word-count="2" 
meta:character-count="114" 
meta:non-whitespace-character-count="114"/></office:meta>
+ <office:font-face-decls>
+  <style:font-face style:name="Liberation Serif" svg:font-family="'Liberation 
Serif'" style:font-family-generic="roman" style:font-pitch="variable"/>
+  <style:font-face style:name="Noto Sans CJK SC" svg:font-family="'Noto Sans 
CJK SC'" style:font-family-generic="system" style:font-pitch="variable"/>
+  <style:font-face style:name="Noto Sans1" svg:font-family="'Noto Sans'" 
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:writing-mode="lr-tb" 
style:flow-with-text="false"/>
+   <style:paragraph-properties style:text-autospace="ideograph-alpha" 
style:line-break="strict" loext:tab-stop-distance="0cm" 
style:font-independent-line-spacing="false">
+    <style:tab-stops/>
+   </style:paragraph-properties>
+   <style:text-properties style:use-window-font-color="true" 
loext:opacity="0%" style:font-name="Liberation Serif" fo:font-size="12pt" 
fo:language="de" fo:country="DE" style:letter-kerning="true" 
style:font-name-asian="Noto Sans CJK SC" style:font-size-asian="10.5pt" 
style:language-asian="zh" style:country-asian="CN" 
style:font-name-complex="Noto Sans1" style:font-size-complex="12pt" 
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="1.251cm" style:writing-mode="page"/>
+   <style:text-properties style:use-window-font-color="true" 
loext:opacity="0%" style:font-name="Liberation Serif" fo:font-size="12pt" 
fo:language="de" fo:country="DE" style:letter-kerning="true" 
style:font-name-asian="Noto Sans CJK SC" style:font-size-asian="10.5pt" 
style:language-asian="zh" style:country-asian="CN" 
style:font-name-complex="Noto Sans1" style:font-size-complex="12pt" 
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="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:style style:name="Internet_20_link" style:display-name="Internet 
link" style:family="text">
+   <style:text-properties fo:color="#000080" 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="Graphics" style:family="graphic">
+   <style:graphic-properties text:anchor-type="paragraph" svg:x="0cm" 
svg:y="0cm" style:wrap="dynamic" style:number-wrapped-paragraphs="no-limit" 
style:wrap-contour="false" style:vertical-pos="top" 
style:vertical-rel="paragraph" style:horizontal-pos="center" 
style:horizontal-rel="paragraph" fo:background-color="transparent" 
draw:fill="none"/>
+  </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" 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"/>
+  </office:styles>
+ <office:automatic-styles>
+  <style:style style:name="P1" style:family="paragraph" 
style:parent-style-name="Standard">
+   <style:text-properties/>
+  </style:style>
+  <style:style style:name="fr1" style:family="graphic" 
style:parent-style-name="Graphics">
+   <style:graphic-properties style:run-through="foreground" 
style:wrap="parallel" style:number-wrapped-paragraphs="no-limit" 
style:wrap-contour="false" style:vertical-pos="from-top" 
style:vertical-rel="paragraph" style:horizontal-pos="from-left" 
style:horizontal-rel="paragraph" style:mirror="none" fo:clip="rect(0cm, 0cm, 
0cm, 0cm)" draw:luminance="0%" draw:contrast="0%" draw:red="0%" draw:green="0%" 
draw:blue="0%" draw:gamma="100%" draw:color-inversion="false" 
draw:image-opacity="100%" draw:color-mode="standard"/>
+  </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="2cm" fo:margin-bottom="2cm" fo:margin-left="2cm" 
fo:margin-right="2cm" style:writing-mode="lr-tb" 
style:layout-grid-color="#c0c0c0" style:layout-grid-lines="20" 
style:layout-grid-base-height="0.706cm" style:layout-grid-ruby-height="0.353cm" 
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="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"><text:a xlink:type="simple" 
xlink:href="https://www.mozilla.org/en-US/firefox/119.0/releasenotes/"; 
text:style-name="Internet_20_link" 
text:visited-style-name="Visited_20_Internet_20_Link">https://www.mozilla.org/en-US<draw:frame
 draw:style-name="fr1" draw:name="Image1" text:anchor-type="char" 
svg:x="5.318cm" svg:y="0.056cm" svg:width="6.364cm" svg:height="6.364cm" 
draw:z-index="0"><draw:image draw:mime-type="image/png">
+       
<office:binary-data>iVBORw0KGgoAAAANSUhEUgAAABMAAAATCAYAAAByUDbMAAAABGdBTUEAANbY1E9YMgAAABl0
+        
RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAFpSURBVHjaYvz//z8DtQBAADER
+        
o+jjZGuibAQIICZiDOK/cgzFwEnrV/4HYXS1AAHERIxBR58yMiAb2DtzM1b1AAHERIxBIIBu
+        
IDYAEEBMxBjE0bgdxcBL3vcZLl16jaEPIICYiDFIU9MSw8BeoeUYhgEEEBMxBnFx8WE1EN3L
+        
AAHERIxBIECMgQABxAhKtPgM+vbtE9xmGP/69eMMP+o9wWLW0kD9OlYM/LlHGQECiAndoKg/
+        
USgGgTTmdS8C0yA+zIUgdeguBAggljtWdQwMVkDXACWMjd0ZXRun/Id5DWTA9C23GSaVxoEN
+        
zISoARvoamnBYF2/hPHs2Z3/z0JdDhBADCBvIuPkhsn/QeDr14//QWwQjY0PVYeiFyCA8OaA
+        
3cdPoEQAiI8PAAQQEwMVAUAAsWATBAX0jx9fsWrAJQ4CAAGE1TBQwOMC9+9fwikHEEBYDQPF
+        IAzIe8TglEMHAAHESM2SFiDAADEwCe4BJwcYAAAAAElFTkSuQmCC
+       </office:binary-data>
+      </draw:image>
+      <svg:title>house</svg:title>
+     </draw:frame>/firefox/119.0/releasenotes/</text:a></text:p>
+   <text:p text:style-name="P1"><text:a xlink:type="simple" 
xlink:href="https://www.mozilla.org/en-US/firefox/118.0/releasenotes/"; 
text:style-name="Internet_20_link" 
text:visited-style-name="Visited_20_Internet_20_Link">https://www.mozilla.org/en-US/firefox/118.0/releasenotes/</text:a></text:p>
+  </office:text>
+ </office:body>
+</office:document>
diff --git a/vcl/qa/cppunit/pdfexport/pdfexport.cxx 
b/vcl/qa/cppunit/pdfexport/pdfexport.cxx
index 0849248dce2a..9db3cf63f187 100644
--- a/vcl/qa/cppunit/pdfexport/pdfexport.cxx
+++ b/vcl/qa/cppunit/pdfexport/pdfexport.cxx
@@ -2103,7 +2103,8 @@ CPPUNIT_TEST_FIXTURE(PdfExportTest, testTdf157816)
                 CPPUNIT_ASSERT_DOUBLES_EQUAL(674.589, pNumT->GetValue(), 1e-3);
                 const auto* pNumR = 
dynamic_cast<vcl::filter::PDFNumberElement*>(rElements[2]);
                 CPPUNIT_ASSERT(pNumR);
-                CPPUNIT_ASSERT_DOUBLES_EQUAL(202.457, pNumR->GetValue(), 1e-3);
+                // this changed to the end of the text, not the start of the 
fly
+                CPPUNIT_ASSERT_DOUBLES_EQUAL(187.207, pNumR->GetValue(), 1e-3);
                 const auto* pNumB = 
dynamic_cast<vcl::filter::PDFNumberElement*>(rElements[3]);
                 CPPUNIT_ASSERT(pNumB);
                 CPPUNIT_ASSERT_DOUBLES_EQUAL(688.389, pNumB->GetValue(), 1e-3);
@@ -2231,7 +2232,7 @@ CPPUNIT_TEST_FIXTURE(PdfExportTest, testTdf157816)
                 CPPUNIT_ASSERT_DOUBLES_EQUAL(660.789, pNumT->GetValue(), 1e-3);
                 const auto* pNumR = 
dynamic_cast<vcl::filter::PDFNumberElement*>(rElements[2]);
                 CPPUNIT_ASSERT(pNumR);
-                CPPUNIT_ASSERT_DOUBLES_EQUAL(202.457, pNumR->GetValue(), 1e-3);
+                CPPUNIT_ASSERT_DOUBLES_EQUAL(179.457, pNumR->GetValue(), 1e-3);
                 const auto* pNumB = 
dynamic_cast<vcl::filter::PDFNumberElement*>(rElements[3]);
                 CPPUNIT_ASSERT(pNumB);
                 CPPUNIT_ASSERT_DOUBLES_EQUAL(674.589, pNumB->GetValue(), 1e-3);
@@ -2295,7 +2296,7 @@ CPPUNIT_TEST_FIXTURE(PdfExportTest, testTdf157816)
                 CPPUNIT_ASSERT_DOUBLES_EQUAL(646.989, pNumT->GetValue(), 1e-3);
                 const auto* pNumR = 
dynamic_cast<vcl::filter::PDFNumberElement*>(rElements[2]);
                 CPPUNIT_ASSERT(pNumR);
-                CPPUNIT_ASSERT_DOUBLES_EQUAL(202.457, pNumR->GetValue(), 1e-3);
+                CPPUNIT_ASSERT_DOUBLES_EQUAL(174.757, pNumR->GetValue(), 1e-3);
                 const auto* pNumB = 
dynamic_cast<vcl::filter::PDFNumberElement*>(rElements[3]);
                 CPPUNIT_ASSERT(pNumB);
                 CPPUNIT_ASSERT_DOUBLES_EQUAL(660.789, pNumB->GetValue(), 1e-3);
@@ -2379,6 +2380,347 @@ CPPUNIT_TEST_FIXTURE(PdfExportTest, testTdf157816)
     CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(5), 
pAnnots->GetElements().size());
 }
 
+CPPUNIT_TEST_FIXTURE(PdfExportTest, testTdf157816Link)
+{
+    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"LinkWithFly.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 pKidsD = 
dynamic_cast<vcl::filter::PDFArrayElement*>(pDocument->Lookup("K"));
+    CPPUNIT_ASSERT(pKidsD);
+    // assume there are no MCID ref at this level
+    auto pKidsDv = pKidsD->GetElements();
+    auto pRefKidD0 = 
dynamic_cast<vcl::filter::PDFReferenceElement*>(pKidsDv[0]);
+    CPPUNIT_ASSERT(pRefKidD0);
+    auto pObjectD0 = pRefKidD0->LookupObject();
+    CPPUNIT_ASSERT(pObjectD0);
+    auto pTypeD0 = 
dynamic_cast<vcl::filter::PDFNameElement*>(pObjectD0->Lookup("Type"));
+    CPPUNIT_ASSERT_EQUAL(OString("StructElem"), pTypeD0->GetValue());
+    auto pSD0 = 
dynamic_cast<vcl::filter::PDFNameElement*>(pObjectD0->Lookup("S"));
+    CPPUNIT_ASSERT_EQUAL(OString("Standard"), pSD0->GetValue());
+
+    auto pKidsD0 = 
dynamic_cast<vcl::filter::PDFArrayElement*>(pObjectD0->Lookup("K"));
+    CPPUNIT_ASSERT(pKidsD0);
+    auto pKidsD0v = pKidsD0->GetElements();
+
+    auto pRefKidD00 = 
dynamic_cast<vcl::filter::PDFReferenceElement*>(pKidsD0v[0]);
+    CPPUNIT_ASSERT(pRefKidD00);
+    auto pObjectD00 = pRefKidD00->LookupObject();
+    CPPUNIT_ASSERT(pObjectD00);
+    auto pTypeD00 = 
dynamic_cast<vcl::filter::PDFNameElement*>(pObjectD00->Lookup("Type"));
+    CPPUNIT_ASSERT_EQUAL(OString("StructElem"), pTypeD00->GetValue());
+    auto pSD00 = 
dynamic_cast<vcl::filter::PDFNameElement*>(pObjectD00->Lookup("S"));
+    CPPUNIT_ASSERT_EQUAL(OString("Link"), pSD00->GetValue());
+    {
+        auto pKids = 
dynamic_cast<vcl::filter::PDFArrayElement*>(pObjectD00->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://www.mozilla.org/en-US/firefox/119.0/releasenotes/"_ustr,
+                    
::vcl::filter::PDFDocument::DecodeHexStringUTF16BE(*pAContents));
+                auto pStructParent
+                    = 
dynamic_cast<vcl::filter::PDFNumberElement*>(pAnnot->Lookup("StructParent"));
+                CPPUNIT_ASSERT(pStructParent); // every link must have it!
+                auto pARect = 
dynamic_cast<vcl::filter::PDFArrayElement*>(pAnnot->Lookup("Rect"));
+                CPPUNIT_ASSERT(pARect);
+                const auto& rElements = pARect->GetElements();
+                CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(4), rElements.size());
+                const auto* pNumL = 
dynamic_cast<vcl::filter::PDFNumberElement*>(rElements[0]);
+                CPPUNIT_ASSERT(pNumL);
+                CPPUNIT_ASSERT_DOUBLES_EQUAL(56.693, pNumL->GetValue(), 1e-3);
+                const auto* pNumT = 
dynamic_cast<vcl::filter::PDFNumberElement*>(rElements[1]);
+                CPPUNIT_ASSERT(pNumT);
+                CPPUNIT_ASSERT_DOUBLES_EQUAL(771.389, pNumT->GetValue(), 1e-3);
+                const auto* pNumR = 
dynamic_cast<vcl::filter::PDFNumberElement*>(rElements[2]);
+                CPPUNIT_ASSERT(pNumR);
+                // this changed to the end of the text, not the start of the 
fly
+                CPPUNIT_ASSERT_DOUBLES_EQUAL(191.707, pNumR->GetValue(), 1e-3);
+                const auto* pNumB = 
dynamic_cast<vcl::filter::PDFNumberElement*>(rElements[3]);
+                CPPUNIT_ASSERT(pNumB);
+                CPPUNIT_ASSERT_DOUBLES_EQUAL(785.189, pNumB->GetValue(), 1e-3);
+            }
+        }
+        CPPUNIT_ASSERT_EQUAL(static_cast<decltype(nMCID)>(1), nMCID);
+        CPPUNIT_ASSERT_EQUAL(static_cast<decltype(nRef)>(1), nRef);
+    }
+
+    auto pRefKidD01 = 
dynamic_cast<vcl::filter::PDFReferenceElement*>(pKidsD0v[1]);
+    CPPUNIT_ASSERT(pRefKidD01);
+    auto pObjectD01 = pRefKidD01->LookupObject();
+    CPPUNIT_ASSERT(pObjectD01);
+    auto pTypeD01 = 
dynamic_cast<vcl::filter::PDFNameElement*>(pObjectD01->Lookup("Type"));
+    CPPUNIT_ASSERT_EQUAL(OString("StructElem"), pTypeD01->GetValue());
+    auto pSD01 = 
dynamic_cast<vcl::filter::PDFNameElement*>(pObjectD01->Lookup("S"));
+    CPPUNIT_ASSERT_EQUAL(OString("Link"), pSD01->GetValue());
+    {
+        auto pKids = 
dynamic_cast<vcl::filter::PDFArrayElement*>(pObjectD01->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://www.mozilla.org/en-US/firefox/119.0/releasenotes/"_ustr,
+                    
::vcl::filter::PDFDocument::DecodeHexStringUTF16BE(*pAContents));
+                auto pStructParent
+                    = 
dynamic_cast<vcl::filter::PDFNumberElement*>(pAnnot->Lookup("StructParent"));
+                CPPUNIT_ASSERT(pStructParent); // every link must have it!
+                auto pARect = 
dynamic_cast<vcl::filter::PDFArrayElement*>(pAnnot->Lookup("Rect"));
+                CPPUNIT_ASSERT(pARect);
+                const auto& rElements = pARect->GetElements();
+                CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(4), rElements.size());
+                const auto* pNumL = 
dynamic_cast<vcl::filter::PDFNumberElement*>(rElements[0]);
+                CPPUNIT_ASSERT(pNumL);
+                CPPUNIT_ASSERT_DOUBLES_EQUAL(387.843, pNumL->GetValue(), 1e-3);
+                const auto* pNumT = 
dynamic_cast<vcl::filter::PDFNumberElement*>(rElements[1]);
+                CPPUNIT_ASSERT(pNumT);
+                CPPUNIT_ASSERT_DOUBLES_EQUAL(771.389, pNumT->GetValue(), 1e-3);
+                const auto* pNumR = 
dynamic_cast<vcl::filter::PDFNumberElement*>(rElements[2]);
+                CPPUNIT_ASSERT(pNumR);
+                // this changed to the end of the text, not the start of the 
fly
+                CPPUNIT_ASSERT_DOUBLES_EQUAL(534.407, pNumR->GetValue(), 1e-3);
+                const auto* pNumB = 
dynamic_cast<vcl::filter::PDFNumberElement*>(rElements[3]);
+                CPPUNIT_ASSERT(pNumB);
+                CPPUNIT_ASSERT_DOUBLES_EQUAL(785.189, pNumB->GetValue(), 1e-3);
+            }
+        }
+        CPPUNIT_ASSERT_EQUAL(static_cast<decltype(nMCID)>(1), nMCID);
+        CPPUNIT_ASSERT_EQUAL(static_cast<decltype(nRef)>(1), nRef);
+    }
+
+    auto pRefKidD02 = 
dynamic_cast<vcl::filter::PDFReferenceElement*>(pKidsD0v[2]);
+    CPPUNIT_ASSERT(pRefKidD02);
+    auto pObjectD02 = pRefKidD02->LookupObject();
+    CPPUNIT_ASSERT(pObjectD02);
+    auto pTypeD02 = 
dynamic_cast<vcl::filter::PDFNameElement*>(pObjectD02->Lookup("Type"));
+    CPPUNIT_ASSERT_EQUAL(OString("StructElem"), pTypeD02->GetValue());
+    auto pSD02 = 
dynamic_cast<vcl::filter::PDFNameElement*>(pObjectD02->Lookup("S"));
+    CPPUNIT_ASSERT_EQUAL(OString("Figure"), pSD02->GetValue());
+
+    auto pRefKidD1 = 
dynamic_cast<vcl::filter::PDFReferenceElement*>(pKidsDv[1]);
+    CPPUNIT_ASSERT(pRefKidD1);
+    auto pObjectD1 = pRefKidD1->LookupObject();
+    CPPUNIT_ASSERT(pObjectD1);
+    auto pTypeD1 = 
dynamic_cast<vcl::filter::PDFNameElement*>(pObjectD1->Lookup("Type"));
+    CPPUNIT_ASSERT_EQUAL(OString("StructElem"), pTypeD1->GetValue());
+    auto pSD1 = 
dynamic_cast<vcl::filter::PDFNameElement*>(pObjectD1->Lookup("S"));
+    CPPUNIT_ASSERT_EQUAL(OString("Standard"), pSD1->GetValue());
+
+    auto pKidsD1 = 
dynamic_cast<vcl::filter::PDFArrayElement*>(pObjectD1->Lookup("K"));
+    CPPUNIT_ASSERT(pKidsD1);
+    auto pKidsD1v = pKidsD1->GetElements();
+
+    auto pRefKidD10 = 
dynamic_cast<vcl::filter::PDFReferenceElement*>(pKidsD1v[0]);
+    CPPUNIT_ASSERT(pRefKidD10);
+    auto pObjectD10 = pRefKidD10->LookupObject();
+    CPPUNIT_ASSERT(pObjectD10);
+    auto pTypeD10 = 
dynamic_cast<vcl::filter::PDFNameElement*>(pObjectD10->Lookup("Type"));
+    CPPUNIT_ASSERT_EQUAL(OString("StructElem"), pTypeD10->GetValue());
+    auto pSD10 = 
dynamic_cast<vcl::filter::PDFNameElement*>(pObjectD10->Lookup("S"));
+    CPPUNIT_ASSERT_EQUAL(OString("Link"), pSD10->GetValue());
+    {
+        auto pKids = 
dynamic_cast<vcl::filter::PDFArrayElement*>(pObjectD10->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://www.mozilla.org/en-US/firefox/118.0/releasenotes/"_ustr,
+                    
::vcl::filter::PDFDocument::DecodeHexStringUTF16BE(*pAContents));
+                auto pStructParent
+                    = 
dynamic_cast<vcl::filter::PDFNumberElement*>(pAnnot->Lookup("StructParent"));
+                CPPUNIT_ASSERT(pStructParent); // every link must have it!
+                auto pARect = 
dynamic_cast<vcl::filter::PDFArrayElement*>(pAnnot->Lookup("Rect"));
+                CPPUNIT_ASSERT(pARect);
+                const auto& rElements = pARect->GetElements();
+                CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(4), rElements.size());
+                const auto* pNumL = 
dynamic_cast<vcl::filter::PDFNumberElement*>(rElements[0]);
+                CPPUNIT_ASSERT(pNumL);
+                CPPUNIT_ASSERT_DOUBLES_EQUAL(56.693, pNumL->GetValue(), 1e-3);
+                const auto* pNumT = 
dynamic_cast<vcl::filter::PDFNumberElement*>(rElements[1]);
+                CPPUNIT_ASSERT(pNumT);
+                CPPUNIT_ASSERT_DOUBLES_EQUAL(757.589, pNumT->GetValue(), 1e-3);
+                const auto* pNumR = 
dynamic_cast<vcl::filter::PDFNumberElement*>(rElements[2]);
+                CPPUNIT_ASSERT(pNumR);
+                // this changed to the end of the text, not the start of the 
fly
+                CPPUNIT_ASSERT_DOUBLES_EQUAL(191.707, pNumR->GetValue(), 1e-3);
+                const auto* pNumB = 
dynamic_cast<vcl::filter::PDFNumberElement*>(rElements[3]);
+                CPPUNIT_ASSERT(pNumB);
+                CPPUNIT_ASSERT_DOUBLES_EQUAL(771.389, pNumB->GetValue(), 1e-3);
+            }
+        }
+        CPPUNIT_ASSERT_EQUAL(static_cast<decltype(nMCID)>(1), nMCID);
+        CPPUNIT_ASSERT_EQUAL(static_cast<decltype(nRef)>(1), nRef);
+    }
+
+    auto pRefKidD11 = 
dynamic_cast<vcl::filter::PDFReferenceElement*>(pKidsD1v[1]);
+    CPPUNIT_ASSERT(pRefKidD11);
+    auto pObjectD11 = pRefKidD11->LookupObject();
+    CPPUNIT_ASSERT(pObjectD11);
+    auto pTypeD11 = 
dynamic_cast<vcl::filter::PDFNameElement*>(pObjectD11->Lookup("Type"));
+    CPPUNIT_ASSERT_EQUAL(OString("StructElem"), pTypeD11->GetValue());
+    auto pSD11 = 
dynamic_cast<vcl::filter::PDFNameElement*>(pObjectD11->Lookup("S"));
+    CPPUNIT_ASSERT_EQUAL(OString("Link"), pSD11->GetValue());
+    {
+        auto pKids = 
dynamic_cast<vcl::filter::PDFArrayElement*>(pObjectD11->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://www.mozilla.org/en-US/firefox/118.0/releasenotes/"_ustr,
+                    
::vcl::filter::PDFDocument::DecodeHexStringUTF16BE(*pAContents));
+                auto pStructParent
+                    = 
dynamic_cast<vcl::filter::PDFNumberElement*>(pAnnot->Lookup("StructParent"));
+                CPPUNIT_ASSERT(pStructParent); // every link must have it!
+                auto pARect = 
dynamic_cast<vcl::filter::PDFArrayElement*>(pAnnot->Lookup("Rect"));
+                CPPUNIT_ASSERT(pARect);
+                const auto& rElements = pARect->GetElements();
+                CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(4), rElements.size());
+                const auto* pNumL = 
dynamic_cast<vcl::filter::PDFNumberElement*>(rElements[0]);
+                CPPUNIT_ASSERT(pNumL);
+                CPPUNIT_ASSERT_DOUBLES_EQUAL(387.843, pNumL->GetValue(), 1e-3);
+                const auto* pNumT = 
dynamic_cast<vcl::filter::PDFNumberElement*>(rElements[1]);
+                CPPUNIT_ASSERT(pNumT);
+                CPPUNIT_ASSERT_DOUBLES_EQUAL(757.589, pNumT->GetValue(), 1e-3);
+                const auto* pNumR = 
dynamic_cast<vcl::filter::PDFNumberElement*>(rElements[2]);
+                CPPUNIT_ASSERT(pNumR);
+                // this changed to the end of the text, not the start of the 
fly
+                CPPUNIT_ASSERT_DOUBLES_EQUAL(534.407, pNumR->GetValue(), 1e-3);
+                const auto* pNumB = 
dynamic_cast<vcl::filter::PDFNumberElement*>(rElements[3]);
+                CPPUNIT_ASSERT(pNumB);
+                CPPUNIT_ASSERT_DOUBLES_EQUAL(771.389, pNumB->GetValue(), 1e-3);
+            }
+        }
+        CPPUNIT_ASSERT_EQUAL(static_cast<decltype(nMCID)>(1), nMCID);
+        CPPUNIT_ASSERT_EQUAL(static_cast<decltype(nRef)>(1), nRef);
+    }
+
+    // the problem was that in addition to the 4 links with SE there was 1 more
+    auto pAnnots = 
dynamic_cast<vcl::filter::PDFArrayElement*>(aPages[0]->Lookup("Annots"));
+    CPPUNIT_ASSERT(pAnnots);
+    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(4), 
pAnnots->GetElements().size());
+}
+
 CPPUNIT_TEST_FIXTURE(PdfExportTest, testTdf115967)
 {
     aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export");

Reply via email to