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