Add FPDF_StructElement_GetParent Get the parent of the structure element. Change-Id: I7714fd896a27ea42848d643349e868714afc7da5 Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/90433 Reviewed-by: Lei Zhang <thestig@chromium.org> Commit-Queue: Lei Zhang <thestig@chromium.org>
diff --git a/core/fpdfdoc/cpdf_structelement.cpp b/core/fpdfdoc/cpdf_structelement.cpp index dda016b..c9f1161 100644 --- a/core/fpdfdoc/cpdf_structelement.cpp +++ b/core/fpdfdoc/cpdf_structelement.cpp
@@ -47,7 +47,13 @@ LoadKids(m_pDict.Get()); } -CPDF_StructElement::~CPDF_StructElement() = default; +CPDF_StructElement::~CPDF_StructElement() { + for (auto& kid : m_Kids) { + if (kid.m_Type == Kid::kElement) { + kid.m_pElement->SetParent(nullptr); + } + } +} ByteString CPDF_StructElement::GetObjType() const { return GetDict()->GetStringFor("Type");
diff --git a/core/fpdfdoc/cpdf_structelement.h b/core/fpdfdoc/cpdf_structelement.h index efeb2dc..c34f000 100644 --- a/core/fpdfdoc/cpdf_structelement.h +++ b/core/fpdfdoc/cpdf_structelement.h
@@ -35,6 +35,11 @@ bool UpdateKidIfElement(const CPDF_Dictionary* pDict, CPDF_StructElement* pElement); + CPDF_StructElement* GetParent() const { return m_pParentElement.Get(); } + void SetParent(CPDF_StructElement* pParentElement) { + m_pParentElement = pParentElement; + } + private: struct Kid { enum Type { kInvalid, kElement, kPageContent, kStreamContent, kObject }; @@ -60,6 +65,7 @@ UnownedPtr<const CPDF_StructTree> const m_pTree; RetainPtr<const CPDF_Dictionary> const m_pDict; + UnownedPtr<CPDF_StructElement> m_pParentElement; const ByteString m_Type; std::vector<Kid> m_Kids; };
diff --git a/core/fpdfdoc/cpdf_structtree.cpp b/core/fpdfdoc/cpdf_structtree.cpp index 6519e1c..133cf5a 100644 --- a/core/fpdfdoc/cpdf_structtree.cpp +++ b/core/fpdfdoc/cpdf_structtree.cpp
@@ -110,6 +110,8 @@ if (!pParentElement->UpdateKidIfElement(pDict, pElement.Get())) map->erase(pDict); + pElement->SetParent(pParentElement.Get()); + return pElement; }
diff --git a/fpdfsdk/fpdf_structtree.cpp b/fpdfsdk/fpdf_structtree.cpp index a8800cd..e429e68 100644 --- a/fpdfsdk/fpdf_structtree.cpp +++ b/fpdfsdk/fpdf_structtree.cpp
@@ -207,3 +207,14 @@ return FPDFStructElementFromCPDFStructElement(elem->GetKidIfElement(index)); } + +FPDF_EXPORT FPDF_STRUCTELEMENT FPDF_CALLCONV +FPDF_StructElement_GetParent(FPDF_STRUCTELEMENT struct_element) { + CPDF_StructElement* elem = + CPDFStructElementFromFPDFStructElement(struct_element); + CPDF_StructElement* parent = elem ? elem->GetParent() : nullptr; + if (!parent) { + return nullptr; + } + return FPDFStructElementFromCPDFStructElement(parent); +}
diff --git a/fpdfsdk/fpdf_structtree_embeddertest.cpp b/fpdfsdk/fpdf_structtree_embeddertest.cpp index bc26022..5ba2bfe 100644 --- a/fpdfsdk/fpdf_structtree_embeddertest.cpp +++ b/fpdfsdk/fpdf_structtree_embeddertest.cpp
@@ -420,6 +420,38 @@ UnloadPage(page); } +TEST_F(FPDFStructTreeEmbedderTest, GetParent) { + ASSERT_TRUE(OpenDocument("tagged_alt_text.pdf")); + FPDF_PAGE page = LoadPage(0); + ASSERT_TRUE(page); + + { + ScopedFPDFStructTree struct_tree(FPDF_StructTree_GetForPage(page)); + ASSERT_TRUE(struct_tree); + ASSERT_EQ(1, FPDF_StructTree_CountChildren(struct_tree.get())); + + FPDF_STRUCTELEMENT parent = + FPDF_StructTree_GetChildAtIndex(struct_tree.get(), 0); + ASSERT_TRUE(parent); + + ASSERT_EQ(1, FPDF_StructElement_CountChildren(parent)); + + FPDF_STRUCTELEMENT child = FPDF_StructElement_GetChildAtIndex(parent, 0); + ASSERT_TRUE(child); + + // test nullptr inputs + ASSERT_EQ(nullptr, FPDF_StructElement_GetParent(nullptr)); + + ASSERT_EQ(parent, FPDF_StructElement_GetParent(child)); + + // The parent of `parent` is StructTreeRoot and no longer a StructElement. + // We currently handle this case by returning a nullptr. + ASSERT_EQ(nullptr, FPDF_StructElement_GetParent(parent)); + } + + UnloadPage(page); +} + TEST_F(FPDFStructTreeEmbedderTest, GetTitle) { ASSERT_TRUE(OpenDocument("tagged_alt_text.pdf")); FPDF_PAGE page = LoadPage(0);
diff --git a/fpdfsdk/fpdf_view_c_api_test.c b/fpdfsdk/fpdf_view_c_api_test.c index 3d75908..f078104 100644 --- a/fpdfsdk/fpdf_view_c_api_test.c +++ b/fpdfsdk/fpdf_view_c_api_test.c
@@ -360,6 +360,7 @@ CHK(FPDF_StructElement_GetLang); CHK(FPDF_StructElement_GetMarkedContentID); CHK(FPDF_StructElement_GetObjType); + CHK(FPDF_StructElement_GetParent); CHK(FPDF_StructElement_GetStringAttribute); CHK(FPDF_StructElement_GetTitle); CHK(FPDF_StructElement_GetType);
diff --git a/public/fpdf_structtree.h b/public/fpdf_structtree.h index 8daccdb..1485bb0 100644 --- a/public/fpdf_structtree.h +++ b/public/fpdf_structtree.h
@@ -254,6 +254,19 @@ FPDF_StructElement_GetChildAtIndex(FPDF_STRUCTELEMENT struct_element, int index); +// Experimental API. +// Function: FPDF_StructElement_GetParent +// Get the parent of the structure element. +// Parameters: +// struct_tree - Handle to the struct element. +// Return value: +// The parent structure element or NULL on error. +// Comments: +// If structure element is StructTreeRoot, then this function will +// return NULL. +FPDF_EXPORT FPDF_STRUCTELEMENT FPDF_CALLCONV +FPDF_StructElement_GetParent(FPDF_STRUCTELEMENT struct_element); + #ifdef __cplusplus } // extern "C" #endif