drawinglayer/source/primitive2d/controlprimitive2d.cxx     |    4 
 drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx |   20 ++++
 include/drawinglayer/primitive2d/controlprimitive2d.hxx    |    8 +
 svx/source/sdr/contact/viewcontactofunocontrol.cxx         |    9 +
 svx/source/sdr/contact/viewobjectcontactofunocontrol.cxx   |   10 +-
 vcl/qa/cppunit/pdfexport/pdfexport.cxx                     |   63 +++++++++++++
 6 files changed, 109 insertions(+), 5 deletions(-)

New commits:
commit 2dbbc200e87b472e7a6daf1e1f658496fd569813
Author:     Michael Stahl <michael.st...@allotropia.de>
AuthorDate: Wed Oct 11 19:13:53 2023 +0200
Commit:     Caolán McNamara <caolan.mcnam...@collabora.com>
CommitDate: Wed Oct 18 22:23:44 2023 +0200

    drawinglayer,svx: PDF/UA export: put Form SE into anchor paragraph SE
    
    This is like commit d467f1aa3d028f399826c97e2eecedcd79efcf65
    and commit 6e5d59c2ca6969e9491f97cd7a00d094fc62cfb3 but for the
    form controls, which have their own special ControlPrimitive2D.
    
    Change-Id: I4b4ac45e81f490a7b625acd9e8753300d10bf119
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/157847
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>
    (cherry picked from commit d5c19ef9d30cde052e8cd2486ac9395e62d9c9a9)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/157874
    Reviewed-by: Caolán McNamara <caolan.mcnam...@collabora.com>

diff --git a/drawinglayer/source/primitive2d/controlprimitive2d.cxx 
b/drawinglayer/source/primitive2d/controlprimitive2d.cxx
index 372fb61244a0..c8448efa981f 100644
--- a/drawinglayer/source/primitive2d/controlprimitive2d.cxx
+++ b/drawinglayer/source/primitive2d/controlprimitive2d.cxx
@@ -243,10 +243,12 @@ namespace drawinglayer::primitive2d
             uno::Reference< awt::XControlModel > xControlModel,
             uno::Reference<awt::XControl> xXControl,
             ::std::u16string_view const rTitle,
-            ::std::u16string_view const rDescription)
+            ::std::u16string_view const rDescription,
+            void const*const pAnchorKey)
         :   maTransform(std::move(aTransform)),
             mxControlModel(std::move(xControlModel)),
             mxXControl(std::move(xXControl))
+        , m_pAnchorStructureElementKey(pAnchorKey)
         {
             ::rtl::OUStringBuffer buf(rTitle);
             if (!rTitle.empty() && !rDescription.empty())
diff --git a/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx 
b/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx
index a5882e8b95cb..5b853d8152c1 100644
--- a/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx
+++ b/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx
@@ -1101,6 +1101,18 @@ void VclMetafileProcessor2D::processControlPrimitive2D(
     if (!bIsPrintableControl)
         return;
 
+    ::std::optional<sal_Int32> oAnchorParent;
+    if (mpPDFExtOutDevData)
+    {
+        if (rControlPrimitive.GetAnchorStructureElementKey())
+        {
+            sal_Int32 const id = mpPDFExtOutDevData->EnsureStructureElement(
+                rControlPrimitive.GetAnchorStructureElementKey());
+            
oAnchorParent.emplace(mpPDFExtOutDevData->GetCurrentStructureElement());
+            mpPDFExtOutDevData->SetCurrentStructureElement(id);
+        }
+    }
+
     const bool bPDFExport(mpPDFExtOutDevData && 
mpPDFExtOutDevData->GetIsExportFormFields());
     bool bDoProcessRecursively(true);
 
@@ -1153,6 +1165,10 @@ void VclMetafileProcessor2D::processControlPrimitive2D(
             }
             mpPDFExtOutDevData->CreateControl(*pPDFControl);
             mpPDFExtOutDevData->EndStructureElement();
+            if (oAnchorParent)
+            {
+                mpPDFExtOutDevData->SetCurrentStructureElement(*oAnchorParent);
+            }
 
             // no normal paint needed (see original 
UnoControlPDFExportContact::do_PaintObject);
             // do not process recursively
@@ -1235,6 +1251,10 @@ void VclMetafileProcessor2D::processControlPrimitive2D(
     if (mpPDFExtOutDevData)
     {
         mpPDFExtOutDevData->EndStructureElement();
+        if (oAnchorParent)
+        {
+            mpPDFExtOutDevData->SetCurrentStructureElement(*oAnchorParent);
+        }
     }
 }
 
diff --git a/include/drawinglayer/primitive2d/controlprimitive2d.hxx 
b/include/drawinglayer/primitive2d/controlprimitive2d.hxx
index e33c26886cd9..a7128b7f7322 100644
--- a/include/drawinglayer/primitive2d/controlprimitive2d.hxx
+++ b/include/drawinglayer/primitive2d/controlprimitive2d.hxx
@@ -58,6 +58,9 @@ private:
     /// yet another special snowflake way to generate PDF Alt text
     OUString m_AltText;
 
+    /// anchor structure element (Writer)
+    void const* const m_pAnchorStructureElementKey;
+
     /** used from getXControl() to create a local awt::XControl which is 
remembered in mxXControl
                 and from thereon always used and returned by getXControl()
              */
@@ -81,7 +84,8 @@ public:
     ControlPrimitive2D(basegfx::B2DHomMatrix aTransform,
                        css::uno::Reference<css::awt::XControlModel> 
xControlModel,
                        css::uno::Reference<css::awt::XControl> xXControl,
-                       ::std::u16string_view rTitle, ::std::u16string_view 
rDescription);
+                       ::std::u16string_view rTitle, ::std::u16string_view 
rDescription,
+                       void const* pAnchorKey);
 
     /// data read access
     const basegfx::B2DHomMatrix& getTransform() const { return maTransform; }
@@ -98,6 +102,8 @@ public:
 
     OUString const& GetAltText() const { return m_AltText; }
 
+    void const* GetAnchorStructureElementKey() const { return 
m_pAnchorStructureElementKey; }
+
     /// compare operator
     virtual bool operator==(const BasePrimitive2D& rPrimitive) const override;
 
diff --git a/svx/source/sdr/contact/viewcontactofunocontrol.cxx 
b/svx/source/sdr/contact/viewcontactofunocontrol.cxx
index cc14ae06ad5e..3018551d8175 100644
--- a/svx/source/sdr/contact/viewcontactofunocontrol.cxx
+++ b/svx/source/sdr/contact/viewcontactofunocontrol.cxx
@@ -106,6 +106,12 @@ namespace sdr::contact {
 
         if(xControlModel.is())
         {
+            void const* pAnchorKey(nullptr);
+            if (auto const pUserCall = GetSdrObject().GetUserCall())
+            {
+                pAnchorKey = 
pUserCall->GetPDFAnchorStructureElementKey(GetSdrObject());
+            }
+
             // create control primitive WITHOUT possibly existing XControl; 
this would be done in
             // the VOC in createPrimitive2DSequence()
             const drawinglayer::primitive2d::Primitive2DReference xRetval(
@@ -114,7 +120,8 @@ namespace sdr::contact {
                     xControlModel,
                     nullptr,
                     GetSdrObject().GetTitle(),
-                    GetSdrObject().GetDescription()));
+                    GetSdrObject().GetDescription(),
+                    pAnchorKey));
 
             rVisitor.visit(xRetval);
         }
diff --git a/svx/source/sdr/contact/viewobjectcontactofunocontrol.cxx 
b/svx/source/sdr/contact/viewobjectcontactofunocontrol.cxx
index 27eddc715420..e5292b1515d5 100644
--- a/svx/source/sdr/contact/viewobjectcontactofunocontrol.cxx
+++ b/svx/source/sdr/contact/viewobjectcontactofunocontrol.cxx
@@ -1564,12 +1564,18 @@ namespace sdr::contact {
             return;
         }
 
+        SdrObject const& rSdrObj(m_pVOCImpl->getViewContact().GetSdrObject());
+        void const* pAnchorKey(nullptr);
+        if (auto const pUserCall = rSdrObj.GetUserCall())
+        {
+            pAnchorKey = pUserCall->GetPDFAnchorStructureElementKey(rSdrObj);
+        }
+
         // create a primitive and hand over the existing xControl. This will
         // allow the primitive to not need to create another one on demand.
         rContainer.push_back( new 
::drawinglayer::primitive2d::ControlPrimitive2D(
             m_aTransformation, xControlModel, rControl.getControl(),
-            m_pVOCImpl->getViewContact().GetSdrObject().GetTitle(),
-            m_pVOCImpl->getViewContact().GetSdrObject().GetDescription()) );
+            rSdrObj.GetTitle(), rSdrObj.GetDescription(), pAnchorKey) );
     }
 
     sal_uInt32 LazyControlCreationPrimitive2D::getPrimitive2DID() const
diff --git a/vcl/qa/cppunit/pdfexport/pdfexport.cxx 
b/vcl/qa/cppunit/pdfexport/pdfexport.cxx
index 09c6ef847035..9ea2f2a89742 100644
--- a/vcl/qa/cppunit/pdfexport/pdfexport.cxx
+++ b/vcl/qa/cppunit/pdfexport/pdfexport.cxx
@@ -4606,6 +4606,69 @@ CPPUNIT_TEST_FIXTURE(PdfExportTest, testTdf157397)
         CPPUNIT_ASSERT_EQUAL(static_cast<decltype(nMCID)>(1), nMCID);
         CPPUNIT_ASSERT_EQUAL(static_cast<decltype(nRef)>(1), nRef);
     }
+
+    auto pRefKid16 = 
dynamic_cast<vcl::filter::PDFReferenceElement*>(pKids1v[6]);
+    CPPUNIT_ASSERT(pRefKid16);
+    auto pObject16 = pRefKid16->LookupObject();
+    CPPUNIT_ASSERT(pObject16);
+    auto pType16 = 
dynamic_cast<vcl::filter::PDFNameElement*>(pObject16->Lookup("Type"));
+    CPPUNIT_ASSERT_EQUAL(OString("StructElem"), pType16->GetValue());
+    auto pS16 = 
dynamic_cast<vcl::filter::PDFNameElement*>(pObject16->Lookup("S"));
+    CPPUNIT_ASSERT_EQUAL(OString("Text#20body"), pS16->GetValue());
+
+    auto pKids16 = 
dynamic_cast<vcl::filter::PDFArrayElement*>(pObject16->Lookup("K"));
+    CPPUNIT_ASSERT(pKids16);
+    // assume there are no MCID ref at this level
+    auto pKids16v = pKids16->GetElements();
+    auto pRefKid160 = 
dynamic_cast<vcl::filter::PDFReferenceElement*>(pKids16v[0]);
+    CPPUNIT_ASSERT(pRefKid160);
+    auto pObject160 = pRefKid160->LookupObject();
+    CPPUNIT_ASSERT(pObject160);
+    auto pType160 = 
dynamic_cast<vcl::filter::PDFNameElement*>(pObject160->Lookup("Type"));
+    CPPUNIT_ASSERT_EQUAL(OString("StructElem"), pType160->GetValue());
+    auto pS160 = 
dynamic_cast<vcl::filter::PDFNameElement*>(pObject160->Lookup("S"));
+    CPPUNIT_ASSERT_EQUAL(OString("Form"), pS160->GetValue());
+    auto pA160 = 
dynamic_cast<vcl::filter::PDFReferenceElement*>(pObject160->Lookup("A"));
+    CPPUNIT_ASSERT(pA160);
+    auto pA160Obj = pA160->LookupObject();
+    auto pA160O = 
dynamic_cast<vcl::filter::PDFNameElement*>(pA160Obj->Lookup("O"));
+    CPPUNIT_ASSERT(pA160O);
+    CPPUNIT_ASSERT_EQUAL(OString("PrintField"), pA160O->GetValue());
+    auto pA160Role = 
dynamic_cast<vcl::filter::PDFNameElement*>(pA160Obj->Lookup("Role"));
+    CPPUNIT_ASSERT(pA160Role);
+    CPPUNIT_ASSERT_EQUAL(OString("tv"), pA160Role->GetValue());
+
+    {
+        auto pKids = 
dynamic_cast<vcl::filter::PDFArrayElement*>(pObject160->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("Widget"), pASubtype->GetValue());
+            }
+        }
+        CPPUNIT_ASSERT_EQUAL(static_cast<decltype(nMCID)>(1), nMCID);
+        CPPUNIT_ASSERT_EQUAL(static_cast<decltype(nRef)>(1), nRef);
+    }
 }
 
 CPPUNIT_TEST_FIXTURE(PdfExportTest, testTdf135192)

Reply via email to