tdf#159067 drawinglayer: fix untagged form control (PDF/UA export)

If the form object is marked as decorative, the form control should be exported as "Artifact"

Change-Id: I615d308ae966bf3d0f156899a0b4fad2d5a7c492
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/162268
Tested-by: Jenkins
Reviewed-by: Nagy Tibor <tibor.nagy.extern@allotropia.de>
diff --git a/drawinglayer/source/primitive2d/structuretagprimitive2d.cxx b/drawinglayer/source/primitive2d/structuretagprimitive2d.cxx
index 47af55a..783a54a 100644
--- a/drawinglayer/source/primitive2d/structuretagprimitive2d.cxx
+++ b/drawinglayer/source/primitive2d/structuretagprimitive2d.cxx
@@ -30,13 +30,15 @@ namespace drawinglayer::primitive2d
            const vcl::PDFWriter::StructElement& rStructureElement,
            bool bBackground,
            bool bIsImage,
            bool bIsDecorative,
            Primitive2DContainer&& aChildren,
            void const*const pAnchorStructureElementKey,
            ::std::vector<sal_Int32> const*const pAnnotIds)
        :   GroupPrimitive2D(std::move(aChildren)),
            maStructureElement(rStructureElement),
            mbBackground(bBackground),
            mbIsImage(bIsImage)
            mbIsImage(bIsImage),
            mbIsDecorative(bIsDecorative)
        ,   m_pAnchorStructureElementKey(pAnchorStructureElementKey)
        {
            if (pAnnotIds)
diff --git a/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx b/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx
index 22f464d..e4441bb 100644
--- a/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx
+++ b/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx
@@ -1116,8 +1116,9 @@ void VclMetafileProcessor2D::processControlPrimitive2D(

    const bool bPDFExport(mpPDFExtOutDevData && mpPDFExtOutDevData->GetIsExportFormFields());
    bool bDoProcessRecursively(true);
    bool bDecorative = (mpCurrentStructureTag && mpCurrentStructureTag->isDecorative());

    if (bPDFExport)
    if (bPDFExport && !bDecorative)
    {
        // PDF export. Emulate data handling from UnoControlPDFExportContact
        std::unique_ptr<vcl::PDFWriter::AnyWidget> pPDFControl(
@@ -1190,7 +1191,10 @@ void VclMetafileProcessor2D::processControlPrimitive2D(

    if (mpPDFExtOutDevData)
    { // no corresponding PDF Form, use Figure instead
        mpPDFExtOutDevData->WrapBeginStructureElement(vcl::PDFWriter::Figure);
        if (!bDecorative)
            mpPDFExtOutDevData->WrapBeginStructureElement(vcl::PDFWriter::Figure);
        else
            mpPDFExtOutDevData->WrapBeginStructureElement(vcl::PDFWriter::NonStructElement);
        mpPDFExtOutDevData->SetStructureAttribute(vcl::PDFWriter::Placement, vcl::PDFWriter::Block);
        auto const range(rControlPrimitive.getB2DRange(getViewInformation2D()));
        tools::Rectangle const aLogicRect(
@@ -1198,7 +1202,7 @@ void VclMetafileProcessor2D::processControlPrimitive2D(
            basegfx::fround(range.getMaxX()), basegfx::fround(range.getMaxY()));
        mpPDFExtOutDevData->SetStructureBoundingBox(aLogicRect);
        OUString const& rAltText(rControlPrimitive.GetAltText());
        if (!rAltText.isEmpty())
        if (!rAltText.isEmpty() && !bDecorative)
        {
            mpPDFExtOutDevData->SetAlternateText(rAltText);
        }
diff --git a/include/drawinglayer/primitive2d/structuretagprimitive2d.hxx b/include/drawinglayer/primitive2d/structuretagprimitive2d.hxx
index 0d7e6ba..3cc4899 100644
--- a/include/drawinglayer/primitive2d/structuretagprimitive2d.hxx
+++ b/include/drawinglayer/primitive2d/structuretagprimitive2d.hxx
@@ -49,6 +49,8 @@ namespace drawinglayer::primitive2d
            bool                                    mbBackground;
            /// flag for image (OBJ_GRAF)
            bool                                    mbIsImage;
            /// flag for form control object
            bool                                    mbIsDecorative;
            /// anchor structure element (Writer)
            void const* m_pAnchorStructureElementKey;
            /// for Annot structure element, the ids of the annotations
@@ -60,6 +62,7 @@ namespace drawinglayer::primitive2d
                const vcl::PDFWriter::StructElement& rStructureElement,
                bool bBackground,
                bool bIsImage,
                bool bIsDecorative,
                Primitive2DContainer&& aChildren,
                void const* pAnchorStructureElementKey = nullptr,
                ::std::vector<sal_Int32> const* pAnnotIds = nullptr);
@@ -68,6 +71,7 @@ namespace drawinglayer::primitive2d
            const vcl::PDFWriter::StructElement& getStructureElement() const { return maStructureElement; }
            bool isBackground() const { return mbBackground; }
            bool isImage() const { return mbIsImage; }
            bool isDecorative() const { return mbIsDecorative; }
            bool isTaggedSdrObject() const;
            void const* GetAnchorStructureElementKey() const { return m_pAnchorStructureElementKey; }
            ::std::vector<sal_Int32> GetAnnotIds() const { return m_AnnotIds; }
diff --git a/sc/qa/extras/scpdfexport.cxx b/sc/qa/extras/scpdfexport.cxx
index bd6807e..6cf93f7 100644
--- a/sc/qa/extras/scpdfexport.cxx
+++ b/sc/qa/extras/scpdfexport.cxx
@@ -66,6 +66,7 @@ public:
    void testUnoCommands_Tdf120161();
    void testTdf64703_hiddenPageBreak();
    void testTdf159068();
    void testTdf159067();
    void testTdf159066();
    void testTdf159065();
    void testTdf123870();
@@ -81,6 +82,7 @@ public:
    CPPUNIT_TEST(testUnoCommands_Tdf120161);
    CPPUNIT_TEST(testTdf64703_hiddenPageBreak);
    CPPUNIT_TEST(testTdf159068);
    CPPUNIT_TEST(testTdf159067);
    CPPUNIT_TEST(testTdf159066);
    CPPUNIT_TEST(testTdf159065);
    CPPUNIT_TEST(testTdf123870);
@@ -460,6 +462,66 @@ void ScPDFExportTest::testTdf159068()
    CPPUNIT_ASSERT_EQUAL(static_cast<decltype(nArtifact)>(5), nArtifact);
}

void ScPDFExportTest::testTdf159067()
{
    loadFromFile(u"tdf159067.ods");
    uno::Reference<frame::XModel> xModel(mxComponent, uno::UNO_QUERY);

    // A1:B3
    ScRange range1(0, 0, 0, 1, 2, 0);
    exportToPDF(xModel, range1);

    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* pContents = aPages[0]->LookupObject("Contents"_ostr);
    CPPUNIT_ASSERT(pContents);
    vcl::filter::PDFStreamElement* pStream = pContents->GetStream();
    CPPUNIT_ASSERT(pStream);

    SvMemoryStream& rObjectStream = pStream->GetMemory();
    // Uncompress it.
    SvMemoryStream aUncompressed;
    ZCodec aZCodec;
    aZCodec.BeginCompression();
    rObjectStream.Seek(0);
    aZCodec.Decompress(rObjectStream, aUncompressed);
    CPPUNIT_ASSERT(aZCodec.EndCompression());

    auto pStart = static_cast<const char*>(aUncompressed.GetData());
    const char* const pEnd = pStart + aUncompressed.GetSize();

    auto nArtifact(0);
    auto nLine(0);
    while (true)
    {
        ++nLine;
        auto const pLine = ::std::find(pStart, pEnd, '\n');
        if (pLine == pEnd)
        {
            break;
        }
        std::string_view const line(pStart, pLine - pStart);
        pStart = pLine + 1;
        if (!line.empty() && line[0] != '%')
        {
            ::std::cerr << nLine << ": " << line << "\n ";
            if (o3tl::starts_with(line, "/Artifact BMC"))
                nArtifact++;
        }
    }

    // Without the fix in place, this test would have failed with
    // - Expected: 3 (Artifact: Header, Footer, TextBox)
    // - Actual  : 2 (Artifact: Header, Footer)
    CPPUNIT_ASSERT_EQUAL(static_cast<decltype(nArtifact)>(3), nArtifact);
}

void ScPDFExportTest::testTdf159066()
{
    loadFromFile(u"tdf159066.ods");
diff --git a/sc/qa/extras/testdocuments/tdf159067.ods b/sc/qa/extras/testdocuments/tdf159067.ods
new file mode 100644
index 0000000..a6e268d
--- /dev/null
+++ b/sc/qa/extras/testdocuments/tdf159067.ods
Binary files differ
diff --git a/svx/source/sdr/contact/viewobjectcontact.cxx b/svx/source/sdr/contact/viewobjectcontact.cxx
index 09593f1..c962e77 100644
--- a/svx/source/sdr/contact/viewobjectcontact.cxx
+++ b/svx/source/sdr/contact/viewobjectcontact.cxx
@@ -422,6 +422,7 @@ void ViewObjectContact::createStructureTag(drawinglayer::primitive2d::Primitive2
                                eElement,
                                bBackground,
                                bImage,
                                false, // Decorative
                                std::move(rNewPrimitiveSequence),
                                pAnchorKey,
                                &annotIds))
@@ -438,6 +439,7 @@ void ViewObjectContact::createStructureTag(drawinglayer::primitive2d::Primitive2
                        vcl::PDFWriter::Division,
                        true,
                        true,
                        true, // Decorative
                        std::move(rNewPrimitiveSequence))
                };
        }
diff --git a/svx/source/table/viewcontactoftableobj.cxx b/svx/source/table/viewcontactoftableobj.cxx
index ac7472c..b0accab 100644
--- a/svx/source/table/viewcontactoftableobj.cxx
+++ b/svx/source/table/viewcontactoftableobj.cxx
@@ -384,6 +384,7 @@ namespace sdr::contact
                                        eType,
                                        pPage->IsMasterPage(),
                                        false,
                                        false,
                                        std::move(cell)) };
                            }
                            row.append(cell);
@@ -396,6 +397,7 @@ namespace sdr::contact
                                    vcl::PDFWriter::TableRow,
                                    pPage->IsMasterPage(),
                                    false,
                                    false,
                                    std::move(row)) };
                        }
                        aRetval.append(row);