drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx | 10 - sw/source/core/text/EnhancedPDFExportHelper.cxx | 10 + vcl/qa/cppunit/pdfexport/pdfexport.cxx | 77 ++++++++++++- vcl/source/gdi/pdfextoutdevdata.cxx | 3 4 files changed, 91 insertions(+), 9 deletions(-)
New commits: commit a8f522f4257729ea11178ebf165fdd3a2b7be240 Author: Michael Stahl <michael.st...@allotropia.de> AuthorDate: Mon Oct 2 20:33:42 2023 +0200 Commit: Michael Stahl <michael.st...@allotropia.de> CommitDate: Wed Oct 4 11:42:58 2023 +0200 vcl,drawinglayer,sw: PDF/UA export: footnote-container-in-list problem The problem is that if there is a footnote in a list, the footnote container becomes a child of the LI element that contains the footnote anchor, which is of course nonsense. This is because SwTaggedPDFHelper::CheckReopenTag() stopped using SetCurrentStructureElement(), but unfortunately it's required so that once the list ends, the correct parent element is restored for whatever follows the list. There is a similar problem in VclMetafileProcessor2D. (regression from commit d467f1aa3d028f399826c97e2eecedcd79efcf65) Change-Id: I03dee5dc2e11accb97279e5f325808c5b85507a1 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/157501 Tested-by: Jenkins Reviewed-by: Michael Stahl <michael.st...@allotropia.de> diff --git a/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx b/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx index 1a7beb8affc6..d87c70c7e772 100644 --- a/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx +++ b/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx @@ -2527,7 +2527,7 @@ void VclMetafileProcessor2D::processStructureTagPrimitive2D( // structured tag primitive const vcl::PDFWriter::StructElement& rTagElement(rStructureTagCandidate.getStructureElement()); bool bTagUsed((vcl::PDFWriter::NonStructElement != rTagElement)); - bool bNeedEndAnchor(false); + ::std::optional<sal_Int32> oAnchorParent; if (!rStructureTagCandidate.isTaggedSdrObject()) { @@ -2543,8 +2543,8 @@ void VclMetafileProcessor2D::processStructureTagPrimitive2D( { sal_Int32 const id = mpPDFExtOutDevData->EnsureStructureElement( rStructureTagCandidate.GetAnchorStructureElementKey()); - mpPDFExtOutDevData->BeginStructureElement(id); - bNeedEndAnchor = true; + oAnchorParent.emplace(mpPDFExtOutDevData->GetCurrentStructureElement()); + mpPDFExtOutDevData->SetCurrentStructureElement(id); } mpPDFExtOutDevData->WrapBeginStructureElement(rTagElement); switch (rTagElement) @@ -2620,9 +2620,9 @@ void VclMetafileProcessor2D::processStructureTagPrimitive2D( { // write end tag mpPDFExtOutDevData->EndStructureElement(); - if (bNeedEndAnchor) + if (oAnchorParent) { - mpPDFExtOutDevData->EndStructureElement(); + mpPDFExtOutDevData->SetCurrentStructureElement(*oAnchorParent); } } } diff --git a/sw/source/core/text/EnhancedPDFExportHelper.cxx b/sw/source/core/text/EnhancedPDFExportHelper.cxx index 3103b3fe9ef8..9ebc233dc687 100644 --- a/sw/source/core/text/EnhancedPDFExportHelper.cxx +++ b/sw/source/core/text/EnhancedPDFExportHelper.cxx @@ -458,7 +458,15 @@ bool SwTaggedPDFHelper::CheckReopenTag() if (pReopenKey) { - OpenTagImpl(pReopenKey); + // note: it would be possible to get rid of the SetCurrentStructureElement() + // - which is quite ugly - for most cases by recreating the parents until the + // current ancestor, but there are special cases cell frame rowspan > 1 follow + // and footnote frame follow where the parent of the follow is different from + // the parent of the first one, and so in PDFExtOutDevData the wrong parent + // would be restored and used for next elements. + m_nRestoreCurrentTag = mpPDFExtOutDevData->GetCurrentStructureElement(); + sal_Int32 const id = mpPDFExtOutDevData->EnsureStructureElement(pReopenKey); + mpPDFExtOutDevData->SetCurrentStructureElement(id); bRet = true; } diff --git a/vcl/qa/cppunit/pdfexport/pdfexport.cxx b/vcl/qa/cppunit/pdfexport/pdfexport.cxx index a07ceeb53eae..9709d9c57313 100644 --- a/vcl/qa/cppunit/pdfexport/pdfexport.cxx +++ b/vcl/qa/cppunit/pdfexport/pdfexport.cxx @@ -3733,7 +3733,7 @@ CPPUNIT_TEST_FIXTURE(PdfExportTest, testSpans) CPPUNIT_ASSERT(pKids1); // assume there are no MCID ref at this level auto vKids1 = pKids1->GetElements(); - CPPUNIT_ASSERT_EQUAL(size_t(1), vKids1.size()); + CPPUNIT_ASSERT_EQUAL(size_t(2), vKids1.size()); auto pRefKid10 = dynamic_cast<vcl::filter::PDFReferenceElement*>(vKids1[0]); CPPUNIT_ASSERT(pRefKid10); auto pObject10 = pRefKid10->LookupObject(); @@ -3868,8 +3868,7 @@ CPPUNIT_TEST_FIXTURE(PdfExportTest, testSpans) CPPUNIT_ASSERT(pKids1011); // assume there are no MCID ref at this level auto vKids1011 = pKids1011->GetElements(); - //CPPUNIT_ASSERT_EQUAL(size_t(1), vKids1011.size()); - //FIXME Div ??? + CPPUNIT_ASSERT_EQUAL(size_t(1), vKids1011.size()); auto pRefKid10110 = dynamic_cast<vcl::filter::PDFReferenceElement*>(vKids1011[0]); CPPUNIT_ASSERT(pRefKid10110); @@ -4077,6 +4076,78 @@ CPPUNIT_TEST_FIXTURE(PdfExportTest, testSpans) pDictA103101->LookupElement("TextDecorationType")) ->GetValue()); + // now the footnote container - following the list + auto pRefKid11 = dynamic_cast<vcl::filter::PDFReferenceElement*>(vKids1[1]); + CPPUNIT_ASSERT(pRefKid11); + auto pObject11 = pRefKid11->LookupObject(); + CPPUNIT_ASSERT(pObject11); + auto pType11 + = dynamic_cast<vcl::filter::PDFNameElement*>(pObject11->Lookup("Type")); + CPPUNIT_ASSERT_EQUAL(OString("StructElem"), pType11->GetValue()); + auto pS11 = dynamic_cast<vcl::filter::PDFNameElement*>(pObject11->Lookup("S")); + CPPUNIT_ASSERT_EQUAL(OString("Div"), pS11->GetValue()); + + auto pKids11 = dynamic_cast<vcl::filter::PDFArrayElement*>(pObject11->Lookup("K")); + CPPUNIT_ASSERT(pKids11); + // assume there are no MCID ref at this level + auto vKids11 = pKids11->GetElements(); + CPPUNIT_ASSERT_EQUAL(size_t(1), vKids11.size()); + + auto pRefKid110 = dynamic_cast<vcl::filter::PDFReferenceElement*>(vKids11[0]); + CPPUNIT_ASSERT(pRefKid110); + auto pObject110 = pRefKid110->LookupObject(); + CPPUNIT_ASSERT(pObject110); + auto pType110 + = dynamic_cast<vcl::filter::PDFNameElement*>(pObject110->Lookup("Type")); + CPPUNIT_ASSERT_EQUAL(OString("StructElem"), pType110->GetValue()); + auto pS110 = dynamic_cast<vcl::filter::PDFNameElement*>(pObject110->Lookup("S")); + CPPUNIT_ASSERT_EQUAL(OString("Note"), pS110->GetValue()); + + auto pKids110 + = dynamic_cast<vcl::filter::PDFArrayElement*>(pObject110->Lookup("K")); + CPPUNIT_ASSERT(pKids110); + // assume there are no MCID ref at this level + auto vKids110 = pKids110->GetElements(); + CPPUNIT_ASSERT_EQUAL(size_t(2), vKids110.size()); + + auto pRefKid1100 = dynamic_cast<vcl::filter::PDFReferenceElement*>(vKids110[0]); + CPPUNIT_ASSERT(pRefKid1100); + auto pObject1100 = pRefKid1100->LookupObject(); + CPPUNIT_ASSERT(pObject1100); + auto pType1100 + = dynamic_cast<vcl::filter::PDFNameElement*>(pObject1100->Lookup("Type")); + CPPUNIT_ASSERT_EQUAL(OString("StructElem"), pType1100->GetValue()); + auto pS1100 = dynamic_cast<vcl::filter::PDFNameElement*>(pObject1100->Lookup("S")); + CPPUNIT_ASSERT_EQUAL(OString("Lbl"), pS1100->GetValue()); + + auto pKids1100 + = dynamic_cast<vcl::filter::PDFArrayElement*>(pObject1100->Lookup("K")); + CPPUNIT_ASSERT(pKids1100); + // assume there are no MCID ref at this level + auto vKids1100 = pKids1100->GetElements(); + CPPUNIT_ASSERT_EQUAL(size_t(1), vKids1100.size()); + + auto pRefKid11000 = dynamic_cast<vcl::filter::PDFReferenceElement*>(vKids1100[0]); + CPPUNIT_ASSERT(pRefKid11000); + auto pObject11000 = pRefKid11000->LookupObject(); + CPPUNIT_ASSERT(pObject11000); + auto pType11000 + = dynamic_cast<vcl::filter::PDFNameElement*>(pObject11000->Lookup("Type")); + CPPUNIT_ASSERT_EQUAL(OString("StructElem"), pType11000->GetValue()); + auto pS11000 + = dynamic_cast<vcl::filter::PDFNameElement*>(pObject11000->Lookup("S")); + CPPUNIT_ASSERT_EQUAL(OString("Link"), pS11000->GetValue()); + + auto pRefKid1101 = dynamic_cast<vcl::filter::PDFReferenceElement*>(vKids110[1]); + CPPUNIT_ASSERT(pRefKid1101); + auto pObject1101 = pRefKid1101->LookupObject(); + CPPUNIT_ASSERT(pObject1101); + auto pType1101 + = dynamic_cast<vcl::filter::PDFNameElement*>(pObject1101->Lookup("Type")); + CPPUNIT_ASSERT_EQUAL(OString("StructElem"), pType1101->GetValue()); + auto pS1101 = dynamic_cast<vcl::filter::PDFNameElement*>(pObject1101->Lookup("S")); + CPPUNIT_ASSERT_EQUAL(OString("Footnote"), pS1101->GetValue()); + ++nDoc; } } diff --git a/vcl/source/gdi/pdfextoutdevdata.cxx b/vcl/source/gdi/pdfextoutdevdata.cxx index b110557e67d7..7719d6bb97d1 100644 --- a/vcl/source/gdi/pdfextoutdevdata.cxx +++ b/vcl/source/gdi/pdfextoutdevdata.cxx @@ -828,6 +828,9 @@ void PDFExtOutDevData::InitStructureElement(sal_Int32 const id, mpPageSyncData->mParaInts.push_back(id); mpPageSyncData->mParaStructElements.push_back( eType ); mpPageSyncData->mParaOUStrings.push_back( rAlias ); + // update parent: required for hell fly anchor frames in sw, so that on the actual + // anchor frame EndStructureElement() resets mCurrentStructElement properly. + mpGlobalSyncData->mStructParents[id] = mpGlobalSyncData->mCurrentStructElement; } void PDFExtOutDevData::BeginStructureElement(sal_Int32 const id)