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 ++++++++++++++++++++++++++ 5 files changed, 100 insertions(+), 1 deletion(-)
New commits: commit 9654214d0d19a7b4b2b33e62bd5083b59ccadd26 Author: Michael Stahl <michael.st...@allotropia.de> AuthorDate: Fri May 26 16:20:47 2023 +0200 Commit: Xisco Fauli <xiscofa...@libreoffice.org> CommitDate: Wed May 31 10:16:37 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> (cherry picked from commit 07a0c7419d2925a9c8622461073a5d34ffc93e3e) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/152313 Reviewed-by: Xisco Fauli <xiscofa...@libreoffice.org> 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 aff704134ae1..db617325c8f0 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 6cb71550387c..5367006809c2 100644 --- a/sw/source/core/doc/notxtfrm.cxx +++ b/sw/source/core/doc/notxtfrm.cxx @@ -1002,6 +1002,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 60ea081ed423..68c026663478 100644 --- a/vcl/qa/cppunit/pdfexport/pdfexport.cxx +++ b/vcl/qa/cppunit/pdfexport/pdfexport.cxx @@ -3544,6 +3544,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");