[fpdf_structtree] Support references for attribute list/number PDF software such as Adobe Acrobat Pro sometimes uses references for attribute lists (instead of array or dictionary). Similarly, attributes themselves (e.g. "ColSpan" for a TD or TH cell) sometimes use references as well. Change-Id: I1bd8f56348ba48d84b72179c86db688304660682 Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/110850 Reviewed-by: Lei Zhang <thestig@chromium.org> Commit-Queue: Ilaï Deutel <idtl@google.com>
diff --git a/fpdfsdk/fpdf_structtree.cpp b/fpdfsdk/fpdf_structtree.cpp index dc68239..4817f47 100644 --- a/fpdfsdk/fpdf_structtree.cpp +++ b/fpdfsdk/fpdf_structtree.cpp
@@ -135,6 +135,10 @@ if (!elem) return -1; RetainPtr<const CPDF_Object> attr_obj = elem->GetA(); + if (!attr_obj) { + return -1; + } + attr_obj = attr_obj->GetDirect(); if (!attr_obj) return -1; if (attr_obj->IsArray()) @@ -154,6 +158,10 @@ if (!attr_obj) return nullptr; + attr_obj = attr_obj->GetDirect(); + if (!attr_obj) { + return nullptr; + } if (attr_obj->IsDictionary()) { return index == 0 ? FPDFStructElementAttrFromCPDFDictionary( attr_obj->AsDictionary()) @@ -353,7 +361,7 @@ if (!dict) return false; - RetainPtr<const CPDF_Object> obj = dict->GetObjectFor(name); + RetainPtr<const CPDF_Object> obj = dict->GetDirectObjectFor(name); if (!obj || !obj->IsNumber()) return false;
diff --git a/fpdfsdk/fpdf_structtree_embeddertest.cpp b/fpdfsdk/fpdf_structtree_embeddertest.cpp index 1ee1612..2704887 100644 --- a/fpdfsdk/fpdf_structtree_embeddertest.cpp +++ b/fpdfsdk/fpdf_structtree_embeddertest.cpp
@@ -648,11 +648,12 @@ FPDF_STRUCTELEMENT td = FPDF_StructElement_GetChildAtIndex(tr, 1); ASSERT_TRUE(td); { + // Test counting and obtaining attributes via reference ASSERT_EQ(1, FPDF_StructElement_GetAttributeCount(td)); FPDF_STRUCTELEMENT_ATTR attr = FPDF_StructElement_GetAttributeAtIndex(td, 0); ASSERT_TRUE(attr); - ASSERT_EQ(3, FPDF_StructElement_Attr_GetCount(attr)); + ASSERT_EQ(4, FPDF_StructElement_Attr_GetCount(attr)); // Test string and blob type { char buffer[16] = {}; @@ -696,6 +697,23 @@ FPDF_StructElement_Attr_GetBooleanValue(attr, buffer, &val)); EXPECT_TRUE(val); } + + // Test reference to number + { + char buffer[16] = {}; + unsigned long out_len = ULONG_MAX; + ASSERT_TRUE(FPDF_StructElement_Attr_GetName( + attr, 3, buffer, sizeof(buffer), &out_len)); + EXPECT_EQ(8U, out_len); + EXPECT_STREQ("RowSpan", buffer); + + EXPECT_EQ(FPDF_OBJECT_REFERENCE, + FPDF_StructElement_Attr_GetType(attr, buffer)); + float val; + ASSERT_TRUE( + FPDF_StructElement_Attr_GetNumberValue(attr, buffer, &val)); + EXPECT_FLOAT_EQ(3, val); + } } } }
diff --git a/testing/resources/tagged_table.in b/testing/resources/tagged_table.in index ee298c5..6e2ddc0 100644 --- a/testing/resources/tagged_table.in +++ b/testing/resources/tagged_table.in
@@ -203,14 +203,22 @@ /S /TD /P 13 0 R /Pg 3 0 R - /A [<< - /O /Table - /ColProp (Sum) - /CurUSD true - >>] + /A 18 0 R /ID (node18) >> endobj +{{object 18 0}} [ + << + /O /Table + /ColProp (Sum) + /CurUSD true + /RowSpan 19 0 R + >> +] +endobj +{{object 19 0}} + 3 +endobj {{xref}} {{trailer}} {{startxref}}
diff --git a/testing/resources/tagged_table.pdf b/testing/resources/tagged_table.pdf index 4428682..6e2bf9e 100644 --- a/testing/resources/tagged_table.pdf +++ b/testing/resources/tagged_table.pdf
@@ -204,16 +204,24 @@ /S /TD /P 13 0 R /Pg 3 0 R - /A [<< - /O /Table - /ColProp (Sum) - /CurUSD true - >>] + /A 18 0 R /ID (node18) >> endobj +18 0 obj [ + << + /O /Table + /ColProp (Sum) + /CurUSD true + /RowSpan 19 0 R + >> +] +endobj +19 0 obj + 3 +endobj xref -0 18 +0 20 0000000000 65535 f 0000000015 00000 n 0000000145 00000 n @@ -232,10 +240,12 @@ 0000002276 00000 n 0000002366 00000 n 0000002513 00000 n +0000002615 00000 n +0000002715 00000 n trailer << /Root 1 0 R - /Size 18 + /Size 20 >> startxref -2683 +2735 %%EOF