Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
fpdf_structtree_embeddertest.cpp
Go to the documentation of this file.
1// Copyright 2016 The PDFium Authors
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <iterator>
6
7#include "public/fpdf_structtree.h"
8#include "testing/embedder_test.h"
9#include "testing/fx_string_testhelpers.h"
10#include "third_party/abseil-cpp/absl/types/optional.h"
11
13
15 ASSERT_TRUE(OpenDocument("tagged_alt_text.pdf"));
16 FPDF_PAGE page = LoadPage(0);
17 ASSERT_TRUE(page);
18
19 {
20 ScopedFPDFStructTree struct_tree(FPDF_StructTree_GetForPage(page));
21 ASSERT_TRUE(struct_tree);
22 ASSERT_EQ(1, FPDF_StructTree_CountChildren(struct_tree.get()));
23
24 FPDF_STRUCTELEMENT element =
25 FPDF_StructTree_GetChildAtIndex(struct_tree.get(), -1);
26 EXPECT_FALSE(element);
27 element = FPDF_StructTree_GetChildAtIndex(struct_tree.get(), 1);
28 EXPECT_FALSE(element);
29 element = FPDF_StructTree_GetChildAtIndex(struct_tree.get(), 0);
30 ASSERT_TRUE(element);
31 EXPECT_EQ(-1, FPDF_StructElement_GetMarkedContentID(element));
32 EXPECT_EQ(0U, FPDF_StructElement_GetAltText(element, nullptr, 0));
33
34 ASSERT_EQ(1, FPDF_StructElement_CountChildren(element));
35 FPDF_STRUCTELEMENT child_element =
37 EXPECT_FALSE(child_element);
38 child_element = FPDF_StructElement_GetChildAtIndex(element, 1);
39 EXPECT_FALSE(child_element);
40 child_element = FPDF_StructElement_GetChildAtIndex(element, 0);
41 ASSERT_TRUE(child_element);
42 EXPECT_EQ(-1, FPDF_StructElement_GetMarkedContentID(child_element));
43 EXPECT_EQ(0U, FPDF_StructElement_GetAltText(child_element, nullptr, 0));
44
45 ASSERT_EQ(1, FPDF_StructElement_CountChildren(child_element));
46 FPDF_STRUCTELEMENT gchild_element =
48 EXPECT_FALSE(gchild_element);
49 gchild_element = FPDF_StructElement_GetChildAtIndex(child_element, 1);
50 EXPECT_FALSE(gchild_element);
51 gchild_element = FPDF_StructElement_GetChildAtIndex(child_element, 0);
52 ASSERT_TRUE(gchild_element);
53 EXPECT_EQ(-1, FPDF_StructElement_GetMarkedContentID(gchild_element));
54 ASSERT_EQ(24U, FPDF_StructElement_GetAltText(gchild_element, nullptr, 0));
55
56 unsigned short buffer[12];
57 memset(buffer, 0, sizeof(buffer));
58 // Deliberately pass in a small buffer size to make sure |buffer| remains
59 // untouched.
60 ASSERT_EQ(24U, FPDF_StructElement_GetAltText(gchild_element, buffer, 1));
61 for (size_t i = 0; i < std::size(buffer); ++i)
62 EXPECT_EQ(0U, buffer[i]);
63
64 EXPECT_EQ(-1, FPDF_StructElement_GetMarkedContentID(gchild_element));
65 ASSERT_EQ(24U, FPDF_StructElement_GetAltText(gchild_element, buffer,
66 sizeof(buffer)));
67 EXPECT_EQ(L"Black Image", GetPlatformWString(buffer));
68
69 ASSERT_EQ(1, FPDF_StructElement_CountChildren(gchild_element));
70 FPDF_STRUCTELEMENT ggchild_element =
72 EXPECT_FALSE(ggchild_element);
73 }
74
75 UnloadPage(page);
76}
77
79 ASSERT_TRUE(OpenDocument("tagged_actual_text.pdf"));
80 FPDF_PAGE page = LoadPage(0);
81 ASSERT_TRUE(page);
82
83 {
84 ScopedFPDFStructTree struct_tree(FPDF_StructTree_GetForPage(page));
85 ASSERT_TRUE(struct_tree);
86 ASSERT_EQ(1, FPDF_StructTree_CountChildren(struct_tree.get()));
87
88 EXPECT_EQ(0U, FPDF_StructElement_GetActualText(nullptr, nullptr, 0));
89
90 FPDF_STRUCTELEMENT element =
91 FPDF_StructTree_GetChildAtIndex(struct_tree.get(), 0);
92 ASSERT_TRUE(element);
93 EXPECT_EQ(0U, FPDF_StructElement_GetActualText(element, nullptr, 0));
94
95 ASSERT_EQ(1, FPDF_StructElement_CountChildren(element));
96 FPDF_STRUCTELEMENT child_element =
98 ASSERT_TRUE(child_element);
99 EXPECT_EQ(0U, FPDF_StructElement_GetActualText(child_element, nullptr, 0));
100
101 ASSERT_EQ(1, FPDF_StructElement_CountChildren(child_element));
102 FPDF_STRUCTELEMENT gchild_element =
104 ASSERT_TRUE(gchild_element);
105 ASSERT_EQ(24U,
106 FPDF_StructElement_GetActualText(gchild_element, nullptr, 0));
107
108 unsigned short buffer[12] = {};
109 // Deliberately pass in a small buffer size to make sure |buffer| remains
110 // untouched.
111 ASSERT_EQ(24U, FPDF_StructElement_GetActualText(gchild_element, buffer, 1));
112 for (size_t i = 0; i < std::size(buffer); ++i)
113 EXPECT_EQ(0U, buffer[i]);
114 ASSERT_EQ(24U, FPDF_StructElement_GetActualText(gchild_element, buffer,
115 sizeof(buffer)));
116 EXPECT_EQ(L"Actual Text", GetPlatformWString(buffer));
117 }
118
119 UnloadPage(page);
120}
121
123 ASSERT_TRUE(OpenDocument("tagged_table.pdf"));
124 FPDF_PAGE page = LoadPage(0);
125 ASSERT_TRUE(page);
126
127 {
128 ScopedFPDFStructTree struct_tree(FPDF_StructTree_GetForPage(page));
129 ASSERT_TRUE(struct_tree);
130 ASSERT_EQ(1, FPDF_StructTree_CountChildren(struct_tree.get()));
131
132 FPDF_STRUCTELEMENT document =
133 FPDF_StructTree_GetChildAtIndex(struct_tree.get(), 0);
134 ASSERT_TRUE(document);
135
136 constexpr int kBufLen = 100;
137 uint16_t buffer[kBufLen] = {0};
138 EXPECT_EQ(18U, FPDF_StructElement_GetType(document, buffer, kBufLen));
139 EXPECT_EQ("Document", GetPlatformString(buffer));
140
141 ASSERT_EQ(1, FPDF_StructElement_CountChildren(document));
142 FPDF_STRUCTELEMENT table = FPDF_StructElement_GetChildAtIndex(document, 0);
143 ASSERT_TRUE(table);
144
145 EXPECT_EQ(12U, FPDF_StructElement_GetType(table, buffer, kBufLen));
146 EXPECT_EQ("Table", GetPlatformString(buffer));
147
148 // The table should have an attribute "Summary" set to the empty string.
149 EXPECT_EQ(2U, FPDF_StructElement_GetStringAttribute(table, "Summary",
150 buffer, kBufLen));
151
152 ASSERT_EQ(2, FPDF_StructElement_CountChildren(table));
153 FPDF_STRUCTELEMENT row = FPDF_StructElement_GetChildAtIndex(table, 0);
154 ASSERT_TRUE(row);
155
156 ASSERT_EQ(2, FPDF_StructElement_CountChildren(row));
157 FPDF_STRUCTELEMENT header_cell = FPDF_StructElement_GetChildAtIndex(row, 0);
158 ASSERT_TRUE(header_cell);
159
160 EXPECT_EQ(6U, FPDF_StructElement_GetType(header_cell, buffer, kBufLen));
161 EXPECT_EQ("TH", GetPlatformString(buffer));
162
163 // The header should have an attribute "Scope" with a scope of "Row".
164 EXPECT_EQ(8U, FPDF_StructElement_GetStringAttribute(header_cell, "Scope",
165 buffer, kBufLen));
166 EXPECT_EQ("Row", GetPlatformString(buffer));
167
168 // The header has an attribute "ColSpan", but it's not a string so it
169 // returns null.
170 EXPECT_EQ(0U, FPDF_StructElement_GetStringAttribute(header_cell, "ColSpan",
171 buffer, kBufLen));
172
173 // An unsupported attribute should return 0.
174 EXPECT_EQ(0U, FPDF_StructElement_GetStringAttribute(header_cell, "Other",
175 buffer, kBufLen));
176
177 // A null struct element should not crash.
178 EXPECT_EQ(0U, FPDF_StructElement_GetStringAttribute(nullptr, "Other",
179 buffer, kBufLen));
180 }
181
182 UnloadPage(page);
183}
184
186 ASSERT_TRUE(OpenDocument("tagged_table_bad_elem.pdf"));
187 FPDF_PAGE page = LoadPage(0);
188 ASSERT_TRUE(page);
189
190 {
191 ScopedFPDFStructTree struct_tree(FPDF_StructTree_GetForPage(page));
192 ASSERT_TRUE(struct_tree);
193 ASSERT_EQ(1, FPDF_StructTree_CountChildren(struct_tree.get()));
194
195 FPDF_STRUCTELEMENT document =
196 FPDF_StructTree_GetChildAtIndex(struct_tree.get(), 0);
197 ASSERT_TRUE(document);
198
199 constexpr int kBufLen = 100;
200 uint16_t buffer[kBufLen] = {0};
201 EXPECT_EQ(18U, FPDF_StructElement_GetType(document, buffer, kBufLen));
202 EXPECT_EQ("Document", GetPlatformString(buffer));
203
204 // The table can be retrieved, even though it does not have /Type.
205 ASSERT_EQ(1, FPDF_StructElement_CountChildren(document));
206 FPDF_STRUCTELEMENT table = FPDF_StructElement_GetChildAtIndex(document, 0);
207 ASSERT_TRUE(table);
208
209 EXPECT_EQ(12U, FPDF_StructElement_GetType(table, buffer, kBufLen));
210 EXPECT_EQ("Table", GetPlatformString(buffer));
211
212 // The table entry cannot be retrieved, as the element is malformed.
213 EXPECT_EQ(0U, FPDF_StructElement_GetStringAttribute(table, "Summary",
214 buffer, kBufLen));
215
216 // The row can be retrieved, even though it had an invalid /Type.
217 ASSERT_EQ(1, FPDF_StructElement_CountChildren(table));
218 FPDF_STRUCTELEMENT row = FPDF_StructElement_GetChildAtIndex(table, 0);
219 EXPECT_TRUE(row);
220 }
221
222 UnloadPage(page);
223}
224
226 ASSERT_TRUE(OpenDocument("tagged_table.pdf"));
227 FPDF_PAGE page = LoadPage(0);
228 ASSERT_TRUE(page);
229
230 {
231 ScopedFPDFStructTree struct_tree(FPDF_StructTree_GetForPage(page));
232 ASSERT_TRUE(struct_tree);
233 ASSERT_EQ(1, FPDF_StructTree_CountChildren(struct_tree.get()));
234
235 FPDF_STRUCTELEMENT document =
236 FPDF_StructTree_GetChildAtIndex(struct_tree.get(), 0);
237 ASSERT_TRUE(document);
238
239 constexpr int kBufLen = 100;
240 uint16_t buffer[kBufLen] = {0};
241 EXPECT_EQ(18U, FPDF_StructElement_GetType(document, buffer, kBufLen));
242 EXPECT_EQ("Document", GetPlatformString(buffer));
243
244 // The document has no ID.
245 EXPECT_EQ(0U, FPDF_StructElement_GetID(document, buffer, kBufLen));
246
247 ASSERT_EQ(1, FPDF_StructElement_CountChildren(document));
248 FPDF_STRUCTELEMENT table = FPDF_StructElement_GetChildAtIndex(document, 0);
249 ASSERT_TRUE(table);
250
251 EXPECT_EQ(12U, FPDF_StructElement_GetType(table, buffer, kBufLen));
252 EXPECT_EQ("Table", GetPlatformString(buffer));
253
254 // The table has an ID.
255 EXPECT_EQ(14U, FPDF_StructElement_GetID(table, buffer, kBufLen));
256 EXPECT_EQ("node12", GetPlatformString(buffer));
257
258 // The first child of the table is a row, which has an empty ID.
259 // It returns 2U, the length of an empty string, instead of 0U,
260 // representing null.
261 ASSERT_EQ(2, FPDF_StructElement_CountChildren(table));
262 FPDF_STRUCTELEMENT row = FPDF_StructElement_GetChildAtIndex(table, 0);
263 ASSERT_TRUE(row);
264 EXPECT_EQ(2U, FPDF_StructElement_GetID(row, buffer, kBufLen));
265 }
266
267 UnloadPage(page);
268}
269
271 ASSERT_TRUE(OpenDocument("tagged_table.pdf"));
272 FPDF_PAGE page = LoadPage(0);
273 ASSERT_TRUE(page);
274
275 {
276 ScopedFPDFStructTree struct_tree(FPDF_StructTree_GetForPage(page));
277 ASSERT_TRUE(struct_tree);
278 ASSERT_EQ(1, FPDF_StructTree_CountChildren(struct_tree.get()));
279
280 FPDF_STRUCTELEMENT document =
281 FPDF_StructTree_GetChildAtIndex(struct_tree.get(), 0);
282 ASSERT_TRUE(document);
283
284 constexpr int kBufLen = 100;
285 uint16_t buffer[kBufLen] = {0};
286 EXPECT_EQ(18U, FPDF_StructElement_GetType(document, buffer, kBufLen));
287 EXPECT_EQ("Document", GetPlatformString(buffer));
288
289 // Nullptr test
290 EXPECT_EQ(0U, FPDF_StructElement_GetLang(nullptr, buffer, kBufLen));
291
292 // The document has a language.
293 EXPECT_EQ(12U, FPDF_StructElement_GetLang(document, buffer, kBufLen));
294 EXPECT_EQ("en-US", GetPlatformString(buffer));
295
296 ASSERT_EQ(1, FPDF_StructElement_CountChildren(document));
297 FPDF_STRUCTELEMENT table = FPDF_StructElement_GetChildAtIndex(document, 0);
298 ASSERT_TRUE(table);
299
300 // The first child is a table, with a language.
301 EXPECT_EQ(12U, FPDF_StructElement_GetType(table, buffer, kBufLen));
302 EXPECT_EQ("Table", GetPlatformString(buffer));
303
304 EXPECT_EQ(6U, FPDF_StructElement_GetLang(table, buffer, kBufLen));
305 EXPECT_EQ("hu", GetPlatformString(buffer));
306
307 // The first child of the table is a row, which doesn't have a
308 // language explicitly set on it.
309 ASSERT_EQ(2, FPDF_StructElement_CountChildren(table));
310 FPDF_STRUCTELEMENT row = FPDF_StructElement_GetChildAtIndex(table, 0);
311 ASSERT_TRUE(row);
312 EXPECT_EQ(0U, FPDF_StructElement_GetLang(row, buffer, kBufLen));
313 }
314
315 UnloadPage(page);
316}
317
318// See also FPDFEditEmbedderTest.TraverseMarkedContentID, which traverses the
319// marked contents using FPDFPageObj_GetMark() and related API.
321 ASSERT_TRUE(OpenDocument("marked_content_id.pdf"));
322 FPDF_PAGE page = LoadPage(0);
323 ASSERT_TRUE(page);
324
325 {
326 ScopedFPDFStructTree struct_tree(FPDF_StructTree_GetForPage(page));
327 ASSERT_TRUE(struct_tree);
328 ASSERT_EQ(1, FPDF_StructTree_CountChildren(struct_tree.get()));
329
330 FPDF_STRUCTELEMENT element =
331 FPDF_StructTree_GetChildAtIndex(struct_tree.get(), 0);
332 EXPECT_EQ(0, FPDF_StructElement_GetMarkedContentID(element));
333 }
334
335 UnloadPage(page);
336}
337
339 ASSERT_TRUE(OpenDocument("tagged_marked_content.pdf"));
340 FPDF_PAGE page = LoadPage(0);
341 ASSERT_TRUE(page);
342
343 {
344 ScopedFPDFStructTree struct_tree(FPDF_StructTree_GetForPage(page));
345 ASSERT_TRUE(struct_tree);
346 ASSERT_EQ(4, FPDF_StructTree_CountChildren(struct_tree.get()));
347
348 // K is an integer MCID
349 FPDF_STRUCTELEMENT child1 =
350 FPDF_StructTree_GetChildAtIndex(struct_tree.get(), 0);
351 ASSERT_TRUE(child1);
352 // Legacy API
353 EXPECT_EQ(0, FPDF_StructElement_GetMarkedContentID(child1));
354
355 // K is a dict containing MCR object reference
356 FPDF_STRUCTELEMENT child2 =
357 FPDF_StructTree_GetChildAtIndex(struct_tree.get(), 1);
358 ASSERT_TRUE(child2);
359
360 // K is an array containing dict MCR object reference and integer MCID
361 FPDF_STRUCTELEMENT child3 =
362 FPDF_StructTree_GetChildAtIndex(struct_tree.get(), 2);
363 ASSERT_TRUE(child3);
364
365 // K does not exist
366 FPDF_STRUCTELEMENT child4 =
367 FPDF_StructTree_GetChildAtIndex(struct_tree.get(), 3);
368 ASSERT_TRUE(child4);
369
370 // New APIs
377
380
384
387 }
388
389 UnloadPage(page);
390}
391
393 ASSERT_TRUE(OpenDocument("tagged_mcr_multipage.pdf"));
394
395 // Using the loop to make difference clear
396 for (int page_i : {0, 1}) {
397 FPDF_PAGE page = LoadPage(page_i);
398 ASSERT_TRUE(page);
399 ScopedFPDFStructTree struct_tree(FPDF_StructTree_GetForPage(page));
400 ASSERT_TRUE(struct_tree);
401 ASSERT_EQ(1, FPDF_StructTree_CountChildren(struct_tree.get()));
402
403 FPDF_STRUCTELEMENT struct_doc =
404 FPDF_StructTree_GetChildAtIndex(struct_tree.get(), 0);
405 ASSERT_TRUE(struct_doc);
406 EXPECT_EQ(-1, FPDF_StructElement_GetMarkedContentID(struct_doc));
407
408 ASSERT_EQ(2, FPDF_StructElement_CountChildren(struct_doc));
409 FPDF_STRUCTELEMENT child1 =
410 FPDF_StructElement_GetChildAtIndex(struct_doc, 0);
411 EXPECT_FALSE(child1);
412 FPDF_STRUCTELEMENT child2 =
413 FPDF_StructElement_GetChildAtIndex(struct_doc, 1);
414 EXPECT_FALSE(child2);
415
416 EXPECT_EQ(2, FPDF_StructElement_GetMarkedContentIdCount(struct_doc));
417
418 // Both MCID are returned as if part of this page, while they are not.
419 // So `FPDF_StructElement_GetMarkedContentIdAtIndex(...)` does not work
420 // for StructElement spanning multiple pages.
421 EXPECT_EQ(0, FPDF_StructElement_GetMarkedContentIdAtIndex(struct_doc, 0));
422 EXPECT_EQ(0, FPDF_StructElement_GetMarkedContentIdAtIndex(struct_doc, 1));
423
424 // One MCR is pointing to page 1, another to page2, so those are different
425 // for different pages.
426 EXPECT_EQ(page_i == 0 ? 0 : -1,
427 FPDF_StructElement_GetChildMarkedContentID(struct_doc, 0));
428 EXPECT_EQ(page_i == 1 ? 0 : -1,
429 FPDF_StructElement_GetChildMarkedContentID(struct_doc, 1));
430 // Invalid index
431 EXPECT_EQ(-1, FPDF_StructElement_GetChildMarkedContentID(struct_doc, -1));
432 EXPECT_EQ(-1, FPDF_StructElement_GetChildMarkedContentID(struct_doc, 2));
433 // Invalid element
434 EXPECT_EQ(-1, FPDF_StructElement_GetChildMarkedContentID(nullptr, 0));
435 UnloadPage(page);
436 }
437}
438
440 ASSERT_TRUE(OpenDocument("tagged_alt_text.pdf"));
441 FPDF_PAGE page = LoadPage(0);
442 ASSERT_TRUE(page);
443
444 {
445 ScopedFPDFStructTree struct_tree(FPDF_StructTree_GetForPage(page));
446 ASSERT_TRUE(struct_tree);
447 ASSERT_EQ(1, FPDF_StructTree_CountChildren(struct_tree.get()));
448
449 FPDF_STRUCTELEMENT element =
450 FPDF_StructTree_GetChildAtIndex(struct_tree.get(), 0);
451 ASSERT_TRUE(element);
452
453 // test nullptr inputs
454 unsigned short buffer[12];
455 ASSERT_EQ(0U, FPDF_StructElement_GetType(nullptr, buffer, sizeof(buffer)));
456 ASSERT_EQ(0U, FPDF_StructElement_GetType(nullptr, nullptr, 0));
457 ASSERT_EQ(18U, FPDF_StructElement_GetType(element, nullptr, 0));
458
459 memset(buffer, 0, sizeof(buffer));
460 // Deliberately pass in a small buffer size to make sure |buffer| remains
461 // untouched.
462 ASSERT_EQ(18U, FPDF_StructElement_GetType(element, buffer, 1));
463 for (size_t i = 0; i < std::size(buffer); ++i)
464 EXPECT_EQ(0U, buffer[i]);
465
466 ASSERT_EQ(18U, FPDF_StructElement_GetType(element, buffer, sizeof(buffer)));
467 EXPECT_EQ(L"Document", GetPlatformWString(buffer));
468 }
469
470 UnloadPage(page);
471}
472
474 ASSERT_TRUE(OpenDocument("tagged_table_bad_elem.pdf"));
475 FPDF_PAGE page = LoadPage(0);
476 ASSERT_TRUE(page);
477
478 {
479 ScopedFPDFStructTree struct_tree(FPDF_StructTree_GetForPage(page));
480 ASSERT_TRUE(struct_tree);
481 ASSERT_EQ(1, FPDF_StructTree_CountChildren(struct_tree.get()));
482
483 FPDF_STRUCTELEMENT child =
484 FPDF_StructTree_GetChildAtIndex(struct_tree.get(), 0);
485 ASSERT_TRUE(child);
486
487 // test nullptr inputs
488 unsigned short buffer[28] = {};
489 ASSERT_EQ(0U,
490 FPDF_StructElement_GetObjType(nullptr, buffer, sizeof(buffer)));
491 ASSERT_EQ(0U, FPDF_StructElement_GetObjType(nullptr, nullptr, 0));
492 ASSERT_EQ(22U, FPDF_StructElement_GetObjType(child, nullptr, 0));
493
494 // Deliberately pass in a small buffer size to make sure `buffer` remains
495 // untouched.
496 ASSERT_EQ(22U, FPDF_StructElement_GetObjType(child, buffer, 1));
497 for (size_t i = 0; i < std::size(buffer); ++i)
498 EXPECT_EQ(0U, buffer[i]);
499
500 ASSERT_EQ(22U,
501 FPDF_StructElement_GetObjType(child, buffer, sizeof(buffer)));
502 EXPECT_EQ(L"StructElem", GetPlatformWString(buffer));
503
504 ASSERT_EQ(1, FPDF_StructElement_CountChildren(child));
505 FPDF_STRUCTELEMENT gchild = FPDF_StructElement_GetChildAtIndex(child, 0);
506 memset(buffer, 0, sizeof(buffer));
507 // Missing /Type in `gchild`
508 ASSERT_EQ(0U,
509 FPDF_StructElement_GetObjType(gchild, buffer, sizeof(buffer)));
510 // Buffer is untouched.
511 for (size_t i = 0; i < std::size(buffer); ++i)
512 EXPECT_EQ(0U, buffer[i]);
513
514 ASSERT_EQ(1, FPDF_StructElement_CountChildren(gchild));
515 FPDF_STRUCTELEMENT ggchild = FPDF_StructElement_GetChildAtIndex(gchild, 0);
516 ASSERT_EQ(28U,
517 FPDF_StructElement_GetObjType(ggchild, buffer, sizeof(buffer)));
518 // Reading bad elem also works.
519 EXPECT_EQ(L"NotStructElem", GetPlatformWString(buffer));
520 }
521
522 UnloadPage(page);
523}
524
526 ASSERT_TRUE(OpenDocument("tagged_alt_text.pdf"));
527 FPDF_PAGE page = LoadPage(0);
528 ASSERT_TRUE(page);
529
530 {
531 ScopedFPDFStructTree struct_tree(FPDF_StructTree_GetForPage(page));
532 ASSERT_TRUE(struct_tree);
533 ASSERT_EQ(1, FPDF_StructTree_CountChildren(struct_tree.get()));
534
535 FPDF_STRUCTELEMENT parent =
536 FPDF_StructTree_GetChildAtIndex(struct_tree.get(), 0);
537 ASSERT_TRUE(parent);
538
539 ASSERT_EQ(1, FPDF_StructElement_CountChildren(parent));
540
541 FPDF_STRUCTELEMENT child = FPDF_StructElement_GetChildAtIndex(parent, 0);
542 ASSERT_TRUE(child);
543
544 // test nullptr inputs
545 ASSERT_EQ(nullptr, FPDF_StructElement_GetParent(nullptr));
546
547 ASSERT_EQ(parent, FPDF_StructElement_GetParent(child));
548
549 // The parent of `parent` is StructTreeRoot and no longer a StructElement.
550 // We currently handle this case by returning a nullptr.
551 ASSERT_EQ(nullptr, FPDF_StructElement_GetParent(parent));
552 }
553
554 UnloadPage(page);
555}
556
558 ASSERT_TRUE(OpenDocument("tagged_alt_text.pdf"));
559 FPDF_PAGE page = LoadPage(0);
560 ASSERT_TRUE(page);
561
562 {
563 ScopedFPDFStructTree struct_tree(FPDF_StructTree_GetForPage(page));
564 ASSERT_TRUE(struct_tree);
565 ASSERT_EQ(1, FPDF_StructTree_CountChildren(struct_tree.get()));
566
567 FPDF_STRUCTELEMENT element =
568 FPDF_StructTree_GetChildAtIndex(struct_tree.get(), 0);
569 ASSERT_TRUE(element);
570
571 // test nullptr inputs
572 unsigned short buffer[13];
573 ASSERT_EQ(0U, FPDF_StructElement_GetTitle(nullptr, buffer, sizeof(buffer)));
574 ASSERT_EQ(0U, FPDF_StructElement_GetTitle(nullptr, nullptr, 0));
575 ASSERT_EQ(20U, FPDF_StructElement_GetTitle(element, nullptr, 0));
576
577 memset(buffer, 0, sizeof(buffer));
578 // Deliberately pass in a small buffer size to make sure |buffer| remains
579 // untouched.
580 ASSERT_EQ(20U, FPDF_StructElement_GetTitle(element, buffer, 1));
581 for (size_t i = 0; i < std::size(buffer); ++i)
582 EXPECT_EQ(0U, buffer[i]);
583
584 ASSERT_EQ(20U,
585 FPDF_StructElement_GetTitle(element, buffer, sizeof(buffer)));
586
587 EXPECT_EQ(L"TitleText", GetPlatformWString(buffer));
588
589 ASSERT_EQ(1, FPDF_StructElement_CountChildren(element));
590 FPDF_STRUCTELEMENT child_element =
592 ASSERT_TRUE(element);
593
594 ASSERT_EQ(26U, FPDF_StructElement_GetTitle(child_element, buffer,
595 sizeof(buffer)));
596 EXPECT_EQ(L"symbol: 100k", GetPlatformWString(buffer));
597 }
598
599 UnloadPage(page);
600}
601
603 ASSERT_TRUE(OpenDocument("tagged_table.pdf"));
604 FPDF_PAGE page = LoadPage(0);
605 ASSERT_TRUE(page);
606
607 {
608 ScopedFPDFStructTree struct_tree(FPDF_StructTree_GetForPage(page));
609 ASSERT_TRUE(struct_tree);
610 ASSERT_EQ(1, FPDF_StructTree_CountChildren(struct_tree.get()));
611
612 FPDF_STRUCTELEMENT document =
613 FPDF_StructTree_GetChildAtIndex(struct_tree.get(), 0);
614 ASSERT_TRUE(document);
615
616 ASSERT_EQ(1, FPDF_StructElement_CountChildren(document));
617 ASSERT_EQ(-1, FPDF_StructElement_GetAttributeCount(document));
618 FPDF_STRUCTELEMENT table = FPDF_StructElement_GetChildAtIndex(document, 0);
619 ASSERT_TRUE(table);
620
621 ASSERT_EQ(2, FPDF_StructElement_CountChildren(table));
622
623 {
624 FPDF_STRUCTELEMENT tr = FPDF_StructElement_GetChildAtIndex(table, 0);
625 ASSERT_TRUE(tr);
626
628 FPDF_STRUCTELEMENT th = FPDF_StructElement_GetChildAtIndex(tr, 0);
629 ASSERT_TRUE(th);
630
632
633 // nullptr test
634 ASSERT_EQ(nullptr, FPDF_StructElement_GetAttributeAtIndex(document, 0));
635 ASSERT_EQ(nullptr, FPDF_StructElement_GetAttributeAtIndex(document, -1));
636 ASSERT_EQ(nullptr, FPDF_StructElement_GetAttributeAtIndex(th, 2));
637
638 FPDF_STRUCTELEMENT_ATTR attr =
640 ASSERT_TRUE(attr);
641
642 ASSERT_EQ(2, FPDF_StructElement_Attr_GetCount(attr));
643 ASSERT_FALSE(
644 FPDF_StructElement_Attr_GetName(attr, 1, nullptr, 0U, nullptr));
645 unsigned long buffer_len_needed = ULONG_MAX;
646 // Pass buffer = nullptr to obtain the size of the buffer needed,
647 ASSERT_TRUE(FPDF_StructElement_Attr_GetName(attr, 1, nullptr, 0,
648 &buffer_len_needed));
649 EXPECT_EQ(2U, buffer_len_needed);
650 char buffer[8] = {};
651 unsigned long out_len = ULONG_MAX;
652 // Deliberately pass in a small buffer size to make sure `buffer` remains
653 // untouched.
654 ASSERT_TRUE(
655 FPDF_StructElement_Attr_GetName(attr, 1, buffer, 1, &out_len));
656 EXPECT_EQ(2U, out_len);
657 for (size_t i = 0; i < std::size(buffer); ++i)
658 EXPECT_EQ(0, buffer[i]);
659
660 ASSERT_TRUE(FPDF_StructElement_Attr_GetName(attr, 1, buffer,
661 sizeof(buffer), &out_len));
662 EXPECT_EQ(2U, out_len);
663 EXPECT_STREQ("O", buffer);
664 EXPECT_EQ(FPDF_OBJECT_NAME,
666
667 unsigned short str_val[12] = {};
669 attr, buffer, str_val, sizeof(str_val), &out_len));
670 EXPECT_EQ(12U, out_len);
671 EXPECT_EQ(L"Table", GetPlatformWString(str_val));
672
673 memset(buffer, 0, sizeof(buffer));
674 ASSERT_TRUE(FPDF_StructElement_Attr_GetName(attr, 0, buffer,
675 sizeof(buffer), &out_len));
676 EXPECT_EQ(8U, out_len);
677 EXPECT_STREQ("ColSpan", buffer);
678 EXPECT_EQ(FPDF_OBJECT_NUMBER,
680 float num_val;
681 ASSERT_TRUE(
683 EXPECT_FLOAT_EQ(2.0f, num_val);
684 }
685
686 {
687 FPDF_STRUCTELEMENT tr = FPDF_StructElement_GetChildAtIndex(table, 1);
688 ASSERT_TRUE(tr);
689
691 // nullptr when index out of range
692 ASSERT_EQ(nullptr, FPDF_StructElement_GetAttributeAtIndex(tr, 1));
693
695 FPDF_STRUCTELEMENT td = FPDF_StructElement_GetChildAtIndex(tr, 1);
696 ASSERT_TRUE(td);
697 {
698 // Test counting and obtaining attributes via reference
700 FPDF_STRUCTELEMENT_ATTR attr =
702 ASSERT_TRUE(attr);
703 ASSERT_EQ(4, FPDF_StructElement_Attr_GetCount(attr));
704 // Test string and blob type
705 {
706 char buffer[16] = {};
707 unsigned long out_len = ULONG_MAX;
709 attr, 0, buffer, sizeof(buffer), &out_len));
710 EXPECT_EQ(8U, out_len);
711 EXPECT_STREQ("ColProp", buffer);
712
713 EXPECT_EQ(FPDF_OBJECT_STRING,
715
716 unsigned short str_val[12] = {};
718 attr, buffer, str_val, sizeof(str_val), &out_len));
719 EXPECT_EQ(8U, out_len);
720 EXPECT_EQ(L"Sum", GetPlatformWString(str_val));
721
722 char blob_val[3] = {};
724 attr, buffer, blob_val, sizeof(blob_val), &out_len));
725 EXPECT_EQ(3U, out_len);
726 EXPECT_EQ('S', blob_val[0]);
727 EXPECT_EQ('u', blob_val[1]);
728 EXPECT_EQ('m', blob_val[2]);
729 }
730
731 // Test boolean type
732 {
733 char buffer[16] = {};
734 unsigned long out_len = ULONG_MAX;
736 attr, 1, buffer, sizeof(buffer), &out_len));
737 EXPECT_EQ(7U, out_len);
738 EXPECT_STREQ("CurUSD", buffer);
739
740 EXPECT_EQ(FPDF_OBJECT_BOOLEAN,
742 FPDF_BOOL val;
743 ASSERT_TRUE(
745 EXPECT_TRUE(val);
746 }
747
748 // Test reference to number
749 {
750 char buffer[16] = {};
751 unsigned long out_len = ULONG_MAX;
753 attr, 3, buffer, sizeof(buffer), &out_len));
754 EXPECT_EQ(8U, out_len);
755 EXPECT_STREQ("RowSpan", buffer);
756
757 EXPECT_EQ(FPDF_OBJECT_REFERENCE,
759 float val;
760 ASSERT_TRUE(
762 EXPECT_FLOAT_EQ(3, val);
763 }
764 }
765 }
766 }
767
768 UnloadPage(page);
769}
770
772 ASSERT_TRUE(OpenDocument("tagged_nested.pdf"));
773 FPDF_PAGE page = LoadPage(0);
774 ASSERT_TRUE(page);
775
776 {
777 // This call should not crash. https://crbug.com/pdfium/1480
778 ScopedFPDFStructTree struct_tree(FPDF_StructTree_GetForPage(page));
779 ASSERT_TRUE(struct_tree);
780 }
781 UnloadPage(page);
782}
783
785 ASSERT_TRUE(OpenDocument("tagged_mcr_objr.pdf"));
786 FPDF_PAGE page = LoadPage(0);
787 ASSERT_TRUE(page);
788
789 {
790 ScopedFPDFStructTree struct_tree(FPDF_StructTree_GetForPage(page));
791 ASSERT_TRUE(struct_tree);
792 ASSERT_EQ(1, FPDF_StructTree_CountChildren(struct_tree.get()));
793
794 FPDF_STRUCTELEMENT object8 =
795 FPDF_StructTree_GetChildAtIndex(struct_tree.get(), 0);
796 ASSERT_TRUE(object8);
797 unsigned short buffer[12];
798 ASSERT_EQ(18U, FPDF_StructElement_GetType(object8, buffer, sizeof(buffer)));
799 EXPECT_EQ(L"Document", GetPlatformWString(buffer));
800 EXPECT_EQ(-1, FPDF_StructElement_GetMarkedContentID(object8));
801 ASSERT_EQ(2, FPDF_StructElement_CountChildren(object8));
802
803 // First branch. 10 -> 12 -> 13 -> Inline dict.
804 FPDF_STRUCTELEMENT object10 =
806 ASSERT_TRUE(object10);
807 ASSERT_EQ(20U,
808 FPDF_StructElement_GetType(object10, buffer, sizeof(buffer)));
809 EXPECT_EQ(L"NonStruct", GetPlatformWString(buffer));
810 EXPECT_EQ(-1, FPDF_StructElement_GetMarkedContentID(object10));
811 ASSERT_EQ(1, FPDF_StructElement_CountChildren(object10));
812
813 FPDF_STRUCTELEMENT object12 =
815 ASSERT_TRUE(object12);
816 ASSERT_EQ(4U, FPDF_StructElement_GetType(object12, buffer, sizeof(buffer)));
817 EXPECT_EQ(L"P", GetPlatformWString(buffer));
818 EXPECT_EQ(-1, FPDF_StructElement_GetMarkedContentID(object12));
819 ASSERT_EQ(1, FPDF_StructElement_CountChildren(object12));
820
821 FPDF_STRUCTELEMENT object13 =
823 ASSERT_TRUE(object13);
824 ASSERT_EQ(20U,
825 FPDF_StructElement_GetType(object13, buffer, sizeof(buffer)));
826 EXPECT_EQ(L"NonStruct", GetPlatformWString(buffer));
827 EXPECT_EQ(-1, FPDF_StructElement_GetMarkedContentID(object13));
828 ASSERT_EQ(1, FPDF_StructElement_CountChildren(object13));
829
830 // TODO(crbug.com/pdfium/672): Fetch this child element.
831 EXPECT_FALSE(FPDF_StructElement_GetChildAtIndex(object13, 0));
832
833 // Second branch. 11 -> 14 -> Inline dict.
834 // -> 15 -> Inline dict.
835 FPDF_STRUCTELEMENT object11 =
837 ASSERT_TRUE(object11);
838 ASSERT_EQ(4U, FPDF_StructElement_GetType(object11, buffer, sizeof(buffer)));
839 EXPECT_EQ(L"P", GetPlatformWString(buffer));
840 EXPECT_EQ(-1, FPDF_StructElement_GetMarkedContentID(object11));
841 ASSERT_EQ(1, FPDF_StructElement_CountChildren(object11));
842
843 FPDF_STRUCTELEMENT object14 =
845 ASSERT_TRUE(object14);
846 ASSERT_EQ(20U,
847 FPDF_StructElement_GetType(object14, buffer, sizeof(buffer)));
848 EXPECT_EQ(L"NonStruct", GetPlatformWString(buffer));
849 EXPECT_EQ(-1, FPDF_StructElement_GetMarkedContentID(object14));
850 ASSERT_EQ(2, FPDF_StructElement_CountChildren(object14));
851
852 // TODO(crbug.com/pdfium/672): Object 15 should be at index 1.
853 EXPECT_FALSE(FPDF_StructElement_GetChildAtIndex(object14, 1));
854 FPDF_STRUCTELEMENT object15 =
856 ASSERT_TRUE(object15);
857 ASSERT_EQ(20U,
858 FPDF_StructElement_GetType(object15, buffer, sizeof(buffer)));
859 EXPECT_EQ(L"NonStruct", GetPlatformWString(buffer));
860 EXPECT_EQ(-1, FPDF_StructElement_GetMarkedContentID(object15));
861 ASSERT_EQ(1, FPDF_StructElement_CountChildren(object15));
862
863 // TODO(crbug.com/pdfium/672): Fetch this child element.
864 EXPECT_FALSE(FPDF_StructElement_GetChildAtIndex(object15, 0));
865 }
866
867 UnloadPage(page);
868}
869
871 ASSERT_TRUE(OpenDocument("bug_1768.pdf"));
872 FPDF_PAGE page = LoadPage(0);
873 ASSERT_TRUE(page);
874
875 {
876 ScopedFPDFStructTree struct_tree(FPDF_StructTree_GetForPage(page));
877 ASSERT_TRUE(struct_tree);
878 ASSERT_EQ(1, FPDF_StructTree_CountChildren(struct_tree.get()));
879
880 // TODO(crbug.com/pdfium/1768): Fetch this child element. Then consider
881 // writing more of the test to make sure other elements in the tree can be
882 // fetched correctly as well.
883 EXPECT_FALSE(FPDF_StructTree_GetChildAtIndex(struct_tree.get(), 0));
884 }
885
886 UnloadPage(page);
887}
888
890 ASSERT_TRUE(OpenDocument("bug_1296920.pdf"));
891 FPDF_PAGE page = LoadPage(0);
892 ASSERT_TRUE(page);
893
894 {
895 ScopedFPDFStructTree struct_tree(FPDF_StructTree_GetForPage(page));
896 ASSERT_TRUE(struct_tree);
897 ASSERT_EQ(1, FPDF_StructTree_CountChildren(struct_tree.get()));
898
899 // Destroying this tree should not crash.
900 }
901
902 UnloadPage(page);
903}
904
906 ASSERT_TRUE(OpenDocument("tagged_table_bad_parent.pdf"));
907 FPDF_PAGE page = LoadPage(0);
908 ASSERT_TRUE(page);
909
910 {
911 // Calling these APIs should not trigger a dangling pointer.
912 ScopedFPDFStructTree struct_tree(FPDF_StructTree_GetForPage(page));
913 ASSERT_TRUE(struct_tree);
914 ASSERT_EQ(1, FPDF_StructTree_CountChildren(struct_tree.get()));
915 }
916
917 UnloadPage(page);
918}
FPDF_EXPORT FPDF_STRUCTELEMENT FPDF_CALLCONV FPDF_StructElement_GetParent(FPDF_STRUCTELEMENT struct_element)
FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_StructElement_GetLang(FPDF_STRUCTELEMENT struct_element, void *buffer, unsigned long buflen)
FPDF_EXPORT int FPDF_CALLCONV FPDF_StructElement_GetAttributeCount(FPDF_STRUCTELEMENT struct_element)
FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_StructElement_Attr_GetStringValue(FPDF_STRUCTELEMENT_ATTR struct_attribute, FPDF_BYTESTRING name, void *buffer, unsigned long buflen, unsigned long *out_buflen)
FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_StructElement_Attr_GetBooleanValue(FPDF_STRUCTELEMENT_ATTR struct_attribute, FPDF_BYTESTRING name, FPDF_BOOL *out_value)
FPDF_EXPORT int FPDF_CALLCONV FPDF_StructElement_GetMarkedContentID(FPDF_STRUCTELEMENT struct_element)
FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_StructElement_GetStringAttribute(FPDF_STRUCTELEMENT struct_element, FPDF_BYTESTRING attr_name, void *buffer, unsigned long buflen)
FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_StructElement_Attr_GetBlobValue(FPDF_STRUCTELEMENT_ATTR struct_attribute, FPDF_BYTESTRING name, void *buffer, unsigned long buflen, unsigned long *out_buflen)
FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_StructElement_Attr_GetName(FPDF_STRUCTELEMENT_ATTR struct_attribute, int index, void *buffer, unsigned long buflen, unsigned long *out_buflen)
FPDF_EXPORT int FPDF_CALLCONV FPDF_StructElement_GetMarkedContentIdAtIndex(FPDF_STRUCTELEMENT struct_element, int index)
FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_StructElement_GetActualText(FPDF_STRUCTELEMENT struct_element, void *buffer, unsigned long buflen)
FPDF_EXPORT int FPDF_CALLCONV FPDF_StructElement_Attr_GetCount(FPDF_STRUCTELEMENT_ATTR struct_attribute)
FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_StructElement_GetID(FPDF_STRUCTELEMENT struct_element, void *buffer, unsigned long buflen)
FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_StructElement_Attr_GetNumberValue(FPDF_STRUCTELEMENT_ATTR struct_attribute, FPDF_BYTESTRING name, float *out_value)
FPDF_EXPORT FPDF_STRUCTELEMENT FPDF_CALLCONV FPDF_StructElement_GetChildAtIndex(FPDF_STRUCTELEMENT struct_element, int index)
FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_StructElement_GetObjType(FPDF_STRUCTELEMENT struct_element, void *buffer, unsigned long buflen)
FPDF_EXPORT FPDF_OBJECT_TYPE FPDF_CALLCONV FPDF_StructElement_Attr_GetType(FPDF_STRUCTELEMENT_ATTR struct_attribute, FPDF_BYTESTRING name)
FPDF_EXPORT FPDF_STRUCTELEMENT_ATTR FPDF_CALLCONV FPDF_StructElement_GetAttributeAtIndex(FPDF_STRUCTELEMENT struct_element, int index)
FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_StructElement_GetType(FPDF_STRUCTELEMENT struct_element, void *buffer, unsigned long buflen)
FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_StructElement_GetAltText(FPDF_STRUCTELEMENT struct_element, void *buffer, unsigned long buflen)
FPDF_EXPORT int FPDF_CALLCONV FPDF_StructElement_CountChildren(FPDF_STRUCTELEMENT struct_element)
FPDF_EXPORT int FPDF_CALLCONV FPDF_StructElement_GetMarkedContentIdCount(FPDF_STRUCTELEMENT struct_element)
FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_StructElement_GetTitle(FPDF_STRUCTELEMENT struct_element, void *buffer, unsigned long buflen)
TEST_F(FPDFStructTreeEmbedderTest, GetAltText)
#define FPDF_OBJECT_REFERENCE
Definition fpdfview.h:45
#define FPDF_OBJECT_NUMBER
Definition fpdfview.h:38
#define FPDF_OBJECT_NAME
Definition fpdfview.h:40
#define FPDF_OBJECT_BOOLEAN
Definition fpdfview.h:37
#define FPDF_OBJECT_STRING
Definition fpdfview.h:39