drawinglayer/source/primitive2d/structuretagprimitive2d.cxx  |    4 
 drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx   |   27 +--
 include/drawinglayer/primitive2d/structuretagprimitive2d.hxx |    6 
 include/svx/svdobj.hxx                                       |    2 
 svx/source/sdr/contact/viewobjectcontact.cxx                 |    6 
 svx/source/svdraw/svdobj.cxx                                 |    4 
 sw/inc/EnhancedPDFExportHelper.hxx                           |    6 
 sw/inc/dcontact.hxx                                          |    2 
 sw/source/core/text/EnhancedPDFExportHelper.cxx              |   86 +++++------
 vcl/inc/pdf/pdfwriter_impl.hxx                               |    2 
 vcl/qa/cppunit/pdfexport/data/tdf154982.odt                  |binary
 vcl/qa/cppunit/pdfexport/pdfexport.cxx                       |   83 ++++++++++
 vcl/source/gdi/pdfwriter_impl.cxx                            |    5 
 13 files changed, 152 insertions(+), 81 deletions(-)

New commits:
commit 30bb38b041a44f6c30fcf0475b3cf2432dc7f5cb
Author:     Michael Stahl <michael.st...@allotropia.de>
AuthorDate: Wed Jul 12 18:34:24 2023 +0200
Commit:     خالد حسني <kha...@libreoffice.org>
CommitDate: Wed Jul 26 14:40:24 2023 +0200

    tdf#154982 drawinglayer,svx,sw,vcl: PDF export: hell flys and shapes...
    
    ... should be below their anchor paragraph in the structure tree.
    
    Refactor SwEnhancedPDFExportHelper (etc.) to use the new
    EnsureStructureElement()/InitStructureElement() functions instead of
    SetCurrentStructureElement() for the frames, and allow it for flys that
    don't have their anchor paragraphs created yet because the hell layer is
    exported before the document body.
    
    Change-Id: I1be3b54002e8196772e6f9d81dd0fd0c85b6e34b
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/154399
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>
    (cherry picked from commit d467f1aa3d028f399826c97e2eecedcd79efcf65)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/154427
    Reviewed-by: خالد حسني <kha...@libreoffice.org>

diff --git a/drawinglayer/source/primitive2d/structuretagprimitive2d.cxx 
b/drawinglayer/source/primitive2d/structuretagprimitive2d.cxx
index 62da91ecc00f..47af55ab9b57 100644
--- a/drawinglayer/source/primitive2d/structuretagprimitive2d.cxx
+++ b/drawinglayer/source/primitive2d/structuretagprimitive2d.cxx
@@ -31,13 +31,13 @@ namespace drawinglayer::primitive2d
             bool bBackground,
             bool bIsImage,
             Primitive2DContainer&& aChildren,
-            sal_Int32 const nAnchorStructureElementId,
+            void const*const pAnchorStructureElementKey,
             ::std::vector<sal_Int32> const*const pAnnotIds)
         :   GroupPrimitive2D(std::move(aChildren)),
             maStructureElement(rStructureElement),
             mbBackground(bBackground),
             mbIsImage(bIsImage)
-        ,   m_nAnchorStructureElementId(nAnchorStructureElementId)
+        ,   m_pAnchorStructureElementKey(pAnchorStructureElementKey)
         {
             if (pAnnotIds)
             {
diff --git a/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx 
b/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx
index 5e7b5523bad9..7f25b44e1761 100644
--- a/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx
+++ b/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx
@@ -2520,7 +2520,7 @@ void 
VclMetafileProcessor2D::processStructureTagPrimitive2D(
     // structured tag primitive
     const vcl::PDFWriter::StructElement& 
rTagElement(rStructureTagCandidate.getStructureElement());
     bool bTagUsed((vcl::PDFWriter::NonStructElement != rTagElement));
-    sal_Int32 nPreviousElement(-1);
+    bool bNeedEndAnchor(false);
 
     if (!rStructureTagCandidate.isTaggedSdrObject())
     {
@@ -2532,19 +2532,12 @@ void 
VclMetafileProcessor2D::processStructureTagPrimitive2D(
         // foreground object: tag as regular structure element
         if (!rStructureTagCandidate.isBackground())
         {
-            if (rStructureTagCandidate.GetAnchorStructureElementId() != -1)
+            if (rStructureTagCandidate.GetAnchorStructureElementKey() != 
nullptr)
             {
-                auto const nTemp = 
mpPDFExtOutDevData->GetCurrentStructureElement();
-                bool const bSuccess = 
mpPDFExtOutDevData->SetCurrentStructureElement(
-                    rStructureTagCandidate.GetAnchorStructureElementId());
-                if (bSuccess)
-                {
-                    nPreviousElement = nTemp;
-                }
-                else
-                {
-                    SAL_WARN("drawinglayer", "anchor structure element not 
found?");
-                }
+                sal_Int32 const id = 
mpPDFExtOutDevData->EnsureStructureElement(
+                    rStructureTagCandidate.GetAnchorStructureElementKey());
+                mpPDFExtOutDevData->BeginStructureElement(id);
+                bNeedEndAnchor = true;
             }
             mpPDFExtOutDevData->WrapBeginStructureElement(rTagElement);
             switch (rTagElement)
@@ -2620,13 +2613,9 @@ void 
VclMetafileProcessor2D::processStructureTagPrimitive2D(
     {
         // write end tag
         mpPDFExtOutDevData->EndStructureElement();
-        if (nPreviousElement != -1)
+        if (bNeedEndAnchor)
         {
-#ifndef NDEBUG
-            bool const bSuccess =
-#endif
-                
mpPDFExtOutDevData->SetCurrentStructureElement(nPreviousElement);
-            assert(bSuccess);
+            mpPDFExtOutDevData->EndStructureElement();
         }
     }
 }
diff --git a/include/drawinglayer/primitive2d/structuretagprimitive2d.hxx 
b/include/drawinglayer/primitive2d/structuretagprimitive2d.hxx
index 8ee2b267b57f..0d7e6ba57735 100644
--- a/include/drawinglayer/primitive2d/structuretagprimitive2d.hxx
+++ b/include/drawinglayer/primitive2d/structuretagprimitive2d.hxx
@@ -50,7 +50,7 @@ namespace drawinglayer::primitive2d
             /// flag for image (OBJ_GRAF)
             bool                                    mbIsImage;
             /// anchor structure element (Writer)
-            sal_Int32 m_nAnchorStructureElementId;
+            void const* m_pAnchorStructureElementKey;
             /// for Annot structure element, the ids of the annotations
             ::std::vector<sal_Int32> m_AnnotIds;
 
@@ -61,7 +61,7 @@ namespace drawinglayer::primitive2d
                 bool bBackground,
                 bool bIsImage,
                 Primitive2DContainer&& aChildren,
-                sal_Int32 nAnchorStructureElementId = -1,
+                void const* pAnchorStructureElementKey = nullptr,
                 ::std::vector<sal_Int32> const* pAnnotIds = nullptr);
 
             /// data read access
@@ -69,7 +69,7 @@ namespace drawinglayer::primitive2d
             bool isBackground() const { return mbBackground; }
             bool isImage() const { return mbIsImage; }
             bool isTaggedSdrObject() const;
-            sal_Int32 GetAnchorStructureElementId() const { return 
m_nAnchorStructureElementId; }
+            void const* GetAnchorStructureElementKey() const { return 
m_pAnchorStructureElementKey; }
             ::std::vector<sal_Int32> GetAnnotIds() const { return m_AnnotIds; }
 
             /// compare operator
diff --git a/include/svx/svdobj.hxx b/include/svx/svdobj.hxx
index 8dadf982b490..ed62c1db983f 100644
--- a/include/svx/svdobj.hxx
+++ b/include/svx/svdobj.hxx
@@ -129,7 +129,7 @@ class SVXCORE_DLLPUBLIC SdrObjUserCall
 public:
     virtual ~SdrObjUserCall();
     virtual void Changed(const SdrObject& rObj, SdrUserCallType eType, const 
tools::Rectangle& rOldBoundRect);
-    virtual sal_Int32 GetPDFAnchorStructureElementId(SdrObject const& rObj);
+    virtual void const* GetPDFAnchorStructureElementKey(SdrObject const& rObj);
 };
 
 class SVXCORE_DLLPUBLIC SdrObjMacroHitRec
diff --git a/svx/source/sdr/contact/viewobjectcontact.cxx 
b/svx/source/sdr/contact/viewobjectcontact.cxx
index fabf99a13d75..caac4a301042 100644
--- a/svx/source/sdr/contact/viewobjectcontact.cxx
+++ b/svx/source/sdr/contact/viewobjectcontact.cxx
@@ -436,10 +436,10 @@ drawinglayer::primitive2d::Primitive2DContainer const & 
ViewObjectContact::getPr
                     const bool bBackground(pSdrPage->IsMasterPage());
                     const bool bImage(SdrObjKind::Graphic == 
pSdrObj->GetObjIdentifier());
                     // note: there must be output device here, in PDF export
-                    sal_Int32 nAnchorId(-1);
+                    void const* pAnchorKey(nullptr);
                     if (auto const pUserCall = pSdrObj->GetUserCall())
                     {
-                        nAnchorId = 
pUserCall->GetPDFAnchorStructureElementId(*pSdrObj);
+                        pAnchorKey = 
pUserCall->GetPDFAnchorStructureElementKey(*pSdrObj);
                     }
 
                     ::std::vector<sal_Int32> annotIds;
@@ -457,7 +457,7 @@ drawinglayer::primitive2d::Primitive2DContainer const & 
ViewObjectContact::getPr
                             bBackground,
                             bImage,
                             std::move(xNewPrimitiveSequence),
-                            nAnchorId,
+                            pAnchorKey,
                             &annotIds));
                     xNewPrimitiveSequence = 
drawinglayer::primitive2d::Primitive2DContainer { xReference };
                 }
diff --git a/svx/source/svdraw/svdobj.cxx b/svx/source/svdraw/svdobj.cxx
index 5c6eed5ab2fd..5c7789ee7ed0 100644
--- a/svx/source/svdraw/svdobj.cxx
+++ b/svx/source/svdraw/svdobj.cxx
@@ -136,9 +136,9 @@ void SdrObjUserCall::Changed(const SdrObject& /*rObj*/, 
SdrUserCallType /*eType*
 {
 }
 
-sal_Int32 SdrObjUserCall::GetPDFAnchorStructureElementId(SdrObject const&)
+void const* SdrObjUserCall::GetPDFAnchorStructureElementKey(SdrObject const&)
 {
-    return -1;
+    return nullptr;
 }
 
 SdrObjMacroHitRec::SdrObjMacroHitRec() :
diff --git a/sw/inc/EnhancedPDFExportHelper.hxx 
b/sw/inc/EnhancedPDFExportHelper.hxx
index e928e417a0f0..eee6496bd17d 100644
--- a/sw/inc/EnhancedPDFExportHelper.hxx
+++ b/sw/inc/EnhancedPDFExportHelper.hxx
@@ -187,7 +187,7 @@ typedef std::vector< IdMapEntry > LinkIdMap;
 typedef std::map< const SwTable*, TableColumnsMapEntry > TableColumnsMap;
 typedef std::map< const SwNumberTreeNode*, sal_Int32 > NumListIdMap;
 typedef std::map< const SwNumberTreeNode*, sal_Int32 > NumListBodyIdMap;
-typedef std::map< const void*, sal_Int32 > FrameTagIdMap;
+typedef std::set<const void*> FrameTagSet;
 
 class SwEnhancedPDFExportHelper
 {
@@ -215,7 +215,7 @@ class SwEnhancedPDFExportHelper
     static LinkIdMap s_aLinkIdMap;
     static NumListIdMap s_aNumListIdMap;
     static NumListBodyIdMap s_aNumListBodyIdMap;
-    static FrameTagIdMap s_aFrameTagIdMap;
+    static FrameTagSet s_FrameTagSet;
 
     static LanguageType s_eLanguageDefault;
 
@@ -247,7 +247,7 @@ class SwEnhancedPDFExportHelper
     static LinkIdMap& GetLinkIdMap() { return s_aLinkIdMap; }
     static NumListIdMap& GetNumListIdMap() {return s_aNumListIdMap; }
     static NumListBodyIdMap& GetNumListBodyIdMap() {return 
s_aNumListBodyIdMap; }
-    static FrameTagIdMap& GetFrameTagIdMap() { return s_aFrameTagIdMap; }
+    static FrameTagSet & GetFrameTagSet() { return s_FrameTagSet; }
 
     static LanguageType GetDefaultLanguage() {return s_eLanguageDefault; }
 
diff --git a/sw/inc/dcontact.hxx b/sw/inc/dcontact.hxx
index 20d99f4e7523..b4d501f44ccf 100644
--- a/sw/inc/dcontact.hxx
+++ b/sw/inc/dcontact.hxx
@@ -390,7 +390,7 @@ class SAL_DLLPUBLIC_RTTI SwDrawContact final : public 
SwContact
 
         /// Virtual methods of SdrObjUserCall.
         virtual void Changed(const SdrObject& rObj, SdrUserCallType eType, 
const tools::Rectangle& rOldBoundRect) override;
-        virtual sal_Int32 GetPDFAnchorStructureElementId(SdrObject const& 
rObj) override;
+        virtual void const* GetPDFAnchorStructureElementKey(SdrObject const& 
rObj) override;
 
         /** Used by Changed() and by UndoDraw.
          Notifies paragraphs that have to get out of the way. */
diff --git a/sw/source/core/text/EnhancedPDFExportHelper.cxx 
b/sw/source/core/text/EnhancedPDFExportHelper.cxx
index 295281f8ac74..483597ca52b5 100644
--- a/sw/source/core/text/EnhancedPDFExportHelper.cxx
+++ b/sw/source/core/text/EnhancedPDFExportHelper.cxx
@@ -95,7 +95,7 @@ TableColumnsMap SwEnhancedPDFExportHelper::s_aTableColumnsMap;
 LinkIdMap SwEnhancedPDFExportHelper::s_aLinkIdMap;
 NumListIdMap SwEnhancedPDFExportHelper::s_aNumListIdMap;
 NumListBodyIdMap SwEnhancedPDFExportHelper::s_aNumListBodyIdMap;
-FrameTagIdMap SwEnhancedPDFExportHelper::s_aFrameTagIdMap;
+FrameTagSet SwEnhancedPDFExportHelper::s_FrameTagSet;
 
 LanguageType SwEnhancedPDFExportHelper::s_eLanguageDefault = LANGUAGE_SYSTEM;
 
@@ -360,32 +360,16 @@ SwTaggedPDFHelper::~SwTaggedPDFHelper()
 #endif
 }
 
-static auto GetReopenTagFromFrame(SwFrame const& rFrame) -> sal_Int32
-{
-    void const*const pKey = lcl_GetKeyFromFrame(rFrame);
-
-    if (pKey)
-    {
-        FrameTagIdMap const& 
rFrameTagIdMap(SwEnhancedPDFExportHelper::GetFrameTagIdMap());
-        auto const it(rFrameTagIdMap.find(pKey));
-        if (it != rFrameTagIdMap.end())
-        {
-            return (*it).second;
-        }
-    }
-    return -1;
-}
-
-sal_Int32 SwDrawContact::GetPDFAnchorStructureElementId(SdrObject const& rObj)
+void const* SwDrawContact::GetPDFAnchorStructureElementKey(SdrObject const& 
rObj)
 {
     SwFrame const*const pAnchorFrame(GetAnchoredObj(&rObj)->GetAnchorFrame());
-    return pAnchorFrame ? GetReopenTagFromFrame(*pAnchorFrame) : -1;
+    return pAnchorFrame ? lcl_GetKeyFromFrame(*pAnchorFrame) : nullptr;
 }
 
 bool SwTaggedPDFHelper::CheckReopenTag()
 {
     bool bRet = false;
-    sal_Int32 nReopenTag = -1;
+    void const* pReopenKey(nullptr);
     bool bContinue = false; // in some cases we just have to reopen a tag 
without early returning
 
     if ( mpFrameInfo )
@@ -422,21 +406,27 @@ bool SwTaggedPDFHelper::CheckReopenTag()
 
         if ( pKeyFrame )
         {
-            nReopenTag = GetReopenTagFromFrame(*pKeyFrame);
+            void const*const pKey = lcl_GetKeyFromFrame(*pKeyFrame);
+            FrameTagSet& 
rFrameTagSet(SwEnhancedPDFExportHelper::GetFrameTagSet());
+            if (rFrameTagSet.find(pKey) != rFrameTagSet.end()
+                || rFrame.IsFlyFrame()) // for hell layer flys
+            {
+                pReopenKey = pKey;
+            }
         }
     }
 
-    if ( -1 != nReopenTag )
+    if (pReopenKey)
     {
-        m_nRestoreCurrentTag = 
mpPDFExtOutDevData->GetCurrentStructureElement();
-        const bool bSuccess = mpPDFExtOutDevData->SetCurrentStructureElement( 
nReopenTag );
-        OSL_ENSURE( bSuccess, "Failed to reopen tag" );
+        sal_Int32 const id = 
mpPDFExtOutDevData->EnsureStructureElement(pReopenKey);
+        mpPDFExtOutDevData->BeginStructureElement(id);
+        ++m_nEndStructureElement;
 
 #if OSL_DEBUG_LEVEL > 1
         aStructStack.push_back( 99 );
 #endif
 
-        bRet = bSuccess;
+        bRet = true;
     }
 
     return bRet && !bContinue;
@@ -457,8 +447,33 @@ void SwTaggedPDFHelper::CheckRestoreTag() const
 
 void SwTaggedPDFHelper::BeginTag( vcl::PDFWriter::StructElement eType, const 
OUString& rString )
 {
+    void const* pKey(nullptr);
+
+    if ( mpFrameInfo )
+    {
+        const SwFrame& rFrame = mpFrameInfo->mrFrame;
+
+        if ( ( rFrame.IsPageFrame() && !static_cast<const 
SwPageFrame&>(rFrame).GetPrev() ) ||
+             ( rFrame.IsFlowFrame() && 
!SwFlowFrame::CastFlowFrame(&rFrame)->IsFollow() && 
SwFlowFrame::CastFlowFrame(&rFrame)->HasFollow() ) ||
+             ( rFrame.IsTextFrame() && rFrame.GetDrawObjs() ) ||
+             ( rFrame.IsRowFrame() && rFrame.IsInSplitTableRow() ) ||
+             ( rFrame.IsCellFrame() && 
const_cast<SwFrame&>(rFrame).GetNextCellLeaf() ) )
+        {
+            pKey = lcl_GetKeyFromFrame(rFrame);
+
+            if (pKey)
+            {
+                FrameTagSet& 
rFrameTagSet(SwEnhancedPDFExportHelper::GetFrameTagSet());
+                assert(rFrameTagSet.find(pKey) == rFrameTagSet.end());
+                rFrameTagSet.emplace(pKey);
+            }
+        }
+    }
+
     // write new tag
-    const sal_Int32 nId = mpPDFExtOutDevData->WrapBeginStructureElement( 
eType, rString );
+    const sal_Int32 nId = mpPDFExtOutDevData->EnsureStructureElement(pKey);
+    mpPDFExtOutDevData->InitStructureElement(nId, eType, rString);
+    mpPDFExtOutDevData->BeginStructureElement(nId);
     ++m_nEndStructureElement;
 
 #if OSL_DEBUG_LEVEL > 1
@@ -502,21 +517,6 @@ void SwTaggedPDFHelper::BeginTag( 
vcl::PDFWriter::StructElement eType, const OUS
             NumListBodyIdMap& rNumListBodyIdMap = 
SwEnhancedPDFExportHelper::GetNumListBodyIdMap();
             rNumListBodyIdMap[ pNodeNum ] = nId;
         }
-
-        if ( ( rFrame.IsPageFrame() && !static_cast<const 
SwPageFrame&>(rFrame).GetPrev() ) ||
-             ( rFrame.IsFlowFrame() && 
!SwFlowFrame::CastFlowFrame(&rFrame)->IsFollow() && 
SwFlowFrame::CastFlowFrame(&rFrame)->HasFollow() ) ||
-             ( rFrame.IsTextFrame() && rFrame.GetDrawObjs() ) ||
-             ( rFrame.IsRowFrame() && rFrame.IsInSplitTableRow() ) ||
-             ( rFrame.IsCellFrame() && 
const_cast<SwFrame&>(rFrame).GetNextCellLeaf() ) )
-        {
-            const void* pKey = lcl_GetKeyFromFrame( rFrame );
-
-            if ( pKey )
-            {
-                FrameTagIdMap& rFrameTagIdMap = 
SwEnhancedPDFExportHelper::GetFrameTagIdMap();
-                rFrameTagIdMap[ pKey ] = nId;
-            }
-        }
     }
 
     SetAttributes( eType );
@@ -1688,7 +1688,7 @@ SwEnhancedPDFExportHelper::SwEnhancedPDFExportHelper( 
SwEditShell& rSh,
     s_aLinkIdMap.clear();
     s_aNumListIdMap.clear();
     s_aNumListBodyIdMap.clear();
-    s_aFrameTagIdMap.clear();
+    s_FrameTagSet.clear();
 
 #if OSL_DEBUG_LEVEL > 1
     aStructStack.clear();
diff --git a/vcl/inc/pdf/pdfwriter_impl.hxx b/vcl/inc/pdf/pdfwriter_impl.hxx
index 8c232589e9c7..edf88459b4f4 100644
--- a/vcl/inc/pdf/pdfwriter_impl.hxx
+++ b/vcl/inc/pdf/pdfwriter_impl.hxx
@@ -28,6 +28,7 @@
 #include <memory>
 #include <string_view>
 #include <vector>
+#include <stack>
 
 #include <pdf/ResourceDict.hxx>
 #include <pdf/BitmapID.hxx>
@@ -762,6 +763,7 @@ private:
     /* current object in the structure hierarchy
      */
     sal_Int32                           m_nCurrentStructElement;
+    std::stack<sal_Int32> m_StructElementStack;
     /* structure parent tree */
     std::vector< OString >         m_aStructParentTree;
     /* emit structure marks currently (aka. NonStructElement or not)
diff --git a/vcl/qa/cppunit/pdfexport/data/tdf154982.odt 
b/vcl/qa/cppunit/pdfexport/data/tdf154982.odt
new file mode 100644
index 000000000000..a35ffb861abe
Binary files /dev/null and b/vcl/qa/cppunit/pdfexport/data/tdf154982.odt differ
diff --git a/vcl/qa/cppunit/pdfexport/pdfexport.cxx 
b/vcl/qa/cppunit/pdfexport/pdfexport.cxx
index a78ea33e38ba..4cf87ee6c994 100644
--- a/vcl/qa/cppunit/pdfexport/pdfexport.cxx
+++ b/vcl/qa/cppunit/pdfexport/pdfexport.cxx
@@ -3596,20 +3596,20 @@ CPPUNIT_TEST_FIXTURE(PdfExportTest, testTdf57423)
             {
                 switch (nFigure)
                 {
-                    case 0:
+                    case 2:
                         CPPUNIT_ASSERT_EQUAL(OUString(u"QR Code - Tells how to 
get to Mosegaard"),
                                              
::vcl::filter::PDFDocument::DecodeHexStringUTF16BE(
                                                  
*dynamic_cast<vcl::filter::PDFHexStringElement*>(
                                                      pObject->Lookup("Alt"))));
                         break;
-                    case 1:
+                    case 0:
                         CPPUNIT_ASSERT_EQUAL(OUString(u"Title: Arrows - 
Description:  Explains the "
                                                       u"different arrow 
appearances"),
                                              
::vcl::filter::PDFDocument::DecodeHexStringUTF16BE(
                                                  
*dynamic_cast<vcl::filter::PDFHexStringElement*>(
                                                      pObject->Lookup("Alt"))));
                         break;
-                    case 2:
+                    case 1:
                         CPPUNIT_ASSERT_EQUAL(
                             OUString(u"My blue triangle - Does not need 
further description"),
                             ::vcl::filter::PDFDocument::DecodeHexStringUTF16BE(
@@ -3664,6 +3664,83 @@ CPPUNIT_TEST_FIXTURE(PdfExportTest, testTdf57423)
     CPPUNIT_ASSERT_EQUAL(int(4), nDiv);
 }
 
+CPPUNIT_TEST_FIXTURE(PdfExportTest, testTdf154982)
+{
+    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"tdf154982.odt");
+
+    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());
+
+    int nFigure(0);
+    for (const auto& rDocElement : aDocument.GetElements())
+    {
+        auto pObject = 
dynamic_cast<vcl::filter::PDFObjectElement*>(rDocElement.get());
+        if (!pObject)
+            continue;
+        auto pType = 
dynamic_cast<vcl::filter::PDFNameElement*>(pObject->Lookup("Type"));
+        if (pType && pType->GetValue() == "StructElem")
+        {
+            auto pS = 
dynamic_cast<vcl::filter::PDFNameElement*>(pObject->Lookup("S"));
+            if (pS && pS->GetValue() == "Figure")
+            {
+                switch (nFigure)
+                {
+                    case 0:
+                        CPPUNIT_ASSERT_EQUAL(
+                            OUString(u"Here comes the signature - Please sign 
here"),
+                            ::vcl::filter::PDFDocument::DecodeHexStringUTF16BE(
+                                
*dynamic_cast<vcl::filter::PDFHexStringElement*>(
+                                    pObject->Lookup("Alt"))));
+                        break;
+                    case 1:
+                        CPPUNIT_ASSERT_EQUAL(OUString(u"Home"),
+                                             
::vcl::filter::PDFDocument::DecodeHexStringUTF16BE(
+                                                 
*dynamic_cast<vcl::filter::PDFHexStringElement*>(
+                                                     pObject->Lookup("Alt"))));
+                        break;
+                }
+
+                // the problem was that the figures in the hell layer were not
+                // below their anchor paragraphs in the structure tree
+                auto pParentRef
+                    = 
dynamic_cast<vcl::filter::PDFReferenceElement*>(pObject->Lookup("P"));
+                CPPUNIT_ASSERT(pParentRef);
+                auto pParent(pParentRef->LookupObject());
+                CPPUNIT_ASSERT(pParent);
+                auto pParentType
+                    = 
dynamic_cast<vcl::filter::PDFNameElement*>(pParent->Lookup("Type"));
+                CPPUNIT_ASSERT_EQUAL(OString("StructElem"), 
pParentType->GetValue());
+                auto pParentS = 
dynamic_cast<vcl::filter::PDFNameElement*>(pParent->Lookup("S"));
+                CPPUNIT_ASSERT_EQUAL(OString("Standard"), 
pParentS->GetValue());
+
+                auto pPParentRef
+                    = 
dynamic_cast<vcl::filter::PDFReferenceElement*>(pParent->Lookup("P"));
+                CPPUNIT_ASSERT(pPParentRef);
+                auto pPParent(pPParentRef->LookupObject());
+                CPPUNIT_ASSERT(pPParent);
+                auto pPParentType
+                    = 
dynamic_cast<vcl::filter::PDFNameElement*>(pPParent->Lookup("Type"));
+                CPPUNIT_ASSERT_EQUAL(OString("StructElem"), 
pPParentType->GetValue());
+                auto pPParentS = 
dynamic_cast<vcl::filter::PDFNameElement*>(pPParent->Lookup("S"));
+                CPPUNIT_ASSERT_EQUAL(OString("Document"), 
pPParentS->GetValue());
+                ++nFigure;
+            }
+        }
+    }
+    CPPUNIT_ASSERT_EQUAL(int(2), nFigure);
+}
+
 CPPUNIT_TEST_FIXTURE(PdfExportTest, testTdf135192)
 {
     aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export");
diff --git a/vcl/source/gdi/pdfwriter_impl.cxx 
b/vcl/source/gdi/pdfwriter_impl.cxx
index 93ff4c100619..2c7642817f4d 100644
--- a/vcl/source/gdi/pdfwriter_impl.cxx
+++ b/vcl/source/gdi/pdfwriter_impl.cxx
@@ -1233,6 +1233,7 @@ PDFWriterImpl::PDFWriterImpl( const 
PDFWriter::PDFWriterContext& rContext,
     m_aStructure.emplace_back( );
     m_aStructure[0].m_nOwnElement       = 0;
     m_aStructure[0].m_nParentElement    = 0;
+    //m_StructElementStack.push(0);
 
     Font aFont;
     aFont.SetFamilyName( "Times" );
@@ -10887,6 +10888,7 @@ void PDFWriterImpl::beginStructureElement(sal_Int32 
const id)
     endStructureElementMCSeq(EndMode::OnlyStruct);
 
     PDFStructureElement& rEle = m_aStructure[id];
+    m_StructElementStack.push(m_nCurrentStructElement);
     m_nCurrentStructElement = id;
 
     if (g_bDebugDisableCompression)
@@ -10946,7 +10948,8 @@ void PDFWriterImpl::endStructureElement()
     }
 
     // "end" the structure element, the parent becomes current element
-    m_nCurrentStructElement = m_aStructure[ m_nCurrentStructElement 
].m_nParentElement;
+    m_nCurrentStructElement = m_StructElementStack.top();
+    m_StructElementStack.pop();
 
     // check whether to emit structure henceforth
     m_bEmitStructure = checkEmitStructure();

Reply via email to