drawinglayer/source/primitive2d/structuretagprimitive2d.cxx | 4 drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx | 27 +-- include/drawinglayer/primitive2d/structuretagprimitive2d.hxx | 6 include/svx/svdobj.hxx | 2 svx/source/sdr/contact/viewobjectcontact.cxx | 6 svx/source/svdraw/svdobj.cxx | 4 sw/inc/EnhancedPDFExportHelper.hxx | 6 sw/inc/dcontact.hxx | 2 sw/source/core/text/EnhancedPDFExportHelper.cxx | 86 +++++------ vcl/inc/pdf/pdfwriter_impl.hxx | 2 vcl/qa/cppunit/pdfexport/data/tdf154982.odt |binary vcl/qa/cppunit/pdfexport/pdfexport.cxx | 83 ++++++++++ vcl/source/gdi/pdfwriter_impl.cxx | 5 13 files changed, 152 insertions(+), 81 deletions(-)
New commits: commit 30bb38b041a44f6c30fcf0475b3cf2432dc7f5cb Author: Michael Stahl <michael.st...@allotropia.de> AuthorDate: Wed Jul 12 18:34:24 2023 +0200 Commit: خالد حسني <kha...@libreoffice.org> CommitDate: Wed Jul 26 14:40:24 2023 +0200 tdf#154982 drawinglayer,svx,sw,vcl: PDF export: hell flys and shapes... ... should be below their anchor paragraph in the structure tree. Refactor SwEnhancedPDFExportHelper (etc.) to use the new EnsureStructureElement()/InitStructureElement() functions instead of SetCurrentStructureElement() for the frames, and allow it for flys that don't have their anchor paragraphs created yet because the hell layer is exported before the document body. Change-Id: I1be3b54002e8196772e6f9d81dd0fd0c85b6e34b Reviewed-on: https://gerrit.libreoffice.org/c/core/+/154399 Tested-by: Jenkins Reviewed-by: Michael Stahl <michael.st...@allotropia.de> (cherry picked from commit d467f1aa3d028f399826c97e2eecedcd79efcf65) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/154427 Reviewed-by: خالد حسني <kha...@libreoffice.org> diff --git a/drawinglayer/source/primitive2d/structuretagprimitive2d.cxx b/drawinglayer/source/primitive2d/structuretagprimitive2d.cxx index 62da91ecc00f..47af55ab9b57 100644 --- a/drawinglayer/source/primitive2d/structuretagprimitive2d.cxx +++ b/drawinglayer/source/primitive2d/structuretagprimitive2d.cxx @@ -31,13 +31,13 @@ namespace drawinglayer::primitive2d bool bBackground, bool bIsImage, Primitive2DContainer&& aChildren, - sal_Int32 const nAnchorStructureElementId, + void const*const pAnchorStructureElementKey, ::std::vector<sal_Int32> const*const pAnnotIds) : GroupPrimitive2D(std::move(aChildren)), maStructureElement(rStructureElement), mbBackground(bBackground), mbIsImage(bIsImage) - , m_nAnchorStructureElementId(nAnchorStructureElementId) + , m_pAnchorStructureElementKey(pAnchorStructureElementKey) { if (pAnnotIds) { diff --git a/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx b/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx index 5e7b5523bad9..7f25b44e1761 100644 --- a/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx +++ b/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx @@ -2520,7 +2520,7 @@ void VclMetafileProcessor2D::processStructureTagPrimitive2D( // structured tag primitive const vcl::PDFWriter::StructElement& rTagElement(rStructureTagCandidate.getStructureElement()); bool bTagUsed((vcl::PDFWriter::NonStructElement != rTagElement)); - sal_Int32 nPreviousElement(-1); + bool bNeedEndAnchor(false); if (!rStructureTagCandidate.isTaggedSdrObject()) { @@ -2532,19 +2532,12 @@ void VclMetafileProcessor2D::processStructureTagPrimitive2D( // foreground object: tag as regular structure element if (!rStructureTagCandidate.isBackground()) { - if (rStructureTagCandidate.GetAnchorStructureElementId() != -1) + if (rStructureTagCandidate.GetAnchorStructureElementKey() != nullptr) { - auto const nTemp = mpPDFExtOutDevData->GetCurrentStructureElement(); - bool const bSuccess = mpPDFExtOutDevData->SetCurrentStructureElement( - rStructureTagCandidate.GetAnchorStructureElementId()); - if (bSuccess) - { - nPreviousElement = nTemp; - } - else - { - SAL_WARN("drawinglayer", "anchor structure element not found?"); - } + sal_Int32 const id = mpPDFExtOutDevData->EnsureStructureElement( + rStructureTagCandidate.GetAnchorStructureElementKey()); + mpPDFExtOutDevData->BeginStructureElement(id); + bNeedEndAnchor = true; } mpPDFExtOutDevData->WrapBeginStructureElement(rTagElement); switch (rTagElement) @@ -2620,13 +2613,9 @@ void VclMetafileProcessor2D::processStructureTagPrimitive2D( { // write end tag mpPDFExtOutDevData->EndStructureElement(); - if (nPreviousElement != -1) + if (bNeedEndAnchor) { -#ifndef NDEBUG - bool const bSuccess = -#endif - mpPDFExtOutDevData->SetCurrentStructureElement(nPreviousElement); - assert(bSuccess); + mpPDFExtOutDevData->EndStructureElement(); } } } diff --git a/include/drawinglayer/primitive2d/structuretagprimitive2d.hxx b/include/drawinglayer/primitive2d/structuretagprimitive2d.hxx index 8ee2b267b57f..0d7e6ba57735 100644 --- a/include/drawinglayer/primitive2d/structuretagprimitive2d.hxx +++ b/include/drawinglayer/primitive2d/structuretagprimitive2d.hxx @@ -50,7 +50,7 @@ namespace drawinglayer::primitive2d /// flag for image (OBJ_GRAF) bool mbIsImage; /// anchor structure element (Writer) - sal_Int32 m_nAnchorStructureElementId; + void const* m_pAnchorStructureElementKey; /// for Annot structure element, the ids of the annotations ::std::vector<sal_Int32> m_AnnotIds; @@ -61,7 +61,7 @@ namespace drawinglayer::primitive2d bool bBackground, bool bIsImage, Primitive2DContainer&& aChildren, - sal_Int32 nAnchorStructureElementId = -1, + void const* pAnchorStructureElementKey = nullptr, ::std::vector<sal_Int32> const* pAnnotIds = nullptr); /// data read access @@ -69,7 +69,7 @@ namespace drawinglayer::primitive2d bool isBackground() const { return mbBackground; } bool isImage() const { return mbIsImage; } bool isTaggedSdrObject() const; - sal_Int32 GetAnchorStructureElementId() const { return m_nAnchorStructureElementId; } + void const* GetAnchorStructureElementKey() const { return m_pAnchorStructureElementKey; } ::std::vector<sal_Int32> GetAnnotIds() const { return m_AnnotIds; } /// compare operator diff --git a/include/svx/svdobj.hxx b/include/svx/svdobj.hxx index 8dadf982b490..ed62c1db983f 100644 --- a/include/svx/svdobj.hxx +++ b/include/svx/svdobj.hxx @@ -129,7 +129,7 @@ class SVXCORE_DLLPUBLIC SdrObjUserCall public: virtual ~SdrObjUserCall(); virtual void Changed(const SdrObject& rObj, SdrUserCallType eType, const tools::Rectangle& rOldBoundRect); - virtual sal_Int32 GetPDFAnchorStructureElementId(SdrObject const& rObj); + virtual void const* GetPDFAnchorStructureElementKey(SdrObject const& rObj); }; class SVXCORE_DLLPUBLIC SdrObjMacroHitRec diff --git a/svx/source/sdr/contact/viewobjectcontact.cxx b/svx/source/sdr/contact/viewobjectcontact.cxx index fabf99a13d75..caac4a301042 100644 --- a/svx/source/sdr/contact/viewobjectcontact.cxx +++ b/svx/source/sdr/contact/viewobjectcontact.cxx @@ -436,10 +436,10 @@ drawinglayer::primitive2d::Primitive2DContainer const & ViewObjectContact::getPr const bool bBackground(pSdrPage->IsMasterPage()); const bool bImage(SdrObjKind::Graphic == pSdrObj->GetObjIdentifier()); // note: there must be output device here, in PDF export - sal_Int32 nAnchorId(-1); + void const* pAnchorKey(nullptr); if (auto const pUserCall = pSdrObj->GetUserCall()) { - nAnchorId = pUserCall->GetPDFAnchorStructureElementId(*pSdrObj); + pAnchorKey = pUserCall->GetPDFAnchorStructureElementKey(*pSdrObj); } ::std::vector<sal_Int32> annotIds; @@ -457,7 +457,7 @@ drawinglayer::primitive2d::Primitive2DContainer const & ViewObjectContact::getPr bBackground, bImage, std::move(xNewPrimitiveSequence), - nAnchorId, + pAnchorKey, &annotIds)); xNewPrimitiveSequence = drawinglayer::primitive2d::Primitive2DContainer { xReference }; } diff --git a/svx/source/svdraw/svdobj.cxx b/svx/source/svdraw/svdobj.cxx index 5c6eed5ab2fd..5c7789ee7ed0 100644 --- a/svx/source/svdraw/svdobj.cxx +++ b/svx/source/svdraw/svdobj.cxx @@ -136,9 +136,9 @@ void SdrObjUserCall::Changed(const SdrObject& /*rObj*/, SdrUserCallType /*eType* { } -sal_Int32 SdrObjUserCall::GetPDFAnchorStructureElementId(SdrObject const&) +void const* SdrObjUserCall::GetPDFAnchorStructureElementKey(SdrObject const&) { - return -1; + return nullptr; } SdrObjMacroHitRec::SdrObjMacroHitRec() : diff --git a/sw/inc/EnhancedPDFExportHelper.hxx b/sw/inc/EnhancedPDFExportHelper.hxx index e928e417a0f0..eee6496bd17d 100644 --- a/sw/inc/EnhancedPDFExportHelper.hxx +++ b/sw/inc/EnhancedPDFExportHelper.hxx @@ -187,7 +187,7 @@ typedef std::vector< IdMapEntry > LinkIdMap; typedef std::map< const SwTable*, TableColumnsMapEntry > TableColumnsMap; typedef std::map< const SwNumberTreeNode*, sal_Int32 > NumListIdMap; typedef std::map< const SwNumberTreeNode*, sal_Int32 > NumListBodyIdMap; -typedef std::map< const void*, sal_Int32 > FrameTagIdMap; +typedef std::set<const void*> FrameTagSet; class SwEnhancedPDFExportHelper { @@ -215,7 +215,7 @@ class SwEnhancedPDFExportHelper static LinkIdMap s_aLinkIdMap; static NumListIdMap s_aNumListIdMap; static NumListBodyIdMap s_aNumListBodyIdMap; - static FrameTagIdMap s_aFrameTagIdMap; + static FrameTagSet s_FrameTagSet; static LanguageType s_eLanguageDefault; @@ -247,7 +247,7 @@ class SwEnhancedPDFExportHelper static LinkIdMap& GetLinkIdMap() { return s_aLinkIdMap; } static NumListIdMap& GetNumListIdMap() {return s_aNumListIdMap; } static NumListBodyIdMap& GetNumListBodyIdMap() {return s_aNumListBodyIdMap; } - static FrameTagIdMap& GetFrameTagIdMap() { return s_aFrameTagIdMap; } + static FrameTagSet & GetFrameTagSet() { return s_FrameTagSet; } static LanguageType GetDefaultLanguage() {return s_eLanguageDefault; } diff --git a/sw/inc/dcontact.hxx b/sw/inc/dcontact.hxx index 20d99f4e7523..b4d501f44ccf 100644 --- a/sw/inc/dcontact.hxx +++ b/sw/inc/dcontact.hxx @@ -390,7 +390,7 @@ class SAL_DLLPUBLIC_RTTI SwDrawContact final : public SwContact /// Virtual methods of SdrObjUserCall. virtual void Changed(const SdrObject& rObj, SdrUserCallType eType, const tools::Rectangle& rOldBoundRect) override; - virtual sal_Int32 GetPDFAnchorStructureElementId(SdrObject const& rObj) override; + virtual void const* GetPDFAnchorStructureElementKey(SdrObject const& rObj) override; /** Used by Changed() and by UndoDraw. Notifies paragraphs that have to get out of the way. */ diff --git a/sw/source/core/text/EnhancedPDFExportHelper.cxx b/sw/source/core/text/EnhancedPDFExportHelper.cxx index 295281f8ac74..483597ca52b5 100644 --- a/sw/source/core/text/EnhancedPDFExportHelper.cxx +++ b/sw/source/core/text/EnhancedPDFExportHelper.cxx @@ -95,7 +95,7 @@ TableColumnsMap SwEnhancedPDFExportHelper::s_aTableColumnsMap; LinkIdMap SwEnhancedPDFExportHelper::s_aLinkIdMap; NumListIdMap SwEnhancedPDFExportHelper::s_aNumListIdMap; NumListBodyIdMap SwEnhancedPDFExportHelper::s_aNumListBodyIdMap; -FrameTagIdMap SwEnhancedPDFExportHelper::s_aFrameTagIdMap; +FrameTagSet SwEnhancedPDFExportHelper::s_FrameTagSet; LanguageType SwEnhancedPDFExportHelper::s_eLanguageDefault = LANGUAGE_SYSTEM; @@ -360,32 +360,16 @@ SwTaggedPDFHelper::~SwTaggedPDFHelper() #endif } -static auto GetReopenTagFromFrame(SwFrame const& rFrame) -> sal_Int32 -{ - void const*const pKey = lcl_GetKeyFromFrame(rFrame); - - if (pKey) - { - FrameTagIdMap const& rFrameTagIdMap(SwEnhancedPDFExportHelper::GetFrameTagIdMap()); - auto const it(rFrameTagIdMap.find(pKey)); - if (it != rFrameTagIdMap.end()) - { - return (*it).second; - } - } - return -1; -} - -sal_Int32 SwDrawContact::GetPDFAnchorStructureElementId(SdrObject const& rObj) +void const* SwDrawContact::GetPDFAnchorStructureElementKey(SdrObject const& rObj) { SwFrame const*const pAnchorFrame(GetAnchoredObj(&rObj)->GetAnchorFrame()); - return pAnchorFrame ? GetReopenTagFromFrame(*pAnchorFrame) : -1; + return pAnchorFrame ? lcl_GetKeyFromFrame(*pAnchorFrame) : nullptr; } bool SwTaggedPDFHelper::CheckReopenTag() { bool bRet = false; - sal_Int32 nReopenTag = -1; + void const* pReopenKey(nullptr); bool bContinue = false; // in some cases we just have to reopen a tag without early returning if ( mpFrameInfo ) @@ -422,21 +406,27 @@ bool SwTaggedPDFHelper::CheckReopenTag() if ( pKeyFrame ) { - nReopenTag = GetReopenTagFromFrame(*pKeyFrame); + void const*const pKey = lcl_GetKeyFromFrame(*pKeyFrame); + FrameTagSet& rFrameTagSet(SwEnhancedPDFExportHelper::GetFrameTagSet()); + if (rFrameTagSet.find(pKey) != rFrameTagSet.end() + || rFrame.IsFlyFrame()) // for hell layer flys + { + pReopenKey = pKey; + } } } - if ( -1 != nReopenTag ) + if (pReopenKey) { - m_nRestoreCurrentTag = mpPDFExtOutDevData->GetCurrentStructureElement(); - const bool bSuccess = mpPDFExtOutDevData->SetCurrentStructureElement( nReopenTag ); - OSL_ENSURE( bSuccess, "Failed to reopen tag" ); + sal_Int32 const id = mpPDFExtOutDevData->EnsureStructureElement(pReopenKey); + mpPDFExtOutDevData->BeginStructureElement(id); + ++m_nEndStructureElement; #if OSL_DEBUG_LEVEL > 1 aStructStack.push_back( 99 ); #endif - bRet = bSuccess; + bRet = true; } return bRet && !bContinue; @@ -457,8 +447,33 @@ void SwTaggedPDFHelper::CheckRestoreTag() const void SwTaggedPDFHelper::BeginTag( vcl::PDFWriter::StructElement eType, const OUString& rString ) { + void const* pKey(nullptr); + + if ( mpFrameInfo ) + { + const SwFrame& rFrame = mpFrameInfo->mrFrame; + + if ( ( rFrame.IsPageFrame() && !static_cast<const SwPageFrame&>(rFrame).GetPrev() ) || + ( rFrame.IsFlowFrame() && !SwFlowFrame::CastFlowFrame(&rFrame)->IsFollow() && SwFlowFrame::CastFlowFrame(&rFrame)->HasFollow() ) || + ( rFrame.IsTextFrame() && rFrame.GetDrawObjs() ) || + ( rFrame.IsRowFrame() && rFrame.IsInSplitTableRow() ) || + ( rFrame.IsCellFrame() && const_cast<SwFrame&>(rFrame).GetNextCellLeaf() ) ) + { + pKey = lcl_GetKeyFromFrame(rFrame); + + if (pKey) + { + FrameTagSet& rFrameTagSet(SwEnhancedPDFExportHelper::GetFrameTagSet()); + assert(rFrameTagSet.find(pKey) == rFrameTagSet.end()); + rFrameTagSet.emplace(pKey); + } + } + } + // write new tag - const sal_Int32 nId = mpPDFExtOutDevData->WrapBeginStructureElement( eType, rString ); + const sal_Int32 nId = mpPDFExtOutDevData->EnsureStructureElement(pKey); + mpPDFExtOutDevData->InitStructureElement(nId, eType, rString); + mpPDFExtOutDevData->BeginStructureElement(nId); ++m_nEndStructureElement; #if OSL_DEBUG_LEVEL > 1 @@ -502,21 +517,6 @@ void SwTaggedPDFHelper::BeginTag( vcl::PDFWriter::StructElement eType, const OUS NumListBodyIdMap& rNumListBodyIdMap = SwEnhancedPDFExportHelper::GetNumListBodyIdMap(); rNumListBodyIdMap[ pNodeNum ] = nId; } - - if ( ( rFrame.IsPageFrame() && !static_cast<const SwPageFrame&>(rFrame).GetPrev() ) || - ( rFrame.IsFlowFrame() && !SwFlowFrame::CastFlowFrame(&rFrame)->IsFollow() && SwFlowFrame::CastFlowFrame(&rFrame)->HasFollow() ) || - ( rFrame.IsTextFrame() && rFrame.GetDrawObjs() ) || - ( rFrame.IsRowFrame() && rFrame.IsInSplitTableRow() ) || - ( rFrame.IsCellFrame() && const_cast<SwFrame&>(rFrame).GetNextCellLeaf() ) ) - { - const void* pKey = lcl_GetKeyFromFrame( rFrame ); - - if ( pKey ) - { - FrameTagIdMap& rFrameTagIdMap = SwEnhancedPDFExportHelper::GetFrameTagIdMap(); - rFrameTagIdMap[ pKey ] = nId; - } - } } SetAttributes( eType ); @@ -1688,7 +1688,7 @@ SwEnhancedPDFExportHelper::SwEnhancedPDFExportHelper( SwEditShell& rSh, s_aLinkIdMap.clear(); s_aNumListIdMap.clear(); s_aNumListBodyIdMap.clear(); - s_aFrameTagIdMap.clear(); + s_FrameTagSet.clear(); #if OSL_DEBUG_LEVEL > 1 aStructStack.clear(); diff --git a/vcl/inc/pdf/pdfwriter_impl.hxx b/vcl/inc/pdf/pdfwriter_impl.hxx index 8c232589e9c7..edf88459b4f4 100644 --- a/vcl/inc/pdf/pdfwriter_impl.hxx +++ b/vcl/inc/pdf/pdfwriter_impl.hxx @@ -28,6 +28,7 @@ #include <memory> #include <string_view> #include <vector> +#include <stack> #include <pdf/ResourceDict.hxx> #include <pdf/BitmapID.hxx> @@ -762,6 +763,7 @@ private: /* current object in the structure hierarchy */ sal_Int32 m_nCurrentStructElement; + std::stack<sal_Int32> m_StructElementStack; /* structure parent tree */ std::vector< OString > m_aStructParentTree; /* emit structure marks currently (aka. NonStructElement or not) diff --git a/vcl/qa/cppunit/pdfexport/data/tdf154982.odt b/vcl/qa/cppunit/pdfexport/data/tdf154982.odt new file mode 100644 index 000000000000..a35ffb861abe Binary files /dev/null and b/vcl/qa/cppunit/pdfexport/data/tdf154982.odt differ diff --git a/vcl/qa/cppunit/pdfexport/pdfexport.cxx b/vcl/qa/cppunit/pdfexport/pdfexport.cxx index a78ea33e38ba..4cf87ee6c994 100644 --- a/vcl/qa/cppunit/pdfexport/pdfexport.cxx +++ b/vcl/qa/cppunit/pdfexport/pdfexport.cxx @@ -3596,20 +3596,20 @@ CPPUNIT_TEST_FIXTURE(PdfExportTest, testTdf57423) { switch (nFigure) { - case 0: + case 2: CPPUNIT_ASSERT_EQUAL(OUString(u"QR Code - Tells how to get to Mosegaard"), ::vcl::filter::PDFDocument::DecodeHexStringUTF16BE( *dynamic_cast<vcl::filter::PDFHexStringElement*>( pObject->Lookup("Alt")))); break; - case 1: + case 0: CPPUNIT_ASSERT_EQUAL(OUString(u"Title: Arrows - Description: Explains the " u"different arrow appearances"), ::vcl::filter::PDFDocument::DecodeHexStringUTF16BE( *dynamic_cast<vcl::filter::PDFHexStringElement*>( pObject->Lookup("Alt")))); break; - case 2: + case 1: CPPUNIT_ASSERT_EQUAL( OUString(u"My blue triangle - Does not need further description"), ::vcl::filter::PDFDocument::DecodeHexStringUTF16BE( @@ -3664,6 +3664,83 @@ CPPUNIT_TEST_FIXTURE(PdfExportTest, testTdf57423) CPPUNIT_ASSERT_EQUAL(int(4), nDiv); } +CPPUNIT_TEST_FIXTURE(PdfExportTest, testTdf154982) +{ + 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"tdf154982.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()); + + int nFigure(0); + for (const auto& rDocElement : aDocument.GetElements()) + { + auto pObject = dynamic_cast<vcl::filter::PDFObjectElement*>(rDocElement.get()); + if (!pObject) + continue; + auto pType = dynamic_cast<vcl::filter::PDFNameElement*>(pObject->Lookup("Type")); + if (pType && pType->GetValue() == "StructElem") + { + auto pS = dynamic_cast<vcl::filter::PDFNameElement*>(pObject->Lookup("S")); + if (pS && pS->GetValue() == "Figure") + { + switch (nFigure) + { + case 0: + CPPUNIT_ASSERT_EQUAL( + OUString(u"Here comes the signature - Please sign here"), + ::vcl::filter::PDFDocument::DecodeHexStringUTF16BE( + *dynamic_cast<vcl::filter::PDFHexStringElement*>( + pObject->Lookup("Alt")))); + break; + case 1: + CPPUNIT_ASSERT_EQUAL(OUString(u"Home"), + ::vcl::filter::PDFDocument::DecodeHexStringUTF16BE( + *dynamic_cast<vcl::filter::PDFHexStringElement*>( + pObject->Lookup("Alt")))); + break; + } + + // the problem was that the figures in the hell layer were not + // below their anchor paragraphs in the structure tree + auto pParentRef + = dynamic_cast<vcl::filter::PDFReferenceElement*>(pObject->Lookup("P")); + CPPUNIT_ASSERT(pParentRef); + auto pParent(pParentRef->LookupObject()); + CPPUNIT_ASSERT(pParent); + auto pParentType + = dynamic_cast<vcl::filter::PDFNameElement*>(pParent->Lookup("Type")); + CPPUNIT_ASSERT_EQUAL(OString("StructElem"), pParentType->GetValue()); + auto pParentS = dynamic_cast<vcl::filter::PDFNameElement*>(pParent->Lookup("S")); + CPPUNIT_ASSERT_EQUAL(OString("Standard"), pParentS->GetValue()); + + auto pPParentRef + = dynamic_cast<vcl::filter::PDFReferenceElement*>(pParent->Lookup("P")); + CPPUNIT_ASSERT(pPParentRef); + auto pPParent(pPParentRef->LookupObject()); + CPPUNIT_ASSERT(pPParent); + auto pPParentType + = dynamic_cast<vcl::filter::PDFNameElement*>(pPParent->Lookup("Type")); + CPPUNIT_ASSERT_EQUAL(OString("StructElem"), pPParentType->GetValue()); + auto pPParentS = dynamic_cast<vcl::filter::PDFNameElement*>(pPParent->Lookup("S")); + CPPUNIT_ASSERT_EQUAL(OString("Document"), pPParentS->GetValue()); + ++nFigure; + } + } + } + CPPUNIT_ASSERT_EQUAL(int(2), nFigure); +} + CPPUNIT_TEST_FIXTURE(PdfExportTest, testTdf135192) { aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export"); diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx index 93ff4c100619..2c7642817f4d 100644 --- a/vcl/source/gdi/pdfwriter_impl.cxx +++ b/vcl/source/gdi/pdfwriter_impl.cxx @@ -1233,6 +1233,7 @@ PDFWriterImpl::PDFWriterImpl( const PDFWriter::PDFWriterContext& rContext, m_aStructure.emplace_back( ); m_aStructure[0].m_nOwnElement = 0; m_aStructure[0].m_nParentElement = 0; + //m_StructElementStack.push(0); Font aFont; aFont.SetFamilyName( "Times" ); @@ -10887,6 +10888,7 @@ void PDFWriterImpl::beginStructureElement(sal_Int32 const id) endStructureElementMCSeq(EndMode::OnlyStruct); PDFStructureElement& rEle = m_aStructure[id]; + m_StructElementStack.push(m_nCurrentStructElement); m_nCurrentStructElement = id; if (g_bDebugDisableCompression) @@ -10946,7 +10948,8 @@ void PDFWriterImpl::endStructureElement() } // "end" the structure element, the parent becomes current element - m_nCurrentStructElement = m_aStructure[ m_nCurrentStructElement ].m_nParentElement; + m_nCurrentStructElement = m_StructElementStack.top(); + m_StructElementStack.pop(); // check whether to emit structure henceforth m_bEmitStructure = checkEmitStructure();