include/svx/sdr/contact/viewobjectcontact.hxx |    3 
 svx/source/sdr/contact/viewobjectcontact.cxx  |    7 +-
 sw/source/core/doc/notxtfrm.cxx               |    3 
 vcl/qa/cppunit/pdfexport/data/tdf155190.odt   |binary
 vcl/qa/cppunit/pdfexport/pdfexport.cxx        |   88 ++++++++++++++++++++++++++
 vcl/source/gdi/pdfwriter_impl.cxx             |    5 -
 6 files changed, 102 insertions(+), 4 deletions(-)

New commits:
commit 370533da3f07169791c0a17013ca55c57df2f3c9
Author:     Michael Stahl <michael.st...@allotropia.de>
AuthorDate: Fri May 26 16:20:47 2023 +0200
Commit:     Michael Stahl <michael.st...@allotropia.de>
CommitDate: Fri May 26 19:19:20 2023 +0200

    tdf#155190 svx,sw: PDF export: don't tag SwNoTextFrame as Artifact
    
    The problem is that inside of the Figure tag, in
    SwNoTextFrame::ImplPaintPictureGraphic(), ViewContactOfSwNoTextFrame
    and ViewObjectContactOfSwNoTextFrame are used to create and process
    another primitive sequence.
    
    ViewObjectContactOfSwNoTextFrame does not have access to a SdrObject,
    because that was already processed by the outer layer of code that
    called the SwFlyFrame painting code.
    
    Avoid running the code that assumes anything without an SdrObject is an
    artifact by disabling PDF tags altogether in
    ViewObjectContactOfSwNoTextFrame.
    
    (regression from commit 81ef84648515965bf67afaced946227d0f63a71e)
    
    Change-Id: I9fabe7f7e5296f8d850448ac44865f87cd164591
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/152335
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>

diff --git a/include/svx/sdr/contact/viewobjectcontact.hxx 
b/include/svx/sdr/contact/viewobjectcontact.hxx
index 1be4cac81052..6046bd93fe6b 100644
--- a/include/svx/sdr/contact/viewobjectcontact.hxx
+++ b/include/svx/sdr/contact/viewobjectcontact.hxx
@@ -116,6 +116,9 @@ public:
     // This method will not handle included hierarchies and not check 
visibility.
     drawinglayer::primitive2d::Primitive2DContainer const & 
getPrimitive2DSequence(const DisplayInfo& rDisplayInfo) const;
 
+    /// check if getPrimitive2DSequence() should create tag
+    virtual bool isExportPDFTags() const;
+
     // test this VOC for visibility concerning model-view stuff like e.g. Layer
     virtual bool isPrimitiveVisible(const DisplayInfo& rDisplayInfo) const;
 
diff --git a/svx/source/sdr/contact/viewobjectcontact.cxx 
b/svx/source/sdr/contact/viewobjectcontact.cxx
index fb6f0fc73ff1..82b21d137ef1 100644
--- a/svx/source/sdr/contact/viewobjectcontact.cxx
+++ b/svx/source/sdr/contact/viewobjectcontact.cxx
@@ -341,6 +341,11 @@ void ViewObjectContact::createPrimitive2DSequence(const 
DisplayInfo& rDisplayInf
     rVisitor.visit(xRetval);
 }
 
+bool ViewObjectContact::isExportPDFTags() const
+{
+    return GetObjectContact().isExportTaggedPDF();
+}
+
 drawinglayer::primitive2d::Primitive2DContainer const & 
ViewObjectContact::getPrimitive2DSequence(const DisplayInfo& rDisplayInfo) const
 {
     // only some of the top-level apps are any good at reliably invalidating 
us (e.g. writer is not)
@@ -387,7 +392,7 @@ drawinglayer::primitive2d::Primitive2DContainer const & 
ViewObjectContact::getPr
 
     // Check if we need to embed to a StructureTagPrimitive2D, too. This
     // was done at ImplRenderPaintProc::createRedirectedPrimitive2DSequence 
before
-    if (!xNewPrimitiveSequence.empty() && 
GetObjectContact().isExportTaggedPDF())
+    if (!xNewPrimitiveSequence.empty() && isExportPDFTags())
     {
         if (nullptr != pSdrObj)
         {
diff --git a/sw/source/core/doc/notxtfrm.cxx b/sw/source/core/doc/notxtfrm.cxx
index eb0b4d96102a..ccf60904585d 100644
--- a/sw/source/core/doc/notxtfrm.cxx
+++ b/sw/source/core/doc/notxtfrm.cxx
@@ -993,6 +993,9 @@ protected:
         const sdr::contact::DisplayInfo& rDisplayInfo,
         drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) 
const override;
 
+    // tdf#155190 disable this so superclass doesn't wrongly produce NonStruct
+    virtual bool isExportPDFTags() const override { return false; }
+
 public:
     ViewObjectContactOfSwNoTextFrame(
         sdr::contact::ObjectContact& rObjectContact,
diff --git a/vcl/qa/cppunit/pdfexport/data/tdf155190.odt 
b/vcl/qa/cppunit/pdfexport/data/tdf155190.odt
new file mode 100644
index 000000000000..51930ad2992d
Binary files /dev/null and b/vcl/qa/cppunit/pdfexport/data/tdf155190.odt differ
diff --git a/vcl/qa/cppunit/pdfexport/pdfexport.cxx 
b/vcl/qa/cppunit/pdfexport/pdfexport.cxx
index bf2ca137646f..0739cd25cd8a 100644
--- a/vcl/qa/cppunit/pdfexport/pdfexport.cxx
+++ b/vcl/qa/cppunit/pdfexport/pdfexport.cxx
@@ -3598,6 +3598,94 @@ CPPUNIT_TEST_FIXTURE(PdfExportTest, testTdf135192)
     CPPUNIT_ASSERT_EQUAL(int(1), nTable);
 }
 
+CPPUNIT_TEST_FIXTURE(PdfExportTest, testTdf155190)
+{
+    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"tdf155190.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());
+
+    auto nDiv(0);
+    auto nFigure(0);
+    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"));
+
+        auto pS1 = 
dynamic_cast<vcl::filter::PDFNameElement*>(pObject1->Lookup("S"));
+        // start with the text box
+        if (pType1 && pType1->GetValue() == "StructElem" && pS1 && 
pS1->GetValue() == "Div")
+        {
+            ++nDiv;
+            auto pKids1 = 
dynamic_cast<vcl::filter::PDFArrayElement*>(pObject1->Lookup("K"));
+            CPPUNIT_ASSERT(pKids1);
+            for (auto pKid1 : pKids1->GetElements())
+            {
+                auto pRefKid1 = 
dynamic_cast<vcl::filter::PDFReferenceElement*>(pKid1);
+                if (pRefKid1)
+                {
+                    auto pObject2 = pRefKid1->LookupObject();
+                    CPPUNIT_ASSERT(pObject2);
+                    auto pType2
+                        = 
dynamic_cast<vcl::filter::PDFNameElement*>(pObject2->Lookup("Type"));
+                    CPPUNIT_ASSERT(pType2);
+                    CPPUNIT_ASSERT_EQUAL(OString("StructElem"), 
pType2->GetValue());
+                    auto pS2 = 
dynamic_cast<vcl::filter::PDFNameElement*>(pObject2->Lookup("S"));
+                    CPPUNIT_ASSERT_EQUAL(OString("FigureCaption"), 
pS2->GetValue());
+                    auto pKids2
+                        = 
dynamic_cast<vcl::filter::PDFArrayElement*>(pObject2->Lookup("K"));
+                    CPPUNIT_ASSERT(pKids2);
+                    // there are additional children, MCID ref
+                    for (auto pKid2 : pKids2->GetElements())
+                    {
+                        auto pRefKid2 = 
dynamic_cast<vcl::filter::PDFReferenceElement*>(pKid2);
+                        if (pRefKid2)
+                        {
+                            auto pObject3 = pRefKid2->LookupObject();
+                            CPPUNIT_ASSERT(pObject3);
+                            auto pType3 = 
dynamic_cast<vcl::filter::PDFNameElement*>(
+                                pObject3->Lookup("Type"));
+                            if (pType3 && pType3->GetValue() == "StructElem")
+                            {
+                                auto pS3 = 
dynamic_cast<vcl::filter::PDFNameElement*>(
+                                    pObject3->Lookup("S"));
+                                CPPUNIT_ASSERT_EQUAL(OString("Figure"), 
pS3->GetValue());
+                                auto pAlt = 
dynamic_cast<vcl::filter::PDFHexStringElement*>(
+                                    pObject3->Lookup("Alt"));
+                                CPPUNIT_ASSERT_EQUAL(
+                                    OUString("Picture of apples"),
+                                    
::vcl::filter::PDFDocument::DecodeHexStringUTF16BE(*pAlt));
+                                auto pKids3 = 
dynamic_cast<vcl::filter::PDFArrayElement*>(
+                                    pObject3->Lookup("K"));
+                                CPPUNIT_ASSERT(pKids3);
+                                // the problem was that this didn't reference 
an MCID
+                                CPPUNIT_ASSERT(!pKids3->GetElements().empty());
+                                ++nFigure;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+    CPPUNIT_ASSERT_EQUAL(static_cast<decltype(nDiv)>(1), nDiv);
+    CPPUNIT_ASSERT_EQUAL(static_cast<decltype(nDiv)>(1), nFigure);
+}
+
 CPPUNIT_TEST_FIXTURE(PdfExportTest, testMediaShapeAnnot)
 {
     aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export");
commit ef2d064c403738660e9ba6bee6de736d0575dade
Author:     Michael Stahl <michael.st...@allotropia.de>
AuthorDate: Fri May 26 16:18:12 2023 +0200
Commit:     Michael Stahl <michael.st...@allotropia.de>
CommitDate: Fri May 26 19:19:12 2023 +0200

    vcl: PDF export: stop adding pointless circular RoleMap entries
    
    ... for standard roles; no idea what these are supposed to be good for.
    
    Change-Id: Ie2ccf394631a2bccb496b2f93e26a571ba84d58d
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/152334
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>

diff --git a/vcl/source/gdi/pdfwriter_impl.cxx 
b/vcl/source/gdi/pdfwriter_impl.cxx
index c930458f55ab..36fa35e0f6a1 100644
--- a/vcl/source/gdi/pdfwriter_impl.cxx
+++ b/vcl/source/gdi/pdfwriter_impl.cxx
@@ -10616,9 +10616,8 @@ void PDFWriterImpl::addRoleMap(OString aAlias, 
PDFWriter::StructElement eType)
 {
     OString aTag = getStructureTag(eType);
     // For PDF/UA it's not allowed to map an alias with the same name.
-    // Not sure if this allowed, necessary or recommended otherwise, so
-    // only enable filtering when PDF/UA is enabled.
-    if (!m_bIsPDF_UA || aAlias != aTag)
+    // Not aware of a reason for doing it in any case, so just don't do it.
+    if (aAlias != aTag)
         m_aRoleMap[aAlias] = aTag;
 }
 

Reply via email to