1 // Copyright 2016 PDFium Authors. All rights reserved.
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 "core/fxcrt/fx_string.h"
6 #include "public/fpdf_structtree.h"
7 #include "testing/embedder_test.h"
8 #include "third_party/base/optional.h"
9 
10 class FPDFStructTreeEmbedderTest : public EmbedderTest {};
11 
TEST_F(FPDFStructTreeEmbedderTest,GetAltText)12 TEST_F(FPDFStructTreeEmbedderTest, GetAltText) {
13   ASSERT_TRUE(OpenDocument("tagged_alt_text.pdf"));
14   FPDF_PAGE page = LoadPage(0);
15   ASSERT_TRUE(page);
16 
17   {
18     ScopedFPDFStructTree struct_tree(FPDF_StructTree_GetForPage(page));
19     ASSERT_TRUE(struct_tree);
20     ASSERT_EQ(1, FPDF_StructTree_CountChildren(struct_tree.get()));
21 
22     FPDF_STRUCTELEMENT element =
23         FPDF_StructTree_GetChildAtIndex(struct_tree.get(), -1);
24     EXPECT_EQ(nullptr, element);
25     element = FPDF_StructTree_GetChildAtIndex(struct_tree.get(), 1);
26     EXPECT_EQ(nullptr, element);
27     element = FPDF_StructTree_GetChildAtIndex(struct_tree.get(), 0);
28     ASSERT_NE(nullptr, element);
29     EXPECT_EQ(-1, FPDF_StructElement_GetMarkedContentID(element));
30     EXPECT_EQ(0U, FPDF_StructElement_GetAltText(element, nullptr, 0));
31 
32     ASSERT_EQ(1, FPDF_StructElement_CountChildren(element));
33     FPDF_STRUCTELEMENT child_element =
34         FPDF_StructElement_GetChildAtIndex(element, -1);
35     EXPECT_EQ(nullptr, child_element);
36     child_element = FPDF_StructElement_GetChildAtIndex(element, 1);
37     EXPECT_EQ(nullptr, child_element);
38     child_element = FPDF_StructElement_GetChildAtIndex(element, 0);
39     ASSERT_NE(nullptr, child_element);
40     EXPECT_EQ(-1, FPDF_StructElement_GetMarkedContentID(child_element));
41     EXPECT_EQ(0U, FPDF_StructElement_GetAltText(child_element, nullptr, 0));
42 
43     ASSERT_EQ(1, FPDF_StructElement_CountChildren(child_element));
44     FPDF_STRUCTELEMENT gchild_element =
45         FPDF_StructElement_GetChildAtIndex(child_element, -1);
46     EXPECT_EQ(nullptr, gchild_element);
47     gchild_element = FPDF_StructElement_GetChildAtIndex(child_element, 1);
48     EXPECT_EQ(nullptr, gchild_element);
49     gchild_element = FPDF_StructElement_GetChildAtIndex(child_element, 0);
50     ASSERT_NE(nullptr, gchild_element);
51     EXPECT_EQ(-1, FPDF_StructElement_GetMarkedContentID(gchild_element));
52     ASSERT_EQ(24U, FPDF_StructElement_GetAltText(gchild_element, nullptr, 0));
53 
54     unsigned short buffer[12];
55     memset(buffer, 0, sizeof(buffer));
56     // Deliberately pass in a small buffer size to make sure |buffer| remains
57     // untouched.
58     ASSERT_EQ(24U, FPDF_StructElement_GetAltText(gchild_element, buffer, 1));
59     for (size_t i = 0; i < FX_ArraySize(buffer); ++i)
60       EXPECT_EQ(0U, buffer[i]);
61 
62     EXPECT_EQ(-1, FPDF_StructElement_GetMarkedContentID(gchild_element));
63     ASSERT_EQ(24U, FPDF_StructElement_GetAltText(gchild_element, buffer,
64                                                  sizeof(buffer)));
65     const wchar_t kExpected[] = L"Black Image";
66     EXPECT_EQ(WideString(kExpected),
67               WideString::FromUTF16LE(buffer, FXSYS_len(kExpected)));
68 
69     ASSERT_EQ(1, FPDF_StructElement_CountChildren(gchild_element));
70     FPDF_STRUCTELEMENT ggchild_element =
71         FPDF_StructElement_GetChildAtIndex(gchild_element, 0);
72     EXPECT_EQ(nullptr, ggchild_element);
73   }
74 
75   UnloadPage(page);
76 }
77 
TEST_F(FPDFStructTreeEmbedderTest,GetMarkedContentID)78 TEST_F(FPDFStructTreeEmbedderTest, GetMarkedContentID) {
79   ASSERT_TRUE(OpenDocument("marked_content_id.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     FPDF_STRUCTELEMENT element =
89         FPDF_StructTree_GetChildAtIndex(struct_tree.get(), 0);
90     EXPECT_EQ(0, FPDF_StructElement_GetMarkedContentID(element));
91   }
92 
93   UnloadPage(page);
94 }
95 
TEST_F(FPDFStructTreeEmbedderTest,GetType)96 TEST_F(FPDFStructTreeEmbedderTest, GetType) {
97   ASSERT_TRUE(OpenDocument("tagged_alt_text.pdf"));
98   FPDF_PAGE page = LoadPage(0);
99   ASSERT_TRUE(page);
100 
101   {
102     ScopedFPDFStructTree struct_tree(FPDF_StructTree_GetForPage(page));
103     ASSERT_TRUE(struct_tree);
104     ASSERT_EQ(1, FPDF_StructTree_CountChildren(struct_tree.get()));
105 
106     FPDF_STRUCTELEMENT element =
107         FPDF_StructTree_GetChildAtIndex(struct_tree.get(), 0);
108     ASSERT_NE(nullptr, element);
109 
110     // test nullptr inputs
111     unsigned short buffer[12];
112     ASSERT_EQ(0U, FPDF_StructElement_GetType(nullptr, buffer, sizeof(buffer)));
113     ASSERT_EQ(0U, FPDF_StructElement_GetType(nullptr, nullptr, 0));
114     ASSERT_EQ(18U, FPDF_StructElement_GetType(element, nullptr, 0));
115 
116     memset(buffer, 0, sizeof(buffer));
117     // Deliberately pass in a small buffer size to make sure |buffer| remains
118     // untouched.
119     ASSERT_EQ(18U, FPDF_StructElement_GetType(element, buffer, 1));
120     for (size_t i = 0; i < FX_ArraySize(buffer); ++i)
121       EXPECT_EQ(0U, buffer[i]);
122 
123     ASSERT_EQ(18U, FPDF_StructElement_GetType(element, buffer, sizeof(buffer)));
124     const wchar_t kExpected[] = L"Document";
125     EXPECT_EQ(WideString(kExpected),
126               WideString::FromUTF16LE(buffer, FXSYS_len(kExpected)));
127   }
128 
129   UnloadPage(page);
130 }
131 
TEST_F(FPDFStructTreeEmbedderTest,GetTitle)132 TEST_F(FPDFStructTreeEmbedderTest, GetTitle) {
133   ASSERT_TRUE(OpenDocument("tagged_alt_text.pdf"));
134   FPDF_PAGE page = LoadPage(0);
135   ASSERT_TRUE(page);
136 
137   {
138     ScopedFPDFStructTree struct_tree(FPDF_StructTree_GetForPage(page));
139     ASSERT_TRUE(struct_tree);
140     ASSERT_EQ(1, FPDF_StructTree_CountChildren(struct_tree.get()));
141 
142     FPDF_STRUCTELEMENT element =
143         FPDF_StructTree_GetChildAtIndex(struct_tree.get(), 0);
144     ASSERT_NE(nullptr, element);
145 
146     // test nullptr inputs
147     unsigned short buffer[13];
148     ASSERT_EQ(0U, FPDF_StructElement_GetTitle(nullptr, buffer, sizeof(buffer)));
149     ASSERT_EQ(0U, FPDF_StructElement_GetTitle(nullptr, nullptr, 0));
150     ASSERT_EQ(20U, FPDF_StructElement_GetTitle(element, nullptr, 0));
151 
152     memset(buffer, 0, sizeof(buffer));
153     // Deliberately pass in a small buffer size to make sure |buffer| remains
154     // untouched.
155     ASSERT_EQ(20U, FPDF_StructElement_GetTitle(element, buffer, 1));
156     for (size_t i = 0; i < FX_ArraySize(buffer); ++i)
157       EXPECT_EQ(0U, buffer[i]);
158 
159     ASSERT_EQ(20U,
160               FPDF_StructElement_GetTitle(element, buffer, sizeof(buffer)));
161 
162     const wchar_t kExpected[] = L"TitleText";
163     EXPECT_EQ(WideString(kExpected),
164               WideString::FromUTF16LE(buffer, FXSYS_len(kExpected)));
165 
166     ASSERT_EQ(1, FPDF_StructElement_CountChildren(element));
167     FPDF_STRUCTELEMENT child_element =
168         FPDF_StructElement_GetChildAtIndex(element, 0);
169     ASSERT_NE(nullptr, element);
170 
171     ASSERT_EQ(26U, FPDF_StructElement_GetTitle(child_element, buffer,
172                                                sizeof(buffer)));
173     const wchar_t kChildExpected[] = L"symbol: 100k";
174     EXPECT_EQ(WideString(kChildExpected),
175               WideString::FromUTF16LE(buffer, FXSYS_len(kChildExpected)));
176   }
177 
178   UnloadPage(page);
179 }
180