1*3ac0a46fSAndroid Build Coastguard Worker // Copyright 2015 The PDFium Authors
2*3ac0a46fSAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*3ac0a46fSAndroid Build Coastguard Worker // found in the LICENSE file.
4*3ac0a46fSAndroid Build Coastguard Worker
5*3ac0a46fSAndroid Build Coastguard Worker #include <algorithm>
6*3ac0a46fSAndroid Build Coastguard Worker #include <utility>
7*3ac0a46fSAndroid Build Coastguard Worker #include <vector>
8*3ac0a46fSAndroid Build Coastguard Worker
9*3ac0a46fSAndroid Build Coastguard Worker #include "build/build_config.h"
10*3ac0a46fSAndroid Build Coastguard Worker #include "core/fxge/fx_font.h"
11*3ac0a46fSAndroid Build Coastguard Worker #include "public/cpp/fpdf_scopers.h"
12*3ac0a46fSAndroid Build Coastguard Worker #include "public/fpdf_doc.h"
13*3ac0a46fSAndroid Build Coastguard Worker #include "public/fpdf_text.h"
14*3ac0a46fSAndroid Build Coastguard Worker #include "public/fpdf_transformpage.h"
15*3ac0a46fSAndroid Build Coastguard Worker #include "public/fpdfview.h"
16*3ac0a46fSAndroid Build Coastguard Worker #include "testing/embedder_test.h"
17*3ac0a46fSAndroid Build Coastguard Worker #include "testing/fx_string_testhelpers.h"
18*3ac0a46fSAndroid Build Coastguard Worker #include "testing/gtest/include/gtest/gtest.h"
19*3ac0a46fSAndroid Build Coastguard Worker
20*3ac0a46fSAndroid Build Coastguard Worker namespace {
21*3ac0a46fSAndroid Build Coastguard Worker
22*3ac0a46fSAndroid Build Coastguard Worker constexpr char kHelloGoodbyeText[] = "Hello, world!\r\nGoodbye, world!";
23*3ac0a46fSAndroid Build Coastguard Worker constexpr int kHelloGoodbyeTextSize = std::size(kHelloGoodbyeText);
24*3ac0a46fSAndroid Build Coastguard Worker
check_unsigned_shorts(const char * expected,const unsigned short * actual,size_t length)25*3ac0a46fSAndroid Build Coastguard Worker bool check_unsigned_shorts(const char* expected,
26*3ac0a46fSAndroid Build Coastguard Worker const unsigned short* actual,
27*3ac0a46fSAndroid Build Coastguard Worker size_t length) {
28*3ac0a46fSAndroid Build Coastguard Worker if (length > strlen(expected) + 1)
29*3ac0a46fSAndroid Build Coastguard Worker return false;
30*3ac0a46fSAndroid Build Coastguard Worker
31*3ac0a46fSAndroid Build Coastguard Worker for (size_t i = 0; i < length; ++i) {
32*3ac0a46fSAndroid Build Coastguard Worker if (actual[i] != static_cast<unsigned short>(expected[i]))
33*3ac0a46fSAndroid Build Coastguard Worker return false;
34*3ac0a46fSAndroid Build Coastguard Worker }
35*3ac0a46fSAndroid Build Coastguard Worker return true;
36*3ac0a46fSAndroid Build Coastguard Worker }
37*3ac0a46fSAndroid Build Coastguard Worker
38*3ac0a46fSAndroid Build Coastguard Worker } // namespace
39*3ac0a46fSAndroid Build Coastguard Worker
40*3ac0a46fSAndroid Build Coastguard Worker class FPDFTextEmbedderTest : public EmbedderTest {};
41*3ac0a46fSAndroid Build Coastguard Worker
TEST_F(FPDFTextEmbedderTest,Text)42*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFTextEmbedderTest, Text) {
43*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(OpenDocument("hello_world.pdf"));
44*3ac0a46fSAndroid Build Coastguard Worker FPDF_PAGE page = LoadPage(0);
45*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(page);
46*3ac0a46fSAndroid Build Coastguard Worker
47*3ac0a46fSAndroid Build Coastguard Worker FPDF_TEXTPAGE textpage = FPDFText_LoadPage(page);
48*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(textpage);
49*3ac0a46fSAndroid Build Coastguard Worker
50*3ac0a46fSAndroid Build Coastguard Worker unsigned short buffer[128];
51*3ac0a46fSAndroid Build Coastguard Worker memset(buffer, 0xbd, sizeof(buffer));
52*3ac0a46fSAndroid Build Coastguard Worker
53*3ac0a46fSAndroid Build Coastguard Worker // Check that edge cases are handled gracefully
54*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(0, FPDFText_GetText(textpage, 0, 128, nullptr));
55*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(0, FPDFText_GetText(textpage, -1, 128, buffer));
56*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(0, FPDFText_GetText(textpage, 0, -1, buffer));
57*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(1, FPDFText_GetText(textpage, 0, 0, buffer));
58*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(0, buffer[0]);
59*3ac0a46fSAndroid Build Coastguard Worker
60*3ac0a46fSAndroid Build Coastguard Worker // Keep going and check the next case.
61*3ac0a46fSAndroid Build Coastguard Worker memset(buffer, 0xbd, sizeof(buffer));
62*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(2, FPDFText_GetText(textpage, 0, 1, buffer));
63*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(kHelloGoodbyeText[0], buffer[0]);
64*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(0, buffer[1]);
65*3ac0a46fSAndroid Build Coastguard Worker
66*3ac0a46fSAndroid Build Coastguard Worker // Check includes the terminating NUL that is provided.
67*3ac0a46fSAndroid Build Coastguard Worker int num_chars = FPDFText_GetText(textpage, 0, 128, buffer);
68*3ac0a46fSAndroid Build Coastguard Worker ASSERT_EQ(kHelloGoodbyeTextSize, num_chars);
69*3ac0a46fSAndroid Build Coastguard Worker EXPECT_TRUE(
70*3ac0a46fSAndroid Build Coastguard Worker check_unsigned_shorts(kHelloGoodbyeText, buffer, kHelloGoodbyeTextSize));
71*3ac0a46fSAndroid Build Coastguard Worker
72*3ac0a46fSAndroid Build Coastguard Worker // Count does not include the terminating NUL in the string literal.
73*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(kHelloGoodbyeTextSize - 1, FPDFText_CountChars(textpage));
74*3ac0a46fSAndroid Build Coastguard Worker for (size_t i = 0; i < kHelloGoodbyeTextSize - 1; ++i) {
75*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(static_cast<unsigned int>(kHelloGoodbyeText[i]),
76*3ac0a46fSAndroid Build Coastguard Worker FPDFText_GetUnicode(textpage, i))
77*3ac0a46fSAndroid Build Coastguard Worker << " at " << i;
78*3ac0a46fSAndroid Build Coastguard Worker }
79*3ac0a46fSAndroid Build Coastguard Worker
80*3ac0a46fSAndroid Build Coastguard Worker // Extracting using a buffer that will be completely filled. Small buffer is
81*3ac0a46fSAndroid Build Coastguard Worker // 12 elements long, since it will need 2 locations per displayed character in
82*3ac0a46fSAndroid Build Coastguard Worker // the expected string, plus 2 more for the terminating character.
83*3ac0a46fSAndroid Build Coastguard Worker static const char kSmallExpected[] = "Hello";
84*3ac0a46fSAndroid Build Coastguard Worker unsigned short small_buffer[12];
85*3ac0a46fSAndroid Build Coastguard Worker memset(buffer, 0xbd, sizeof(buffer));
86*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(6, FPDFText_GetText(textpage, 0, 5, small_buffer));
87*3ac0a46fSAndroid Build Coastguard Worker EXPECT_TRUE(check_unsigned_shorts(kSmallExpected, small_buffer,
88*3ac0a46fSAndroid Build Coastguard Worker sizeof(kSmallExpected)));
89*3ac0a46fSAndroid Build Coastguard Worker
90*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(12.0, FPDFText_GetFontSize(textpage, 0));
91*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(16.0, FPDFText_GetFontSize(textpage, 15));
92*3ac0a46fSAndroid Build Coastguard Worker
93*3ac0a46fSAndroid Build Coastguard Worker double left = 1.0;
94*3ac0a46fSAndroid Build Coastguard Worker double right = 2.0;
95*3ac0a46fSAndroid Build Coastguard Worker double bottom = 3.0;
96*3ac0a46fSAndroid Build Coastguard Worker double top = 4.0;
97*3ac0a46fSAndroid Build Coastguard Worker EXPECT_FALSE(FPDFText_GetCharBox(nullptr, 4, &left, &right, &bottom, &top));
98*3ac0a46fSAndroid Build Coastguard Worker EXPECT_DOUBLE_EQ(1.0, left);
99*3ac0a46fSAndroid Build Coastguard Worker EXPECT_DOUBLE_EQ(2.0, right);
100*3ac0a46fSAndroid Build Coastguard Worker EXPECT_DOUBLE_EQ(3.0, bottom);
101*3ac0a46fSAndroid Build Coastguard Worker EXPECT_DOUBLE_EQ(4.0, top);
102*3ac0a46fSAndroid Build Coastguard Worker EXPECT_FALSE(FPDFText_GetCharBox(textpage, -1, &left, &right, &bottom, &top));
103*3ac0a46fSAndroid Build Coastguard Worker EXPECT_DOUBLE_EQ(1.0, left);
104*3ac0a46fSAndroid Build Coastguard Worker EXPECT_DOUBLE_EQ(2.0, right);
105*3ac0a46fSAndroid Build Coastguard Worker EXPECT_DOUBLE_EQ(3.0, bottom);
106*3ac0a46fSAndroid Build Coastguard Worker EXPECT_DOUBLE_EQ(4.0, top);
107*3ac0a46fSAndroid Build Coastguard Worker EXPECT_FALSE(FPDFText_GetCharBox(textpage, 55, &left, &right, &bottom, &top));
108*3ac0a46fSAndroid Build Coastguard Worker EXPECT_DOUBLE_EQ(1.0, left);
109*3ac0a46fSAndroid Build Coastguard Worker EXPECT_DOUBLE_EQ(2.0, right);
110*3ac0a46fSAndroid Build Coastguard Worker EXPECT_DOUBLE_EQ(3.0, bottom);
111*3ac0a46fSAndroid Build Coastguard Worker EXPECT_DOUBLE_EQ(4.0, top);
112*3ac0a46fSAndroid Build Coastguard Worker EXPECT_FALSE(
113*3ac0a46fSAndroid Build Coastguard Worker FPDFText_GetCharBox(textpage, 4, nullptr, &right, &bottom, &top));
114*3ac0a46fSAndroid Build Coastguard Worker EXPECT_FALSE(FPDFText_GetCharBox(textpage, 4, &left, nullptr, &bottom, &top));
115*3ac0a46fSAndroid Build Coastguard Worker EXPECT_FALSE(FPDFText_GetCharBox(textpage, 4, &left, &right, nullptr, &top));
116*3ac0a46fSAndroid Build Coastguard Worker EXPECT_FALSE(
117*3ac0a46fSAndroid Build Coastguard Worker FPDFText_GetCharBox(textpage, 4, &left, &right, &bottom, nullptr));
118*3ac0a46fSAndroid Build Coastguard Worker EXPECT_FALSE(
119*3ac0a46fSAndroid Build Coastguard Worker FPDFText_GetCharBox(textpage, 4, nullptr, nullptr, nullptr, nullptr));
120*3ac0a46fSAndroid Build Coastguard Worker
121*3ac0a46fSAndroid Build Coastguard Worker EXPECT_TRUE(FPDFText_GetCharBox(textpage, 4, &left, &right, &bottom, &top));
122*3ac0a46fSAndroid Build Coastguard Worker EXPECT_NEAR(41.120, left, 0.001);
123*3ac0a46fSAndroid Build Coastguard Worker EXPECT_NEAR(46.208, right, 0.001);
124*3ac0a46fSAndroid Build Coastguard Worker EXPECT_NEAR(49.892, bottom, 0.001);
125*3ac0a46fSAndroid Build Coastguard Worker EXPECT_NEAR(55.652, top, 0.001);
126*3ac0a46fSAndroid Build Coastguard Worker
127*3ac0a46fSAndroid Build Coastguard Worker FS_RECTF rect = {4.0f, 1.0f, 3.0f, 2.0f};
128*3ac0a46fSAndroid Build Coastguard Worker EXPECT_FALSE(FPDFText_GetLooseCharBox(nullptr, 4, &rect));
129*3ac0a46fSAndroid Build Coastguard Worker EXPECT_FLOAT_EQ(4.0f, rect.left);
130*3ac0a46fSAndroid Build Coastguard Worker EXPECT_FLOAT_EQ(3.0f, rect.right);
131*3ac0a46fSAndroid Build Coastguard Worker EXPECT_FLOAT_EQ(2.0f, rect.bottom);
132*3ac0a46fSAndroid Build Coastguard Worker EXPECT_FLOAT_EQ(1.0f, rect.top);
133*3ac0a46fSAndroid Build Coastguard Worker EXPECT_FALSE(FPDFText_GetLooseCharBox(textpage, -1, &rect));
134*3ac0a46fSAndroid Build Coastguard Worker EXPECT_FLOAT_EQ(4.0f, rect.left);
135*3ac0a46fSAndroid Build Coastguard Worker EXPECT_FLOAT_EQ(3.0f, rect.right);
136*3ac0a46fSAndroid Build Coastguard Worker EXPECT_FLOAT_EQ(2.0f, rect.bottom);
137*3ac0a46fSAndroid Build Coastguard Worker EXPECT_FLOAT_EQ(1.0f, rect.top);
138*3ac0a46fSAndroid Build Coastguard Worker EXPECT_FALSE(FPDFText_GetLooseCharBox(textpage, 55, &rect));
139*3ac0a46fSAndroid Build Coastguard Worker EXPECT_FLOAT_EQ(4.0f, rect.left);
140*3ac0a46fSAndroid Build Coastguard Worker EXPECT_FLOAT_EQ(3.0f, rect.right);
141*3ac0a46fSAndroid Build Coastguard Worker EXPECT_FLOAT_EQ(2.0f, rect.bottom);
142*3ac0a46fSAndroid Build Coastguard Worker EXPECT_FLOAT_EQ(1.0f, rect.top);
143*3ac0a46fSAndroid Build Coastguard Worker EXPECT_FALSE(FPDFText_GetLooseCharBox(textpage, 4, nullptr));
144*3ac0a46fSAndroid Build Coastguard Worker
145*3ac0a46fSAndroid Build Coastguard Worker EXPECT_TRUE(FPDFText_GetLooseCharBox(textpage, 4, &rect));
146*3ac0a46fSAndroid Build Coastguard Worker EXPECT_FLOAT_EQ(40.664001f, rect.left);
147*3ac0a46fSAndroid Build Coastguard Worker EXPECT_FLOAT_EQ(46.664001f, rect.right);
148*3ac0a46fSAndroid Build Coastguard Worker EXPECT_FLOAT_EQ(47.667271f, rect.bottom);
149*3ac0a46fSAndroid Build Coastguard Worker EXPECT_FLOAT_EQ(59.667271f, rect.top);
150*3ac0a46fSAndroid Build Coastguard Worker
151*3ac0a46fSAndroid Build Coastguard Worker double x = 0.0;
152*3ac0a46fSAndroid Build Coastguard Worker double y = 0.0;
153*3ac0a46fSAndroid Build Coastguard Worker EXPECT_TRUE(FPDFText_GetCharOrigin(textpage, 4, &x, &y));
154*3ac0a46fSAndroid Build Coastguard Worker EXPECT_NEAR(40.664, x, 0.001);
155*3ac0a46fSAndroid Build Coastguard Worker EXPECT_NEAR(50.000, y, 0.001);
156*3ac0a46fSAndroid Build Coastguard Worker
157*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(4, FPDFText_GetCharIndexAtPos(textpage, 42.0, 50.0, 1.0, 1.0));
158*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(-1, FPDFText_GetCharIndexAtPos(textpage, 0.0, 0.0, 1.0, 1.0));
159*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(-1, FPDFText_GetCharIndexAtPos(textpage, 199.0, 199.0, 1.0, 1.0));
160*3ac0a46fSAndroid Build Coastguard Worker
161*3ac0a46fSAndroid Build Coastguard Worker // Test out of range indicies.
162*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(-1,
163*3ac0a46fSAndroid Build Coastguard Worker FPDFText_GetCharIndexAtPos(textpage, 42.0, 10000000.0, 1.0, 1.0));
164*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(-1, FPDFText_GetCharIndexAtPos(textpage, -1.0, 50.0, 1.0, 1.0));
165*3ac0a46fSAndroid Build Coastguard Worker
166*3ac0a46fSAndroid Build Coastguard Worker // Count does not include the terminating NUL in the string literal.
167*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(2, FPDFText_CountRects(textpage, 0, kHelloGoodbyeTextSize - 1));
168*3ac0a46fSAndroid Build Coastguard Worker
169*3ac0a46fSAndroid Build Coastguard Worker left = 0.0;
170*3ac0a46fSAndroid Build Coastguard Worker right = 0.0;
171*3ac0a46fSAndroid Build Coastguard Worker bottom = 0.0;
172*3ac0a46fSAndroid Build Coastguard Worker top = 0.0;
173*3ac0a46fSAndroid Build Coastguard Worker EXPECT_TRUE(FPDFText_GetRect(textpage, 1, &left, &top, &right, &bottom));
174*3ac0a46fSAndroid Build Coastguard Worker EXPECT_NEAR(20.800, left, 0.001);
175*3ac0a46fSAndroid Build Coastguard Worker EXPECT_NEAR(135.040, right, 0.001);
176*3ac0a46fSAndroid Build Coastguard Worker EXPECT_NEAR(96.688, bottom, 0.001);
177*3ac0a46fSAndroid Build Coastguard Worker EXPECT_NEAR(111.600, top, 0.001);
178*3ac0a46fSAndroid Build Coastguard Worker
179*3ac0a46fSAndroid Build Coastguard Worker // Test out of range indicies set outputs to (0.0, 0.0, 0.0, 0.0).
180*3ac0a46fSAndroid Build Coastguard Worker left = -1.0;
181*3ac0a46fSAndroid Build Coastguard Worker right = -1.0;
182*3ac0a46fSAndroid Build Coastguard Worker bottom = -1.0;
183*3ac0a46fSAndroid Build Coastguard Worker top = -1.0;
184*3ac0a46fSAndroid Build Coastguard Worker EXPECT_FALSE(FPDFText_GetRect(textpage, -1, &left, &top, &right, &bottom));
185*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(0.0, left);
186*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(0.0, right);
187*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(0.0, bottom);
188*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(0.0, top);
189*3ac0a46fSAndroid Build Coastguard Worker
190*3ac0a46fSAndroid Build Coastguard Worker left = -2.0;
191*3ac0a46fSAndroid Build Coastguard Worker right = -2.0;
192*3ac0a46fSAndroid Build Coastguard Worker bottom = -2.0;
193*3ac0a46fSAndroid Build Coastguard Worker top = -2.0;
194*3ac0a46fSAndroid Build Coastguard Worker EXPECT_FALSE(FPDFText_GetRect(textpage, 2, &left, &top, &right, &bottom));
195*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(0.0, left);
196*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(0.0, right);
197*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(0.0, bottom);
198*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(0.0, top);
199*3ac0a46fSAndroid Build Coastguard Worker
200*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(
201*3ac0a46fSAndroid Build Coastguard Worker 9, FPDFText_GetBoundedText(textpage, 41.0, 56.0, 82.0, 48.0, nullptr, 0));
202*3ac0a46fSAndroid Build Coastguard Worker
203*3ac0a46fSAndroid Build Coastguard Worker // Extract starting at character 4 as above.
204*3ac0a46fSAndroid Build Coastguard Worker memset(buffer, 0xbd, sizeof(buffer));
205*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(
206*3ac0a46fSAndroid Build Coastguard Worker 1, FPDFText_GetBoundedText(textpage, 41.0, 56.0, 82.0, 48.0, buffer, 1));
207*3ac0a46fSAndroid Build Coastguard Worker EXPECT_TRUE(check_unsigned_shorts(kHelloGoodbyeText + 4, buffer, 1));
208*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(0xbdbd, buffer[1]);
209*3ac0a46fSAndroid Build Coastguard Worker
210*3ac0a46fSAndroid Build Coastguard Worker memset(buffer, 0xbd, sizeof(buffer));
211*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(
212*3ac0a46fSAndroid Build Coastguard Worker 9, FPDFText_GetBoundedText(textpage, 41.0, 56.0, 82.0, 48.0, buffer, 9));
213*3ac0a46fSAndroid Build Coastguard Worker EXPECT_TRUE(check_unsigned_shorts(kHelloGoodbyeText + 4, buffer, 8));
214*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(0xbdbd, buffer[9]);
215*3ac0a46fSAndroid Build Coastguard Worker
216*3ac0a46fSAndroid Build Coastguard Worker memset(buffer, 0xbd, sizeof(buffer));
217*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(10, FPDFText_GetBoundedText(textpage, 41.0, 56.0, 82.0, 48.0,
218*3ac0a46fSAndroid Build Coastguard Worker buffer, 128));
219*3ac0a46fSAndroid Build Coastguard Worker EXPECT_TRUE(check_unsigned_shorts(kHelloGoodbyeText + 4, buffer, 9));
220*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(0u, buffer[9]);
221*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(0xbdbd, buffer[10]);
222*3ac0a46fSAndroid Build Coastguard Worker
223*3ac0a46fSAndroid Build Coastguard Worker FPDFText_ClosePage(textpage);
224*3ac0a46fSAndroid Build Coastguard Worker UnloadPage(page);
225*3ac0a46fSAndroid Build Coastguard Worker }
226*3ac0a46fSAndroid Build Coastguard Worker
TEST_F(FPDFTextEmbedderTest,TextVertical)227*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFTextEmbedderTest, TextVertical) {
228*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(OpenDocument("vertical_text.pdf"));
229*3ac0a46fSAndroid Build Coastguard Worker FPDF_PAGE page = LoadPage(0);
230*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(page);
231*3ac0a46fSAndroid Build Coastguard Worker
232*3ac0a46fSAndroid Build Coastguard Worker FPDF_TEXTPAGE textpage = FPDFText_LoadPage(page);
233*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(textpage);
234*3ac0a46fSAndroid Build Coastguard Worker
235*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(12.0, FPDFText_GetFontSize(textpage, 0));
236*3ac0a46fSAndroid Build Coastguard Worker
237*3ac0a46fSAndroid Build Coastguard Worker double x = 0.0;
238*3ac0a46fSAndroid Build Coastguard Worker double y = 0.0;
239*3ac0a46fSAndroid Build Coastguard Worker EXPECT_TRUE(FPDFText_GetCharOrigin(textpage, 1, &x, &y));
240*3ac0a46fSAndroid Build Coastguard Worker EXPECT_NEAR(6.664, x, 0.001);
241*3ac0a46fSAndroid Build Coastguard Worker EXPECT_NEAR(171.508, y, 0.001);
242*3ac0a46fSAndroid Build Coastguard Worker
243*3ac0a46fSAndroid Build Coastguard Worker EXPECT_TRUE(FPDFText_GetCharOrigin(textpage, 2, &x, &y));
244*3ac0a46fSAndroid Build Coastguard Worker EXPECT_NEAR(8.668, x, 0.001);
245*3ac0a46fSAndroid Build Coastguard Worker EXPECT_NEAR(160.492, y, 0.001);
246*3ac0a46fSAndroid Build Coastguard Worker
247*3ac0a46fSAndroid Build Coastguard Worker FS_RECTF rect;
248*3ac0a46fSAndroid Build Coastguard Worker EXPECT_TRUE(FPDFText_GetLooseCharBox(textpage, 1, &rect));
249*3ac0a46fSAndroid Build Coastguard Worker EXPECT_NEAR(4, rect.left, 0.001);
250*3ac0a46fSAndroid Build Coastguard Worker EXPECT_NEAR(16, rect.right, 0.001);
251*3ac0a46fSAndroid Build Coastguard Worker EXPECT_NEAR(178.984, rect.bottom, 0.001);
252*3ac0a46fSAndroid Build Coastguard Worker EXPECT_NEAR(170.308, rect.top, 0.001);
253*3ac0a46fSAndroid Build Coastguard Worker
254*3ac0a46fSAndroid Build Coastguard Worker EXPECT_TRUE(FPDFText_GetLooseCharBox(textpage, 2, &rect));
255*3ac0a46fSAndroid Build Coastguard Worker EXPECT_NEAR(4, rect.left, 0.001);
256*3ac0a46fSAndroid Build Coastguard Worker EXPECT_NEAR(16, rect.right, 0.001);
257*3ac0a46fSAndroid Build Coastguard Worker EXPECT_NEAR(170.308, rect.bottom, 0.001);
258*3ac0a46fSAndroid Build Coastguard Worker EXPECT_NEAR(159.292, rect.top, 0.001);
259*3ac0a46fSAndroid Build Coastguard Worker
260*3ac0a46fSAndroid Build Coastguard Worker FPDFText_ClosePage(textpage);
261*3ac0a46fSAndroid Build Coastguard Worker UnloadPage(page);
262*3ac0a46fSAndroid Build Coastguard Worker }
263*3ac0a46fSAndroid Build Coastguard Worker
TEST_F(FPDFTextEmbedderTest,TextHebrewMirrored)264*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFTextEmbedderTest, TextHebrewMirrored) {
265*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(OpenDocument("hebrew_mirrored.pdf"));
266*3ac0a46fSAndroid Build Coastguard Worker FPDF_PAGE page = LoadPage(0);
267*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(page);
268*3ac0a46fSAndroid Build Coastguard Worker
269*3ac0a46fSAndroid Build Coastguard Worker {
270*3ac0a46fSAndroid Build Coastguard Worker ScopedFPDFTextPage textpage(FPDFText_LoadPage(page));
271*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(textpage);
272*3ac0a46fSAndroid Build Coastguard Worker
273*3ac0a46fSAndroid Build Coastguard Worker constexpr int kCharCount = 10;
274*3ac0a46fSAndroid Build Coastguard Worker ASSERT_EQ(kCharCount, FPDFText_CountChars(textpage.get()));
275*3ac0a46fSAndroid Build Coastguard Worker
276*3ac0a46fSAndroid Build Coastguard Worker unsigned short buffer[kCharCount + 1];
277*3ac0a46fSAndroid Build Coastguard Worker memset(buffer, 0x42, sizeof(buffer));
278*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(kCharCount + 1,
279*3ac0a46fSAndroid Build Coastguard Worker FPDFText_GetText(textpage.get(), 0, kCharCount, buffer));
280*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(0x05d1, buffer[0]);
281*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(0x05e0, buffer[1]);
282*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(0x05d9, buffer[2]);
283*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(0x05de, buffer[3]);
284*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(0x05d9, buffer[4]);
285*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(0x05df, buffer[5]);
286*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(0x000d, buffer[6]);
287*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(0x000a, buffer[7]);
288*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(0x05df, buffer[8]);
289*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(0x05d1, buffer[9]);
290*3ac0a46fSAndroid Build Coastguard Worker }
291*3ac0a46fSAndroid Build Coastguard Worker
292*3ac0a46fSAndroid Build Coastguard Worker UnloadPage(page);
293*3ac0a46fSAndroid Build Coastguard Worker }
294*3ac0a46fSAndroid Build Coastguard Worker
TEST_F(FPDFTextEmbedderTest,TextSearch)295*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFTextEmbedderTest, TextSearch) {
296*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(OpenDocument("hello_world.pdf"));
297*3ac0a46fSAndroid Build Coastguard Worker FPDF_PAGE page = LoadPage(0);
298*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(page);
299*3ac0a46fSAndroid Build Coastguard Worker
300*3ac0a46fSAndroid Build Coastguard Worker FPDF_TEXTPAGE textpage = FPDFText_LoadPage(page);
301*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(textpage);
302*3ac0a46fSAndroid Build Coastguard Worker
303*3ac0a46fSAndroid Build Coastguard Worker ScopedFPDFWideString nope = GetFPDFWideString(L"nope");
304*3ac0a46fSAndroid Build Coastguard Worker ScopedFPDFWideString world = GetFPDFWideString(L"world");
305*3ac0a46fSAndroid Build Coastguard Worker ScopedFPDFWideString world_caps = GetFPDFWideString(L"WORLD");
306*3ac0a46fSAndroid Build Coastguard Worker ScopedFPDFWideString world_substr = GetFPDFWideString(L"orld");
307*3ac0a46fSAndroid Build Coastguard Worker
308*3ac0a46fSAndroid Build Coastguard Worker {
309*3ac0a46fSAndroid Build Coastguard Worker // No occurrences of "nope" in test page.
310*3ac0a46fSAndroid Build Coastguard Worker ScopedFPDFTextFind search(FPDFText_FindStart(textpage, nope.get(), 0, 0));
311*3ac0a46fSAndroid Build Coastguard Worker EXPECT_TRUE(search);
312*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(0, FPDFText_GetSchResultIndex(search.get()));
313*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(0, FPDFText_GetSchCount(search.get()));
314*3ac0a46fSAndroid Build Coastguard Worker
315*3ac0a46fSAndroid Build Coastguard Worker // Advancing finds nothing.
316*3ac0a46fSAndroid Build Coastguard Worker EXPECT_FALSE(FPDFText_FindNext(search.get()));
317*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(0, FPDFText_GetSchResultIndex(search.get()));
318*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(0, FPDFText_GetSchCount(search.get()));
319*3ac0a46fSAndroid Build Coastguard Worker
320*3ac0a46fSAndroid Build Coastguard Worker // Retreating finds nothing.
321*3ac0a46fSAndroid Build Coastguard Worker EXPECT_FALSE(FPDFText_FindPrev(search.get()));
322*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(0, FPDFText_GetSchResultIndex(search.get()));
323*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(0, FPDFText_GetSchCount(search.get()));
324*3ac0a46fSAndroid Build Coastguard Worker }
325*3ac0a46fSAndroid Build Coastguard Worker
326*3ac0a46fSAndroid Build Coastguard Worker {
327*3ac0a46fSAndroid Build Coastguard Worker // Two occurrences of "world" in test page.
328*3ac0a46fSAndroid Build Coastguard Worker ScopedFPDFTextFind search(FPDFText_FindStart(textpage, world.get(), 0, 2));
329*3ac0a46fSAndroid Build Coastguard Worker EXPECT_TRUE(search);
330*3ac0a46fSAndroid Build Coastguard Worker
331*3ac0a46fSAndroid Build Coastguard Worker // Remains not found until advanced.
332*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(0, FPDFText_GetSchResultIndex(search.get()));
333*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(0, FPDFText_GetSchCount(search.get()));
334*3ac0a46fSAndroid Build Coastguard Worker
335*3ac0a46fSAndroid Build Coastguard Worker // First occurrence of "world" in this test page.
336*3ac0a46fSAndroid Build Coastguard Worker EXPECT_TRUE(FPDFText_FindNext(search.get()));
337*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(7, FPDFText_GetSchResultIndex(search.get()));
338*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(5, FPDFText_GetSchCount(search.get()));
339*3ac0a46fSAndroid Build Coastguard Worker
340*3ac0a46fSAndroid Build Coastguard Worker // Last occurrence of "world" in this test page.
341*3ac0a46fSAndroid Build Coastguard Worker EXPECT_TRUE(FPDFText_FindNext(search.get()));
342*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(24, FPDFText_GetSchResultIndex(search.get()));
343*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(5, FPDFText_GetSchCount(search.get()));
344*3ac0a46fSAndroid Build Coastguard Worker
345*3ac0a46fSAndroid Build Coastguard Worker // Found position unchanged when fails to advance.
346*3ac0a46fSAndroid Build Coastguard Worker EXPECT_FALSE(FPDFText_FindNext(search.get()));
347*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(24, FPDFText_GetSchResultIndex(search.get()));
348*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(5, FPDFText_GetSchCount(search.get()));
349*3ac0a46fSAndroid Build Coastguard Worker
350*3ac0a46fSAndroid Build Coastguard Worker // Back to first occurrence.
351*3ac0a46fSAndroid Build Coastguard Worker EXPECT_TRUE(FPDFText_FindPrev(search.get()));
352*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(7, FPDFText_GetSchResultIndex(search.get()));
353*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(5, FPDFText_GetSchCount(search.get()));
354*3ac0a46fSAndroid Build Coastguard Worker
355*3ac0a46fSAndroid Build Coastguard Worker // Found position unchanged when fails to retreat.
356*3ac0a46fSAndroid Build Coastguard Worker EXPECT_FALSE(FPDFText_FindPrev(search.get()));
357*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(7, FPDFText_GetSchResultIndex(search.get()));
358*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(5, FPDFText_GetSchCount(search.get()));
359*3ac0a46fSAndroid Build Coastguard Worker }
360*3ac0a46fSAndroid Build Coastguard Worker
361*3ac0a46fSAndroid Build Coastguard Worker {
362*3ac0a46fSAndroid Build Coastguard Worker // Exact search unaffected by case sensitiity and whole word flags.
363*3ac0a46fSAndroid Build Coastguard Worker ScopedFPDFTextFind search(FPDFText_FindStart(
364*3ac0a46fSAndroid Build Coastguard Worker textpage, world.get(), FPDF_MATCHCASE | FPDF_MATCHWHOLEWORD, 0));
365*3ac0a46fSAndroid Build Coastguard Worker EXPECT_TRUE(search);
366*3ac0a46fSAndroid Build Coastguard Worker EXPECT_TRUE(FPDFText_FindNext(search.get()));
367*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(7, FPDFText_GetSchResultIndex(search.get()));
368*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(5, FPDFText_GetSchCount(search.get()));
369*3ac0a46fSAndroid Build Coastguard Worker }
370*3ac0a46fSAndroid Build Coastguard Worker
371*3ac0a46fSAndroid Build Coastguard Worker {
372*3ac0a46fSAndroid Build Coastguard Worker // Default is case-insensitive, so matching agaist caps works.
373*3ac0a46fSAndroid Build Coastguard Worker ScopedFPDFTextFind search(
374*3ac0a46fSAndroid Build Coastguard Worker FPDFText_FindStart(textpage, world_caps.get(), 0, 0));
375*3ac0a46fSAndroid Build Coastguard Worker EXPECT_TRUE(search);
376*3ac0a46fSAndroid Build Coastguard Worker EXPECT_TRUE(FPDFText_FindNext(search.get()));
377*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(7, FPDFText_GetSchResultIndex(search.get()));
378*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(5, FPDFText_GetSchCount(search.get()));
379*3ac0a46fSAndroid Build Coastguard Worker }
380*3ac0a46fSAndroid Build Coastguard Worker
381*3ac0a46fSAndroid Build Coastguard Worker {
382*3ac0a46fSAndroid Build Coastguard Worker // But can be made case sensitive, in which case this fails.
383*3ac0a46fSAndroid Build Coastguard Worker ScopedFPDFTextFind search(
384*3ac0a46fSAndroid Build Coastguard Worker FPDFText_FindStart(textpage, world_caps.get(), FPDF_MATCHCASE, 0));
385*3ac0a46fSAndroid Build Coastguard Worker EXPECT_FALSE(FPDFText_FindNext(search.get()));
386*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(0, FPDFText_GetSchResultIndex(search.get()));
387*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(0, FPDFText_GetSchCount(search.get()));
388*3ac0a46fSAndroid Build Coastguard Worker }
389*3ac0a46fSAndroid Build Coastguard Worker
390*3ac0a46fSAndroid Build Coastguard Worker {
391*3ac0a46fSAndroid Build Coastguard Worker // Default is match anywhere within word, so matching substring works.
392*3ac0a46fSAndroid Build Coastguard Worker ScopedFPDFTextFind search(
393*3ac0a46fSAndroid Build Coastguard Worker FPDFText_FindStart(textpage, world_substr.get(), 0, 0));
394*3ac0a46fSAndroid Build Coastguard Worker EXPECT_TRUE(FPDFText_FindNext(search.get()));
395*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(8, FPDFText_GetSchResultIndex(search.get()));
396*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(4, FPDFText_GetSchCount(search.get()));
397*3ac0a46fSAndroid Build Coastguard Worker }
398*3ac0a46fSAndroid Build Coastguard Worker
399*3ac0a46fSAndroid Build Coastguard Worker {
400*3ac0a46fSAndroid Build Coastguard Worker // But can be made to mach word boundaries, in which case this fails.
401*3ac0a46fSAndroid Build Coastguard Worker ScopedFPDFTextFind search(FPDFText_FindStart(textpage, world_substr.get(),
402*3ac0a46fSAndroid Build Coastguard Worker FPDF_MATCHWHOLEWORD, 0));
403*3ac0a46fSAndroid Build Coastguard Worker EXPECT_FALSE(FPDFText_FindNext(search.get()));
404*3ac0a46fSAndroid Build Coastguard Worker // TODO(tsepez): investigate strange index/count values in this state.
405*3ac0a46fSAndroid Build Coastguard Worker }
406*3ac0a46fSAndroid Build Coastguard Worker
407*3ac0a46fSAndroid Build Coastguard Worker FPDFText_ClosePage(textpage);
408*3ac0a46fSAndroid Build Coastguard Worker UnloadPage(page);
409*3ac0a46fSAndroid Build Coastguard Worker }
410*3ac0a46fSAndroid Build Coastguard Worker
TEST_F(FPDFTextEmbedderTest,TextSearchConsecutive)411*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFTextEmbedderTest, TextSearchConsecutive) {
412*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(OpenDocument("find_text_consecutive.pdf"));
413*3ac0a46fSAndroid Build Coastguard Worker FPDF_PAGE page = LoadPage(0);
414*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(page);
415*3ac0a46fSAndroid Build Coastguard Worker
416*3ac0a46fSAndroid Build Coastguard Worker FPDF_TEXTPAGE textpage = FPDFText_LoadPage(page);
417*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(textpage);
418*3ac0a46fSAndroid Build Coastguard Worker
419*3ac0a46fSAndroid Build Coastguard Worker ScopedFPDFWideString aaaa = GetFPDFWideString(L"aaaa");
420*3ac0a46fSAndroid Build Coastguard Worker
421*3ac0a46fSAndroid Build Coastguard Worker {
422*3ac0a46fSAndroid Build Coastguard Worker // Search for "aaaa" yields 2 results in "aaaaaaaaaa".
423*3ac0a46fSAndroid Build Coastguard Worker ScopedFPDFTextFind search(FPDFText_FindStart(textpage, aaaa.get(), 0, 0));
424*3ac0a46fSAndroid Build Coastguard Worker EXPECT_TRUE(search);
425*3ac0a46fSAndroid Build Coastguard Worker
426*3ac0a46fSAndroid Build Coastguard Worker // Remains not found until advanced.
427*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(0, FPDFText_GetSchResultIndex(search.get()));
428*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(0, FPDFText_GetSchCount(search.get()));
429*3ac0a46fSAndroid Build Coastguard Worker
430*3ac0a46fSAndroid Build Coastguard Worker // First occurrence of "aaaa" in this test page.
431*3ac0a46fSAndroid Build Coastguard Worker EXPECT_TRUE(FPDFText_FindNext(search.get()));
432*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(0, FPDFText_GetSchResultIndex(search.get()));
433*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(4, FPDFText_GetSchCount(search.get()));
434*3ac0a46fSAndroid Build Coastguard Worker
435*3ac0a46fSAndroid Build Coastguard Worker // Last occurrence of "aaaa" in this test page.
436*3ac0a46fSAndroid Build Coastguard Worker EXPECT_TRUE(FPDFText_FindNext(search.get()));
437*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(4, FPDFText_GetSchResultIndex(search.get()));
438*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(4, FPDFText_GetSchCount(search.get()));
439*3ac0a46fSAndroid Build Coastguard Worker
440*3ac0a46fSAndroid Build Coastguard Worker // Found position unchanged when fails to advance.
441*3ac0a46fSAndroid Build Coastguard Worker EXPECT_FALSE(FPDFText_FindNext(search.get()));
442*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(4, FPDFText_GetSchResultIndex(search.get()));
443*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(4, FPDFText_GetSchCount(search.get()));
444*3ac0a46fSAndroid Build Coastguard Worker
445*3ac0a46fSAndroid Build Coastguard Worker // Back to first occurrence.
446*3ac0a46fSAndroid Build Coastguard Worker EXPECT_TRUE(FPDFText_FindPrev(search.get()));
447*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(0, FPDFText_GetSchResultIndex(search.get()));
448*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(4, FPDFText_GetSchCount(search.get()));
449*3ac0a46fSAndroid Build Coastguard Worker
450*3ac0a46fSAndroid Build Coastguard Worker // Found position unchanged when fails to retreat.
451*3ac0a46fSAndroid Build Coastguard Worker EXPECT_FALSE(FPDFText_FindPrev(search.get()));
452*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(0, FPDFText_GetSchResultIndex(search.get()));
453*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(4, FPDFText_GetSchCount(search.get()));
454*3ac0a46fSAndroid Build Coastguard Worker }
455*3ac0a46fSAndroid Build Coastguard Worker
456*3ac0a46fSAndroid Build Coastguard Worker {
457*3ac0a46fSAndroid Build Coastguard Worker // Search for "aaaa" yields 7 results in "aaaaaaaaaa", when searching with
458*3ac0a46fSAndroid Build Coastguard Worker // FPDF_CONSECUTIVE.
459*3ac0a46fSAndroid Build Coastguard Worker ScopedFPDFTextFind search(
460*3ac0a46fSAndroid Build Coastguard Worker FPDFText_FindStart(textpage, aaaa.get(), FPDF_CONSECUTIVE, 0));
461*3ac0a46fSAndroid Build Coastguard Worker EXPECT_TRUE(search);
462*3ac0a46fSAndroid Build Coastguard Worker
463*3ac0a46fSAndroid Build Coastguard Worker // Remains not found until advanced.
464*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(0, FPDFText_GetSchResultIndex(search.get()));
465*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(0, FPDFText_GetSchCount(search.get()));
466*3ac0a46fSAndroid Build Coastguard Worker
467*3ac0a46fSAndroid Build Coastguard Worker // Find consecutive occurrences of "aaaa" in this test page:
468*3ac0a46fSAndroid Build Coastguard Worker for (int i = 0; i < 7; ++i) {
469*3ac0a46fSAndroid Build Coastguard Worker EXPECT_TRUE(FPDFText_FindNext(search.get()));
470*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(i, FPDFText_GetSchResultIndex(search.get()));
471*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(4, FPDFText_GetSchCount(search.get()));
472*3ac0a46fSAndroid Build Coastguard Worker }
473*3ac0a46fSAndroid Build Coastguard Worker
474*3ac0a46fSAndroid Build Coastguard Worker // Found position unchanged when fails to advance.
475*3ac0a46fSAndroid Build Coastguard Worker EXPECT_FALSE(FPDFText_FindNext(search.get()));
476*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(6, FPDFText_GetSchResultIndex(search.get()));
477*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(4, FPDFText_GetSchCount(search.get()));
478*3ac0a46fSAndroid Build Coastguard Worker
479*3ac0a46fSAndroid Build Coastguard Worker for (int i = 5; i >= 0; --i) {
480*3ac0a46fSAndroid Build Coastguard Worker EXPECT_TRUE(FPDFText_FindPrev(search.get()));
481*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(i, FPDFText_GetSchResultIndex(search.get()));
482*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(4, FPDFText_GetSchCount(search.get()));
483*3ac0a46fSAndroid Build Coastguard Worker }
484*3ac0a46fSAndroid Build Coastguard Worker
485*3ac0a46fSAndroid Build Coastguard Worker // Found position unchanged when fails to retreat.
486*3ac0a46fSAndroid Build Coastguard Worker EXPECT_FALSE(FPDFText_FindPrev(search.get()));
487*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(0, FPDFText_GetSchResultIndex(search.get()));
488*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(4, FPDFText_GetSchCount(search.get()));
489*3ac0a46fSAndroid Build Coastguard Worker }
490*3ac0a46fSAndroid Build Coastguard Worker
491*3ac0a46fSAndroid Build Coastguard Worker FPDFText_ClosePage(textpage);
492*3ac0a46fSAndroid Build Coastguard Worker UnloadPage(page);
493*3ac0a46fSAndroid Build Coastguard Worker }
494*3ac0a46fSAndroid Build Coastguard Worker
495*3ac0a46fSAndroid Build Coastguard Worker // Fails on Windows. https://crbug.com/pdfium/1370
496*3ac0a46fSAndroid Build Coastguard Worker #if BUILDFLAG(IS_WIN)
497*3ac0a46fSAndroid Build Coastguard Worker #define MAYBE_TextSearchLatinExtended DISABLED_TextSearchLatinExtended
498*3ac0a46fSAndroid Build Coastguard Worker #else
499*3ac0a46fSAndroid Build Coastguard Worker #define MAYBE_TextSearchLatinExtended TextSearchLatinExtended
500*3ac0a46fSAndroid Build Coastguard Worker #endif
TEST_F(FPDFTextEmbedderTest,MAYBE_TextSearchLatinExtended)501*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFTextEmbedderTest, MAYBE_TextSearchLatinExtended) {
502*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(OpenDocument("latin_extended.pdf"));
503*3ac0a46fSAndroid Build Coastguard Worker FPDF_PAGE page = LoadPage(0);
504*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(page);
505*3ac0a46fSAndroid Build Coastguard Worker
506*3ac0a46fSAndroid Build Coastguard Worker FPDF_TEXTPAGE textpage = FPDFText_LoadPage(page);
507*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(textpage);
508*3ac0a46fSAndroid Build Coastguard Worker
509*3ac0a46fSAndroid Build Coastguard Worker // Upper/lowercase 'a' with breve.
510*3ac0a46fSAndroid Build Coastguard Worker constexpr FPDF_WCHAR kNeedleUpper[] = {0x0102, 0x0000};
511*3ac0a46fSAndroid Build Coastguard Worker constexpr FPDF_WCHAR kNeedleLower[] = {0x0103, 0x0000};
512*3ac0a46fSAndroid Build Coastguard Worker
513*3ac0a46fSAndroid Build Coastguard Worker for (const auto* needle : {kNeedleUpper, kNeedleLower}) {
514*3ac0a46fSAndroid Build Coastguard Worker ScopedFPDFTextFind search(FPDFText_FindStart(textpage, needle, 0, 0));
515*3ac0a46fSAndroid Build Coastguard Worker EXPECT_TRUE(search);
516*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(0, FPDFText_GetSchResultIndex(search.get()));
517*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(0, FPDFText_GetSchCount(search.get()));
518*3ac0a46fSAndroid Build Coastguard Worker
519*3ac0a46fSAndroid Build Coastguard Worker // Should find 2 results at position 21/22, both with length 1.
520*3ac0a46fSAndroid Build Coastguard Worker EXPECT_TRUE(FPDFText_FindNext(search.get()));
521*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(2, FPDFText_GetSchResultIndex(search.get()));
522*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(1, FPDFText_GetSchCount(search.get()));
523*3ac0a46fSAndroid Build Coastguard Worker EXPECT_TRUE(FPDFText_FindNext(search.get()));
524*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(3, FPDFText_GetSchResultIndex(search.get()));
525*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(1, FPDFText_GetSchCount(search.get()));
526*3ac0a46fSAndroid Build Coastguard Worker // And no more than 2 results.
527*3ac0a46fSAndroid Build Coastguard Worker EXPECT_FALSE(FPDFText_FindNext(search.get()));
528*3ac0a46fSAndroid Build Coastguard Worker }
529*3ac0a46fSAndroid Build Coastguard Worker
530*3ac0a46fSAndroid Build Coastguard Worker FPDFText_ClosePage(textpage);
531*3ac0a46fSAndroid Build Coastguard Worker UnloadPage(page);
532*3ac0a46fSAndroid Build Coastguard Worker }
533*3ac0a46fSAndroid Build Coastguard Worker
534*3ac0a46fSAndroid Build Coastguard Worker // Test that the page has characters despite a bad stream length.
TEST_F(FPDFTextEmbedderTest,StreamLengthPastEndOfFile)535*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFTextEmbedderTest, StreamLengthPastEndOfFile) {
536*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(OpenDocument("bug_57.pdf"));
537*3ac0a46fSAndroid Build Coastguard Worker FPDF_PAGE page = LoadPage(0);
538*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(page);
539*3ac0a46fSAndroid Build Coastguard Worker
540*3ac0a46fSAndroid Build Coastguard Worker FPDF_TEXTPAGE textpage = FPDFText_LoadPage(page);
541*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(textpage);
542*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(13, FPDFText_CountChars(textpage));
543*3ac0a46fSAndroid Build Coastguard Worker
544*3ac0a46fSAndroid Build Coastguard Worker FPDFText_ClosePage(textpage);
545*3ac0a46fSAndroid Build Coastguard Worker UnloadPage(page);
546*3ac0a46fSAndroid Build Coastguard Worker }
547*3ac0a46fSAndroid Build Coastguard Worker
TEST_F(FPDFTextEmbedderTest,WebLinks)548*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFTextEmbedderTest, WebLinks) {
549*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(OpenDocument("weblinks.pdf"));
550*3ac0a46fSAndroid Build Coastguard Worker FPDF_PAGE page = LoadPage(0);
551*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(page);
552*3ac0a46fSAndroid Build Coastguard Worker
553*3ac0a46fSAndroid Build Coastguard Worker FPDF_TEXTPAGE textpage = FPDFText_LoadPage(page);
554*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(textpage);
555*3ac0a46fSAndroid Build Coastguard Worker
556*3ac0a46fSAndroid Build Coastguard Worker {
557*3ac0a46fSAndroid Build Coastguard Worker ScopedFPDFPageLink pagelink(FPDFLink_LoadWebLinks(textpage));
558*3ac0a46fSAndroid Build Coastguard Worker EXPECT_TRUE(pagelink);
559*3ac0a46fSAndroid Build Coastguard Worker
560*3ac0a46fSAndroid Build Coastguard Worker // Page contains two HTTP-style URLs.
561*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(2, FPDFLink_CountWebLinks(pagelink.get()));
562*3ac0a46fSAndroid Build Coastguard Worker
563*3ac0a46fSAndroid Build Coastguard Worker // Only a terminating NUL required for bogus links.
564*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(1, FPDFLink_GetURL(pagelink.get(), 2, nullptr, 0));
565*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(1, FPDFLink_GetURL(pagelink.get(), 1400, nullptr, 0));
566*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(1, FPDFLink_GetURL(pagelink.get(), -1, nullptr, 0));
567*3ac0a46fSAndroid Build Coastguard Worker }
568*3ac0a46fSAndroid Build Coastguard Worker
569*3ac0a46fSAndroid Build Coastguard Worker FPDF_PAGELINK pagelink = FPDFLink_LoadWebLinks(textpage);
570*3ac0a46fSAndroid Build Coastguard Worker EXPECT_TRUE(pagelink);
571*3ac0a46fSAndroid Build Coastguard Worker
572*3ac0a46fSAndroid Build Coastguard Worker // Query the number of characters required for each link (incl NUL).
573*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(25, FPDFLink_GetURL(pagelink, 0, nullptr, 0));
574*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(26, FPDFLink_GetURL(pagelink, 1, nullptr, 0));
575*3ac0a46fSAndroid Build Coastguard Worker
576*3ac0a46fSAndroid Build Coastguard Worker static const char expected_url[] = "http://example.com?q=foo";
577*3ac0a46fSAndroid Build Coastguard Worker static const size_t expected_len = sizeof(expected_url);
578*3ac0a46fSAndroid Build Coastguard Worker unsigned short buffer[128];
579*3ac0a46fSAndroid Build Coastguard Worker
580*3ac0a46fSAndroid Build Coastguard Worker // Retrieve a link with too small a buffer. Buffer will not be
581*3ac0a46fSAndroid Build Coastguard Worker // NUL-terminated, but must not be modified past indicated length,
582*3ac0a46fSAndroid Build Coastguard Worker // so pre-fill with a pattern to check write bounds.
583*3ac0a46fSAndroid Build Coastguard Worker memset(buffer, 0xbd, sizeof(buffer));
584*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(1, FPDFLink_GetURL(pagelink, 0, buffer, 1));
585*3ac0a46fSAndroid Build Coastguard Worker EXPECT_TRUE(check_unsigned_shorts(expected_url, buffer, 1));
586*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(0xbdbd, buffer[1]);
587*3ac0a46fSAndroid Build Coastguard Worker
588*3ac0a46fSAndroid Build Coastguard Worker // Check buffer that doesn't have space for a terminating NUL.
589*3ac0a46fSAndroid Build Coastguard Worker memset(buffer, 0xbd, sizeof(buffer));
590*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(static_cast<int>(expected_len - 1),
591*3ac0a46fSAndroid Build Coastguard Worker FPDFLink_GetURL(pagelink, 0, buffer, expected_len - 1));
592*3ac0a46fSAndroid Build Coastguard Worker EXPECT_TRUE(check_unsigned_shorts(expected_url, buffer, expected_len - 1));
593*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(0xbdbd, buffer[expected_len - 1]);
594*3ac0a46fSAndroid Build Coastguard Worker
595*3ac0a46fSAndroid Build Coastguard Worker // Retreive link with exactly-sized buffer.
596*3ac0a46fSAndroid Build Coastguard Worker memset(buffer, 0xbd, sizeof(buffer));
597*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(static_cast<int>(expected_len),
598*3ac0a46fSAndroid Build Coastguard Worker FPDFLink_GetURL(pagelink, 0, buffer, expected_len));
599*3ac0a46fSAndroid Build Coastguard Worker EXPECT_TRUE(check_unsigned_shorts(expected_url, buffer, expected_len));
600*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(0u, buffer[expected_len - 1]);
601*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(0xbdbd, buffer[expected_len]);
602*3ac0a46fSAndroid Build Coastguard Worker
603*3ac0a46fSAndroid Build Coastguard Worker // Retreive link with ample-sized-buffer.
604*3ac0a46fSAndroid Build Coastguard Worker memset(buffer, 0xbd, sizeof(buffer));
605*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(static_cast<int>(expected_len),
606*3ac0a46fSAndroid Build Coastguard Worker FPDFLink_GetURL(pagelink, 0, buffer, 128));
607*3ac0a46fSAndroid Build Coastguard Worker EXPECT_TRUE(check_unsigned_shorts(expected_url, buffer, expected_len));
608*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(0u, buffer[expected_len - 1]);
609*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(0xbdbd, buffer[expected_len]);
610*3ac0a46fSAndroid Build Coastguard Worker
611*3ac0a46fSAndroid Build Coastguard Worker // Each link rendered in a single rect in this test page.
612*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(1, FPDFLink_CountRects(pagelink, 0));
613*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(1, FPDFLink_CountRects(pagelink, 1));
614*3ac0a46fSAndroid Build Coastguard Worker
615*3ac0a46fSAndroid Build Coastguard Worker // Each link rendered in a single rect in this test page.
616*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(0, FPDFLink_CountRects(pagelink, -1));
617*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(0, FPDFLink_CountRects(pagelink, 2));
618*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(0, FPDFLink_CountRects(pagelink, 10000));
619*3ac0a46fSAndroid Build Coastguard Worker
620*3ac0a46fSAndroid Build Coastguard Worker // Check boundary of valid link index with valid rect index.
621*3ac0a46fSAndroid Build Coastguard Worker double left = 0.0;
622*3ac0a46fSAndroid Build Coastguard Worker double right = 0.0;
623*3ac0a46fSAndroid Build Coastguard Worker double top = 0.0;
624*3ac0a46fSAndroid Build Coastguard Worker double bottom = 0.0;
625*3ac0a46fSAndroid Build Coastguard Worker EXPECT_TRUE(FPDFLink_GetRect(pagelink, 0, 0, &left, &top, &right, &bottom));
626*3ac0a46fSAndroid Build Coastguard Worker EXPECT_NEAR(50.828, left, 0.001);
627*3ac0a46fSAndroid Build Coastguard Worker EXPECT_NEAR(187.904, right, 0.001);
628*3ac0a46fSAndroid Build Coastguard Worker EXPECT_NEAR(97.516, bottom, 0.001);
629*3ac0a46fSAndroid Build Coastguard Worker EXPECT_NEAR(108.700, top, 0.001);
630*3ac0a46fSAndroid Build Coastguard Worker
631*3ac0a46fSAndroid Build Coastguard Worker // Check that valid link with invalid rect index leaves parameters unchanged.
632*3ac0a46fSAndroid Build Coastguard Worker left = -1.0;
633*3ac0a46fSAndroid Build Coastguard Worker right = -1.0;
634*3ac0a46fSAndroid Build Coastguard Worker top = -1.0;
635*3ac0a46fSAndroid Build Coastguard Worker bottom = -1.0;
636*3ac0a46fSAndroid Build Coastguard Worker EXPECT_FALSE(FPDFLink_GetRect(pagelink, 0, 1, &left, &top, &right, &bottom));
637*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(-1.0, left);
638*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(-1.0, right);
639*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(-1.0, bottom);
640*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(-1.0, top);
641*3ac0a46fSAndroid Build Coastguard Worker
642*3ac0a46fSAndroid Build Coastguard Worker // Check that invalid link index leaves parameters unchanged.
643*3ac0a46fSAndroid Build Coastguard Worker left = -2.0;
644*3ac0a46fSAndroid Build Coastguard Worker right = -2.0;
645*3ac0a46fSAndroid Build Coastguard Worker top = -2.0;
646*3ac0a46fSAndroid Build Coastguard Worker bottom = -2.0;
647*3ac0a46fSAndroid Build Coastguard Worker EXPECT_FALSE(FPDFLink_GetRect(pagelink, -1, 0, &left, &top, &right, &bottom));
648*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(-2.0, left);
649*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(-2.0, right);
650*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(-2.0, bottom);
651*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(-2.0, top);
652*3ac0a46fSAndroid Build Coastguard Worker
653*3ac0a46fSAndroid Build Coastguard Worker FPDFLink_CloseWebLinks(pagelink);
654*3ac0a46fSAndroid Build Coastguard Worker FPDFText_ClosePage(textpage);
655*3ac0a46fSAndroid Build Coastguard Worker UnloadPage(page);
656*3ac0a46fSAndroid Build Coastguard Worker }
657*3ac0a46fSAndroid Build Coastguard Worker
TEST_F(FPDFTextEmbedderTest,WebLinksAcrossLines)658*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFTextEmbedderTest, WebLinksAcrossLines) {
659*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(OpenDocument("weblinks_across_lines.pdf"));
660*3ac0a46fSAndroid Build Coastguard Worker FPDF_PAGE page = LoadPage(0);
661*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(page);
662*3ac0a46fSAndroid Build Coastguard Worker
663*3ac0a46fSAndroid Build Coastguard Worker FPDF_TEXTPAGE textpage = FPDFText_LoadPage(page);
664*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(textpage);
665*3ac0a46fSAndroid Build Coastguard Worker
666*3ac0a46fSAndroid Build Coastguard Worker FPDF_PAGELINK pagelink = FPDFLink_LoadWebLinks(textpage);
667*3ac0a46fSAndroid Build Coastguard Worker EXPECT_TRUE(pagelink);
668*3ac0a46fSAndroid Build Coastguard Worker
669*3ac0a46fSAndroid Build Coastguard Worker static const char* const kExpectedUrls[] = {
670*3ac0a46fSAndroid Build Coastguard Worker "http://example.com", // from "http://www.example.com?\r\nfoo"
671*3ac0a46fSAndroid Build Coastguard Worker "http://example.com/", // from "http://www.example.com/\r\nfoo"
672*3ac0a46fSAndroid Build Coastguard Worker "http://example.com/test-foo", // from "http://example.com/test-\r\nfoo"
673*3ac0a46fSAndroid Build Coastguard Worker "http://abc.com/test-foo", // from "http://abc.com/test-\r\n\r\nfoo"
674*3ac0a46fSAndroid Build Coastguard Worker // Next two links from "http://www.example.com/\r\nhttp://www.abc.com/"
675*3ac0a46fSAndroid Build Coastguard Worker "http://example.com/",
676*3ac0a46fSAndroid Build Coastguard Worker "http://www.abc.com",
677*3ac0a46fSAndroid Build Coastguard Worker };
678*3ac0a46fSAndroid Build Coastguard Worker static const int kNumLinks = static_cast<int>(std::size(kExpectedUrls));
679*3ac0a46fSAndroid Build Coastguard Worker
680*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(kNumLinks, FPDFLink_CountWebLinks(pagelink));
681*3ac0a46fSAndroid Build Coastguard Worker
682*3ac0a46fSAndroid Build Coastguard Worker unsigned short buffer[128];
683*3ac0a46fSAndroid Build Coastguard Worker for (int i = 0; i < kNumLinks; i++) {
684*3ac0a46fSAndroid Build Coastguard Worker const size_t expected_len = strlen(kExpectedUrls[i]) + 1;
685*3ac0a46fSAndroid Build Coastguard Worker memset(buffer, 0, sizeof(buffer));
686*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(static_cast<int>(expected_len),
687*3ac0a46fSAndroid Build Coastguard Worker FPDFLink_GetURL(pagelink, i, nullptr, 0));
688*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(static_cast<int>(expected_len),
689*3ac0a46fSAndroid Build Coastguard Worker FPDFLink_GetURL(pagelink, i, buffer, std::size(buffer)));
690*3ac0a46fSAndroid Build Coastguard Worker EXPECT_TRUE(check_unsigned_shorts(kExpectedUrls[i], buffer, expected_len));
691*3ac0a46fSAndroid Build Coastguard Worker }
692*3ac0a46fSAndroid Build Coastguard Worker
693*3ac0a46fSAndroid Build Coastguard Worker FPDFLink_CloseWebLinks(pagelink);
694*3ac0a46fSAndroid Build Coastguard Worker FPDFText_ClosePage(textpage);
695*3ac0a46fSAndroid Build Coastguard Worker UnloadPage(page);
696*3ac0a46fSAndroid Build Coastguard Worker }
697*3ac0a46fSAndroid Build Coastguard Worker
TEST_F(FPDFTextEmbedderTest,WebLinksAcrossLinesBug)698*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFTextEmbedderTest, WebLinksAcrossLinesBug) {
699*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(OpenDocument("bug_650.pdf"));
700*3ac0a46fSAndroid Build Coastguard Worker FPDF_PAGE page = LoadPage(0);
701*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(page);
702*3ac0a46fSAndroid Build Coastguard Worker
703*3ac0a46fSAndroid Build Coastguard Worker FPDF_TEXTPAGE textpage = FPDFText_LoadPage(page);
704*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(textpage);
705*3ac0a46fSAndroid Build Coastguard Worker
706*3ac0a46fSAndroid Build Coastguard Worker FPDF_PAGELINK pagelink = FPDFLink_LoadWebLinks(textpage);
707*3ac0a46fSAndroid Build Coastguard Worker EXPECT_TRUE(pagelink);
708*3ac0a46fSAndroid Build Coastguard Worker
709*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(2, FPDFLink_CountWebLinks(pagelink));
710*3ac0a46fSAndroid Build Coastguard Worker unsigned short buffer[128] = {0};
711*3ac0a46fSAndroid Build Coastguard Worker static const char kExpectedUrl[] =
712*3ac0a46fSAndroid Build Coastguard Worker "http://tutorial45.com/learn-autocad-basics-day-166/";
713*3ac0a46fSAndroid Build Coastguard Worker static const int kUrlSize = static_cast<int>(sizeof(kExpectedUrl));
714*3ac0a46fSAndroid Build Coastguard Worker
715*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(kUrlSize, FPDFLink_GetURL(pagelink, 1, nullptr, 0));
716*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(kUrlSize, FPDFLink_GetURL(pagelink, 1, buffer, std::size(buffer)));
717*3ac0a46fSAndroid Build Coastguard Worker EXPECT_TRUE(check_unsigned_shorts(kExpectedUrl, buffer, kUrlSize));
718*3ac0a46fSAndroid Build Coastguard Worker
719*3ac0a46fSAndroid Build Coastguard Worker FPDFLink_CloseWebLinks(pagelink);
720*3ac0a46fSAndroid Build Coastguard Worker FPDFText_ClosePage(textpage);
721*3ac0a46fSAndroid Build Coastguard Worker UnloadPage(page);
722*3ac0a46fSAndroid Build Coastguard Worker }
723*3ac0a46fSAndroid Build Coastguard Worker
TEST_F(FPDFTextEmbedderTest,WebLinksCharRanges)724*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFTextEmbedderTest, WebLinksCharRanges) {
725*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(OpenDocument("weblinks.pdf"));
726*3ac0a46fSAndroid Build Coastguard Worker FPDF_PAGE page = LoadPage(0);
727*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(page);
728*3ac0a46fSAndroid Build Coastguard Worker
729*3ac0a46fSAndroid Build Coastguard Worker FPDF_TEXTPAGE text_page = FPDFText_LoadPage(page);
730*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(text_page);
731*3ac0a46fSAndroid Build Coastguard Worker
732*3ac0a46fSAndroid Build Coastguard Worker FPDF_PAGELINK page_link = FPDFLink_LoadWebLinks(text_page);
733*3ac0a46fSAndroid Build Coastguard Worker EXPECT_TRUE(page_link);
734*3ac0a46fSAndroid Build Coastguard Worker
735*3ac0a46fSAndroid Build Coastguard Worker // Test for char indices of a valid link
736*3ac0a46fSAndroid Build Coastguard Worker int start_char_index;
737*3ac0a46fSAndroid Build Coastguard Worker int char_count;
738*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(
739*3ac0a46fSAndroid Build Coastguard Worker FPDFLink_GetTextRange(page_link, 0, &start_char_index, &char_count));
740*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(35, start_char_index);
741*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(24, char_count);
742*3ac0a46fSAndroid Build Coastguard Worker
743*3ac0a46fSAndroid Build Coastguard Worker // Test for char indices of an invalid link
744*3ac0a46fSAndroid Build Coastguard Worker start_char_index = -10;
745*3ac0a46fSAndroid Build Coastguard Worker char_count = -8;
746*3ac0a46fSAndroid Build Coastguard Worker ASSERT_FALSE(
747*3ac0a46fSAndroid Build Coastguard Worker FPDFLink_GetTextRange(page_link, 6, &start_char_index, &char_count));
748*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(start_char_index, -10);
749*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(char_count, -8);
750*3ac0a46fSAndroid Build Coastguard Worker
751*3ac0a46fSAndroid Build Coastguard Worker // Test for pagelink = nullptr
752*3ac0a46fSAndroid Build Coastguard Worker start_char_index = -10;
753*3ac0a46fSAndroid Build Coastguard Worker char_count = -8;
754*3ac0a46fSAndroid Build Coastguard Worker ASSERT_FALSE(
755*3ac0a46fSAndroid Build Coastguard Worker FPDFLink_GetTextRange(nullptr, 0, &start_char_index, &char_count));
756*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(start_char_index, -10);
757*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(char_count, -8);
758*3ac0a46fSAndroid Build Coastguard Worker
759*3ac0a46fSAndroid Build Coastguard Worker // Test for link_index < 0
760*3ac0a46fSAndroid Build Coastguard Worker start_char_index = -10;
761*3ac0a46fSAndroid Build Coastguard Worker char_count = -8;
762*3ac0a46fSAndroid Build Coastguard Worker ASSERT_FALSE(
763*3ac0a46fSAndroid Build Coastguard Worker FPDFLink_GetTextRange(page_link, -4, &start_char_index, &char_count));
764*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(start_char_index, -10);
765*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(char_count, -8);
766*3ac0a46fSAndroid Build Coastguard Worker
767*3ac0a46fSAndroid Build Coastguard Worker FPDFLink_CloseWebLinks(page_link);
768*3ac0a46fSAndroid Build Coastguard Worker FPDFText_ClosePage(text_page);
769*3ac0a46fSAndroid Build Coastguard Worker UnloadPage(page);
770*3ac0a46fSAndroid Build Coastguard Worker }
771*3ac0a46fSAndroid Build Coastguard Worker
TEST_F(FPDFTextEmbedderTest,AnnotLinks)772*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFTextEmbedderTest, AnnotLinks) {
773*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(OpenDocument("annots.pdf"));
774*3ac0a46fSAndroid Build Coastguard Worker FPDF_PAGE page = LoadPage(0);
775*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(page);
776*3ac0a46fSAndroid Build Coastguard Worker
777*3ac0a46fSAndroid Build Coastguard Worker // Get link count via checking annotation subtype
778*3ac0a46fSAndroid Build Coastguard Worker int annot_count = FPDFPage_GetAnnotCount(page);
779*3ac0a46fSAndroid Build Coastguard Worker ASSERT_EQ(9, annot_count);
780*3ac0a46fSAndroid Build Coastguard Worker int annot_subtype_link_count = 0;
781*3ac0a46fSAndroid Build Coastguard Worker for (int i = 0; i < annot_count; ++i) {
782*3ac0a46fSAndroid Build Coastguard Worker ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, i));
783*3ac0a46fSAndroid Build Coastguard Worker if (FPDFAnnot_GetSubtype(annot.get()) == FPDF_ANNOT_LINK) {
784*3ac0a46fSAndroid Build Coastguard Worker ++annot_subtype_link_count;
785*3ac0a46fSAndroid Build Coastguard Worker }
786*3ac0a46fSAndroid Build Coastguard Worker }
787*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(4, annot_subtype_link_count);
788*3ac0a46fSAndroid Build Coastguard Worker
789*3ac0a46fSAndroid Build Coastguard Worker // Validate that FPDFLink_Enumerate() returns same number of links
790*3ac0a46fSAndroid Build Coastguard Worker int start_pos = 0;
791*3ac0a46fSAndroid Build Coastguard Worker FPDF_LINK link_annot;
792*3ac0a46fSAndroid Build Coastguard Worker int link_count = 0;
793*3ac0a46fSAndroid Build Coastguard Worker while (FPDFLink_Enumerate(page, &start_pos, &link_annot)) {
794*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(link_annot);
795*3ac0a46fSAndroid Build Coastguard Worker if (start_pos == 1 || start_pos == 2) {
796*3ac0a46fSAndroid Build Coastguard Worker // First two links point to first and second page within the document
797*3ac0a46fSAndroid Build Coastguard Worker // respectively
798*3ac0a46fSAndroid Build Coastguard Worker FPDF_DEST link_dest = FPDFLink_GetDest(document(), link_annot);
799*3ac0a46fSAndroid Build Coastguard Worker EXPECT_TRUE(link_dest);
800*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(start_pos - 1,
801*3ac0a46fSAndroid Build Coastguard Worker FPDFDest_GetDestPageIndex(document(), link_dest));
802*3ac0a46fSAndroid Build Coastguard Worker } else if (start_pos == 3) { // points to PDF Spec URL
803*3ac0a46fSAndroid Build Coastguard Worker FS_RECTF link_rect;
804*3ac0a46fSAndroid Build Coastguard Worker EXPECT_TRUE(FPDFLink_GetAnnotRect(link_annot, &link_rect));
805*3ac0a46fSAndroid Build Coastguard Worker EXPECT_NEAR(66.0, link_rect.left, 0.001);
806*3ac0a46fSAndroid Build Coastguard Worker EXPECT_NEAR(544.0, link_rect.top, 0.001);
807*3ac0a46fSAndroid Build Coastguard Worker EXPECT_NEAR(196.0, link_rect.right, 0.001);
808*3ac0a46fSAndroid Build Coastguard Worker EXPECT_NEAR(529.0, link_rect.bottom, 0.001);
809*3ac0a46fSAndroid Build Coastguard Worker } else if (start_pos == 4) { // this link has quad points
810*3ac0a46fSAndroid Build Coastguard Worker int quad_point_count = FPDFLink_CountQuadPoints(link_annot);
811*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(1, quad_point_count);
812*3ac0a46fSAndroid Build Coastguard Worker FS_QUADPOINTSF quad_points;
813*3ac0a46fSAndroid Build Coastguard Worker EXPECT_TRUE(FPDFLink_GetQuadPoints(link_annot, 0, &quad_points));
814*3ac0a46fSAndroid Build Coastguard Worker EXPECT_NEAR(83.0, quad_points.x1, 0.001);
815*3ac0a46fSAndroid Build Coastguard Worker EXPECT_NEAR(453.0, quad_points.y1, 0.001);
816*3ac0a46fSAndroid Build Coastguard Worker EXPECT_NEAR(178.0, quad_points.x2, 0.001);
817*3ac0a46fSAndroid Build Coastguard Worker EXPECT_NEAR(453.0, quad_points.y2, 0.001);
818*3ac0a46fSAndroid Build Coastguard Worker EXPECT_NEAR(83.0, quad_points.x3, 0.001);
819*3ac0a46fSAndroid Build Coastguard Worker EXPECT_NEAR(440.0, quad_points.y3, 0.001);
820*3ac0a46fSAndroid Build Coastguard Worker EXPECT_NEAR(178.0, quad_points.x4, 0.001);
821*3ac0a46fSAndroid Build Coastguard Worker EXPECT_NEAR(440.0, quad_points.y4, 0.001);
822*3ac0a46fSAndroid Build Coastguard Worker // AnnotRect is same as quad points for this link
823*3ac0a46fSAndroid Build Coastguard Worker FS_RECTF link_rect;
824*3ac0a46fSAndroid Build Coastguard Worker EXPECT_TRUE(FPDFLink_GetAnnotRect(link_annot, &link_rect));
825*3ac0a46fSAndroid Build Coastguard Worker EXPECT_NEAR(link_rect.left, quad_points.x1, 0.001);
826*3ac0a46fSAndroid Build Coastguard Worker EXPECT_NEAR(link_rect.top, quad_points.y1, 0.001);
827*3ac0a46fSAndroid Build Coastguard Worker EXPECT_NEAR(link_rect.right, quad_points.x4, 0.001);
828*3ac0a46fSAndroid Build Coastguard Worker EXPECT_NEAR(link_rect.bottom, quad_points.y4, 0.001);
829*3ac0a46fSAndroid Build Coastguard Worker }
830*3ac0a46fSAndroid Build Coastguard Worker ++link_count;
831*3ac0a46fSAndroid Build Coastguard Worker }
832*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(annot_subtype_link_count, link_count);
833*3ac0a46fSAndroid Build Coastguard Worker
834*3ac0a46fSAndroid Build Coastguard Worker UnloadPage(page);
835*3ac0a46fSAndroid Build Coastguard Worker }
836*3ac0a46fSAndroid Build Coastguard Worker
TEST_F(FPDFTextEmbedderTest,GetFontSize)837*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFTextEmbedderTest, GetFontSize) {
838*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(OpenDocument("hello_world.pdf"));
839*3ac0a46fSAndroid Build Coastguard Worker FPDF_PAGE page = LoadPage(0);
840*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(page);
841*3ac0a46fSAndroid Build Coastguard Worker
842*3ac0a46fSAndroid Build Coastguard Worker FPDF_TEXTPAGE textpage = FPDFText_LoadPage(page);
843*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(textpage);
844*3ac0a46fSAndroid Build Coastguard Worker
845*3ac0a46fSAndroid Build Coastguard Worker const double kExpectedFontsSizes[] = {12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
846*3ac0a46fSAndroid Build Coastguard Worker 12, 12, 12, 1, 1, 16, 16, 16, 16, 16,
847*3ac0a46fSAndroid Build Coastguard Worker 16, 16, 16, 16, 16, 16, 16, 16, 16, 16};
848*3ac0a46fSAndroid Build Coastguard Worker
849*3ac0a46fSAndroid Build Coastguard Worker int count = FPDFText_CountChars(textpage);
850*3ac0a46fSAndroid Build Coastguard Worker ASSERT_EQ(std::size(kExpectedFontsSizes), static_cast<size_t>(count));
851*3ac0a46fSAndroid Build Coastguard Worker for (int i = 0; i < count; ++i)
852*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(kExpectedFontsSizes[i], FPDFText_GetFontSize(textpage, i)) << i;
853*3ac0a46fSAndroid Build Coastguard Worker
854*3ac0a46fSAndroid Build Coastguard Worker FPDFText_ClosePage(textpage);
855*3ac0a46fSAndroid Build Coastguard Worker UnloadPage(page);
856*3ac0a46fSAndroid Build Coastguard Worker }
857*3ac0a46fSAndroid Build Coastguard Worker
TEST_F(FPDFTextEmbedderTest,GetFontInfo)858*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFTextEmbedderTest, GetFontInfo) {
859*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(OpenDocument("hello_world.pdf"));
860*3ac0a46fSAndroid Build Coastguard Worker FPDF_PAGE page = LoadPage(0);
861*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(page);
862*3ac0a46fSAndroid Build Coastguard Worker
863*3ac0a46fSAndroid Build Coastguard Worker FPDF_TEXTPAGE textpage = FPDFText_LoadPage(page);
864*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(textpage);
865*3ac0a46fSAndroid Build Coastguard Worker std::vector<char> font_name;
866*3ac0a46fSAndroid Build Coastguard Worker size_t num_chars1 = strlen("Hello, world!");
867*3ac0a46fSAndroid Build Coastguard Worker const char kExpectedFontName1[] = "Times-Roman";
868*3ac0a46fSAndroid Build Coastguard Worker
869*3ac0a46fSAndroid Build Coastguard Worker for (size_t i = 0; i < num_chars1; i++) {
870*3ac0a46fSAndroid Build Coastguard Worker int flags = -1;
871*3ac0a46fSAndroid Build Coastguard Worker unsigned long length =
872*3ac0a46fSAndroid Build Coastguard Worker FPDFText_GetFontInfo(textpage, i, nullptr, 0, &flags);
873*3ac0a46fSAndroid Build Coastguard Worker static constexpr unsigned long expected_length = sizeof(kExpectedFontName1);
874*3ac0a46fSAndroid Build Coastguard Worker ASSERT_EQ(expected_length, length);
875*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(FXFONT_NONSYMBOLIC, flags);
876*3ac0a46fSAndroid Build Coastguard Worker font_name.resize(length);
877*3ac0a46fSAndroid Build Coastguard Worker std::fill(font_name.begin(), font_name.end(), 'a');
878*3ac0a46fSAndroid Build Coastguard Worker flags = -1;
879*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(expected_length,
880*3ac0a46fSAndroid Build Coastguard Worker FPDFText_GetFontInfo(textpage, i, font_name.data(),
881*3ac0a46fSAndroid Build Coastguard Worker font_name.size(), &flags));
882*3ac0a46fSAndroid Build Coastguard Worker EXPECT_STREQ(kExpectedFontName1, font_name.data());
883*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(FXFONT_NONSYMBOLIC, flags);
884*3ac0a46fSAndroid Build Coastguard Worker }
885*3ac0a46fSAndroid Build Coastguard Worker // If the size of the buffer is not large enough, the buffer should remain
886*3ac0a46fSAndroid Build Coastguard Worker // unchanged.
887*3ac0a46fSAndroid Build Coastguard Worker font_name.pop_back();
888*3ac0a46fSAndroid Build Coastguard Worker std::fill(font_name.begin(), font_name.end(), 'a');
889*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(sizeof(kExpectedFontName1),
890*3ac0a46fSAndroid Build Coastguard Worker FPDFText_GetFontInfo(textpage, 0, font_name.data(),
891*3ac0a46fSAndroid Build Coastguard Worker font_name.size(), nullptr));
892*3ac0a46fSAndroid Build Coastguard Worker for (char a : font_name)
893*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ('a', a);
894*3ac0a46fSAndroid Build Coastguard Worker
895*3ac0a46fSAndroid Build Coastguard Worker // The text is "Hello, world!\r\nGoodbye, world!", so the next two characters
896*3ac0a46fSAndroid Build Coastguard Worker // do not have any font information.
897*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(0u, FPDFText_GetFontInfo(textpage, num_chars1, font_name.data(),
898*3ac0a46fSAndroid Build Coastguard Worker font_name.size(), nullptr));
899*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(0u, FPDFText_GetFontInfo(textpage, num_chars1 + 1, font_name.data(),
900*3ac0a46fSAndroid Build Coastguard Worker font_name.size(), nullptr));
901*3ac0a46fSAndroid Build Coastguard Worker
902*3ac0a46fSAndroid Build Coastguard Worker size_t num_chars2 = strlen("Goodbye, world!");
903*3ac0a46fSAndroid Build Coastguard Worker const char kExpectedFontName2[] = "Helvetica";
904*3ac0a46fSAndroid Build Coastguard Worker for (size_t i = num_chars1 + 2; i < num_chars1 + num_chars2 + 2; i++) {
905*3ac0a46fSAndroid Build Coastguard Worker int flags = -1;
906*3ac0a46fSAndroid Build Coastguard Worker unsigned long length =
907*3ac0a46fSAndroid Build Coastguard Worker FPDFText_GetFontInfo(textpage, i, nullptr, 0, &flags);
908*3ac0a46fSAndroid Build Coastguard Worker static constexpr unsigned long expected_length = sizeof(kExpectedFontName2);
909*3ac0a46fSAndroid Build Coastguard Worker ASSERT_EQ(expected_length, length);
910*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(FXFONT_NONSYMBOLIC, flags);
911*3ac0a46fSAndroid Build Coastguard Worker font_name.resize(length);
912*3ac0a46fSAndroid Build Coastguard Worker std::fill(font_name.begin(), font_name.end(), 'a');
913*3ac0a46fSAndroid Build Coastguard Worker flags = -1;
914*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(expected_length,
915*3ac0a46fSAndroid Build Coastguard Worker FPDFText_GetFontInfo(textpage, i, font_name.data(),
916*3ac0a46fSAndroid Build Coastguard Worker font_name.size(), &flags));
917*3ac0a46fSAndroid Build Coastguard Worker EXPECT_STREQ(kExpectedFontName2, font_name.data());
918*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(FXFONT_NONSYMBOLIC, flags);
919*3ac0a46fSAndroid Build Coastguard Worker }
920*3ac0a46fSAndroid Build Coastguard Worker
921*3ac0a46fSAndroid Build Coastguard Worker // Now try some out of bounds indices and null pointers to make sure we do not
922*3ac0a46fSAndroid Build Coastguard Worker // crash.
923*3ac0a46fSAndroid Build Coastguard Worker // No textpage.
924*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(0u, FPDFText_GetFontInfo(nullptr, 0, font_name.data(),
925*3ac0a46fSAndroid Build Coastguard Worker font_name.size(), nullptr));
926*3ac0a46fSAndroid Build Coastguard Worker // No buffer.
927*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(sizeof(kExpectedFontName1),
928*3ac0a46fSAndroid Build Coastguard Worker FPDFText_GetFontInfo(textpage, 0, nullptr, 0, nullptr));
929*3ac0a46fSAndroid Build Coastguard Worker // Negative index.
930*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(0u, FPDFText_GetFontInfo(textpage, -1, font_name.data(),
931*3ac0a46fSAndroid Build Coastguard Worker font_name.size(), nullptr));
932*3ac0a46fSAndroid Build Coastguard Worker // Out of bounds index.
933*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(0u, FPDFText_GetFontInfo(textpage, 1000, font_name.data(),
934*3ac0a46fSAndroid Build Coastguard Worker font_name.size(), nullptr));
935*3ac0a46fSAndroid Build Coastguard Worker
936*3ac0a46fSAndroid Build Coastguard Worker FPDFText_ClosePage(textpage);
937*3ac0a46fSAndroid Build Coastguard Worker UnloadPage(page);
938*3ac0a46fSAndroid Build Coastguard Worker }
939*3ac0a46fSAndroid Build Coastguard Worker
TEST_F(FPDFTextEmbedderTest,ToUnicode)940*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFTextEmbedderTest, ToUnicode) {
941*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(OpenDocument("bug_583.pdf"));
942*3ac0a46fSAndroid Build Coastguard Worker FPDF_PAGE page = LoadPage(0);
943*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(page);
944*3ac0a46fSAndroid Build Coastguard Worker
945*3ac0a46fSAndroid Build Coastguard Worker FPDF_TEXTPAGE textpage = FPDFText_LoadPage(page);
946*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(textpage);
947*3ac0a46fSAndroid Build Coastguard Worker
948*3ac0a46fSAndroid Build Coastguard Worker ASSERT_EQ(1, FPDFText_CountChars(textpage));
949*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(0U, FPDFText_GetUnicode(textpage, 0));
950*3ac0a46fSAndroid Build Coastguard Worker
951*3ac0a46fSAndroid Build Coastguard Worker FPDFText_ClosePage(textpage);
952*3ac0a46fSAndroid Build Coastguard Worker UnloadPage(page);
953*3ac0a46fSAndroid Build Coastguard Worker }
954*3ac0a46fSAndroid Build Coastguard Worker
TEST_F(FPDFTextEmbedderTest,IsGenerated)955*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFTextEmbedderTest, IsGenerated) {
956*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(OpenDocument("hello_world.pdf"));
957*3ac0a46fSAndroid Build Coastguard Worker FPDF_PAGE page = LoadPage(0);
958*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(page);
959*3ac0a46fSAndroid Build Coastguard Worker
960*3ac0a46fSAndroid Build Coastguard Worker {
961*3ac0a46fSAndroid Build Coastguard Worker ScopedFPDFTextPage textpage(FPDFText_LoadPage(page));
962*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(textpage);
963*3ac0a46fSAndroid Build Coastguard Worker
964*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(static_cast<unsigned int>('H'),
965*3ac0a46fSAndroid Build Coastguard Worker FPDFText_GetUnicode(textpage.get(), 0));
966*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(0, FPDFText_IsGenerated(textpage.get(), 0));
967*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(static_cast<unsigned int>(' '),
968*3ac0a46fSAndroid Build Coastguard Worker FPDFText_GetUnicode(textpage.get(), 6));
969*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(0, FPDFText_IsGenerated(textpage.get(), 6));
970*3ac0a46fSAndroid Build Coastguard Worker
971*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(static_cast<unsigned int>('\r'),
972*3ac0a46fSAndroid Build Coastguard Worker FPDFText_GetUnicode(textpage.get(), 13));
973*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(1, FPDFText_IsGenerated(textpage.get(), 13));
974*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(static_cast<unsigned int>('\n'),
975*3ac0a46fSAndroid Build Coastguard Worker FPDFText_GetUnicode(textpage.get(), 14));
976*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(1, FPDFText_IsGenerated(textpage.get(), 14));
977*3ac0a46fSAndroid Build Coastguard Worker
978*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(-1, FPDFText_IsGenerated(textpage.get(), -1));
979*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(-1, FPDFText_IsGenerated(textpage.get(), kHelloGoodbyeTextSize));
980*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(-1, FPDFText_IsGenerated(nullptr, 6));
981*3ac0a46fSAndroid Build Coastguard Worker }
982*3ac0a46fSAndroid Build Coastguard Worker
983*3ac0a46fSAndroid Build Coastguard Worker UnloadPage(page);
984*3ac0a46fSAndroid Build Coastguard Worker }
985*3ac0a46fSAndroid Build Coastguard Worker
TEST_F(FPDFTextEmbedderTest,IsInvalidUnicode)986*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFTextEmbedderTest, IsInvalidUnicode) {
987*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(OpenDocument("bug_1388_2.pdf"));
988*3ac0a46fSAndroid Build Coastguard Worker FPDF_PAGE page = LoadPage(0);
989*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(page);
990*3ac0a46fSAndroid Build Coastguard Worker
991*3ac0a46fSAndroid Build Coastguard Worker {
992*3ac0a46fSAndroid Build Coastguard Worker constexpr int kExpectedCharCount = 5;
993*3ac0a46fSAndroid Build Coastguard Worker ScopedFPDFTextPage textpage(FPDFText_LoadPage(page));
994*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(textpage);
995*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(kExpectedCharCount, FPDFText_CountChars(textpage.get()));
996*3ac0a46fSAndroid Build Coastguard Worker
997*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(static_cast<unsigned int>('X'),
998*3ac0a46fSAndroid Build Coastguard Worker FPDFText_GetUnicode(textpage.get(), 0));
999*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(0, FPDFText_HasUnicodeMapError(textpage.get(), 0));
1000*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(static_cast<unsigned int>(' '),
1001*3ac0a46fSAndroid Build Coastguard Worker FPDFText_GetUnicode(textpage.get(), 1));
1002*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(0, FPDFText_HasUnicodeMapError(textpage.get(), 1));
1003*3ac0a46fSAndroid Build Coastguard Worker
1004*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(31u, FPDFText_GetUnicode(textpage.get(), 2));
1005*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(1, FPDFText_HasUnicodeMapError(textpage.get(), 2));
1006*3ac0a46fSAndroid Build Coastguard Worker
1007*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(-1, FPDFText_HasUnicodeMapError(textpage.get(), -1));
1008*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(-1,
1009*3ac0a46fSAndroid Build Coastguard Worker FPDFText_HasUnicodeMapError(textpage.get(), kExpectedCharCount));
1010*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(-1, FPDFText_HasUnicodeMapError(nullptr, 0));
1011*3ac0a46fSAndroid Build Coastguard Worker }
1012*3ac0a46fSAndroid Build Coastguard Worker
1013*3ac0a46fSAndroid Build Coastguard Worker UnloadPage(page);
1014*3ac0a46fSAndroid Build Coastguard Worker }
1015*3ac0a46fSAndroid Build Coastguard Worker
TEST_F(FPDFTextEmbedderTest,Bug_921)1016*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFTextEmbedderTest, Bug_921) {
1017*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(OpenDocument("bug_921.pdf"));
1018*3ac0a46fSAndroid Build Coastguard Worker FPDF_PAGE page = LoadPage(0);
1019*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(page);
1020*3ac0a46fSAndroid Build Coastguard Worker
1021*3ac0a46fSAndroid Build Coastguard Worker FPDF_TEXTPAGE textpage = FPDFText_LoadPage(page);
1022*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(textpage);
1023*3ac0a46fSAndroid Build Coastguard Worker
1024*3ac0a46fSAndroid Build Coastguard Worker static constexpr unsigned int kData[] = {
1025*3ac0a46fSAndroid Build Coastguard Worker 1095, 1077, 1083, 1086, 1074, 1077, 1095, 1077, 1089, 1082, 1086, 1077,
1026*3ac0a46fSAndroid Build Coastguard Worker 32, 1089, 1090, 1088, 1072, 1076, 1072, 1085, 1080, 1077, 46, 32};
1027*3ac0a46fSAndroid Build Coastguard Worker static constexpr int kStartIndex = 238;
1028*3ac0a46fSAndroid Build Coastguard Worker
1029*3ac0a46fSAndroid Build Coastguard Worker ASSERT_EQ(268, FPDFText_CountChars(textpage));
1030*3ac0a46fSAndroid Build Coastguard Worker for (size_t i = 0; i < std::size(kData); ++i)
1031*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(kData[i], FPDFText_GetUnicode(textpage, kStartIndex + i));
1032*3ac0a46fSAndroid Build Coastguard Worker
1033*3ac0a46fSAndroid Build Coastguard Worker unsigned short buffer[std::size(kData) + 1];
1034*3ac0a46fSAndroid Build Coastguard Worker memset(buffer, 0xbd, sizeof(buffer));
1035*3ac0a46fSAndroid Build Coastguard Worker int count = FPDFText_GetText(textpage, kStartIndex, std::size(kData), buffer);
1036*3ac0a46fSAndroid Build Coastguard Worker ASSERT_GT(count, 0);
1037*3ac0a46fSAndroid Build Coastguard Worker ASSERT_EQ(std::size(kData) + 1, static_cast<size_t>(count));
1038*3ac0a46fSAndroid Build Coastguard Worker for (size_t i = 0; i < std::size(kData); ++i)
1039*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(kData[i], buffer[i]);
1040*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(0, buffer[std::size(kData)]);
1041*3ac0a46fSAndroid Build Coastguard Worker
1042*3ac0a46fSAndroid Build Coastguard Worker FPDFText_ClosePage(textpage);
1043*3ac0a46fSAndroid Build Coastguard Worker UnloadPage(page);
1044*3ac0a46fSAndroid Build Coastguard Worker }
1045*3ac0a46fSAndroid Build Coastguard Worker
TEST_F(FPDFTextEmbedderTest,GetTextWithHyphen)1046*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFTextEmbedderTest, GetTextWithHyphen) {
1047*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(OpenDocument("bug_781804.pdf"));
1048*3ac0a46fSAndroid Build Coastguard Worker FPDF_PAGE page = LoadPage(0);
1049*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(page);
1050*3ac0a46fSAndroid Build Coastguard Worker
1051*3ac0a46fSAndroid Build Coastguard Worker FPDF_TEXTPAGE textpage = FPDFText_LoadPage(page);
1052*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(textpage);
1053*3ac0a46fSAndroid Build Coastguard Worker
1054*3ac0a46fSAndroid Build Coastguard Worker // Check that soft hyphens are not included
1055*3ac0a46fSAndroid Build Coastguard Worker // Expecting 'Veritaserum', except there is a \uFFFE where the hyphen was in
1056*3ac0a46fSAndroid Build Coastguard Worker // the original text. This is a weird thing that Adobe does, which we
1057*3ac0a46fSAndroid Build Coastguard Worker // replicate.
1058*3ac0a46fSAndroid Build Coastguard Worker constexpr unsigned short soft_expected[] = {
1059*3ac0a46fSAndroid Build Coastguard Worker 0x0056, 0x0065, 0x0072, 0x0069, 0x0074, 0x0061, 0xfffe,
1060*3ac0a46fSAndroid Build Coastguard Worker 0x0073, 0x0065, 0x0072, 0x0075, 0x006D, 0x0000};
1061*3ac0a46fSAndroid Build Coastguard Worker {
1062*3ac0a46fSAndroid Build Coastguard Worker constexpr int count = std::size(soft_expected) - 1;
1063*3ac0a46fSAndroid Build Coastguard Worker unsigned short buffer[std::size(soft_expected)];
1064*3ac0a46fSAndroid Build Coastguard Worker memset(buffer, 0, sizeof(buffer));
1065*3ac0a46fSAndroid Build Coastguard Worker
1066*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(count + 1, FPDFText_GetText(textpage, 0, count, buffer));
1067*3ac0a46fSAndroid Build Coastguard Worker for (int i = 0; i < count; i++)
1068*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(soft_expected[i], buffer[i]);
1069*3ac0a46fSAndroid Build Coastguard Worker }
1070*3ac0a46fSAndroid Build Coastguard Worker
1071*3ac0a46fSAndroid Build Coastguard Worker // Check that hard hyphens are included
1072*3ac0a46fSAndroid Build Coastguard Worker {
1073*3ac0a46fSAndroid Build Coastguard Worker // There isn't the \0 in the actual doc, but there is a \r\n, so need to
1074*3ac0a46fSAndroid Build Coastguard Worker // add 1 to get aligned.
1075*3ac0a46fSAndroid Build Coastguard Worker constexpr size_t offset = std::size(soft_expected) + 1;
1076*3ac0a46fSAndroid Build Coastguard Worker // Expecting 'User-\r\ngenerated', the - is a unicode character, so cannot
1077*3ac0a46fSAndroid Build Coastguard Worker // store in a char[].
1078*3ac0a46fSAndroid Build Coastguard Worker constexpr unsigned short hard_expected[] = {
1079*3ac0a46fSAndroid Build Coastguard Worker 0x0055, 0x0073, 0x0065, 0x0072, 0x2010, 0x000d, 0x000a, 0x0067, 0x0065,
1080*3ac0a46fSAndroid Build Coastguard Worker 0x006e, 0x0065, 0x0072, 0x0061, 0x0074, 0x0065, 0x0064, 0x0000};
1081*3ac0a46fSAndroid Build Coastguard Worker constexpr int count = std::size(hard_expected) - 1;
1082*3ac0a46fSAndroid Build Coastguard Worker unsigned short buffer[std::size(hard_expected)];
1083*3ac0a46fSAndroid Build Coastguard Worker
1084*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(count + 1, FPDFText_GetText(textpage, offset, count, buffer));
1085*3ac0a46fSAndroid Build Coastguard Worker for (int i = 0; i < count; i++)
1086*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(hard_expected[i], buffer[i]);
1087*3ac0a46fSAndroid Build Coastguard Worker }
1088*3ac0a46fSAndroid Build Coastguard Worker
1089*3ac0a46fSAndroid Build Coastguard Worker FPDFText_ClosePage(textpage);
1090*3ac0a46fSAndroid Build Coastguard Worker UnloadPage(page);
1091*3ac0a46fSAndroid Build Coastguard Worker }
1092*3ac0a46fSAndroid Build Coastguard Worker
TEST_F(FPDFTextEmbedderTest,bug_782596)1093*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFTextEmbedderTest, bug_782596) {
1094*3ac0a46fSAndroid Build Coastguard Worker // If there is a regression in this test, it will only fail under ASAN
1095*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(OpenDocument("bug_782596.pdf"));
1096*3ac0a46fSAndroid Build Coastguard Worker FPDF_PAGE page = LoadPage(0);
1097*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(page);
1098*3ac0a46fSAndroid Build Coastguard Worker FPDF_TEXTPAGE textpage = FPDFText_LoadPage(page);
1099*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(textpage);
1100*3ac0a46fSAndroid Build Coastguard Worker FPDFText_ClosePage(textpage);
1101*3ac0a46fSAndroid Build Coastguard Worker UnloadPage(page);
1102*3ac0a46fSAndroid Build Coastguard Worker }
1103*3ac0a46fSAndroid Build Coastguard Worker
TEST_F(FPDFTextEmbedderTest,ControlCharacters)1104*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFTextEmbedderTest, ControlCharacters) {
1105*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(OpenDocument("control_characters.pdf"));
1106*3ac0a46fSAndroid Build Coastguard Worker FPDF_PAGE page = LoadPage(0);
1107*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(page);
1108*3ac0a46fSAndroid Build Coastguard Worker
1109*3ac0a46fSAndroid Build Coastguard Worker FPDF_TEXTPAGE textpage = FPDFText_LoadPage(page);
1110*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(textpage);
1111*3ac0a46fSAndroid Build Coastguard Worker
1112*3ac0a46fSAndroid Build Coastguard Worker // Should not include the control characters in the output
1113*3ac0a46fSAndroid Build Coastguard Worker unsigned short buffer[128];
1114*3ac0a46fSAndroid Build Coastguard Worker memset(buffer, 0xbd, sizeof(buffer));
1115*3ac0a46fSAndroid Build Coastguard Worker int num_chars = FPDFText_GetText(textpage, 0, 128, buffer);
1116*3ac0a46fSAndroid Build Coastguard Worker ASSERT_EQ(kHelloGoodbyeTextSize, num_chars);
1117*3ac0a46fSAndroid Build Coastguard Worker EXPECT_TRUE(
1118*3ac0a46fSAndroid Build Coastguard Worker check_unsigned_shorts(kHelloGoodbyeText, buffer, kHelloGoodbyeTextSize));
1119*3ac0a46fSAndroid Build Coastguard Worker
1120*3ac0a46fSAndroid Build Coastguard Worker // Attempting to get a chunk of text after the control characters
1121*3ac0a46fSAndroid Build Coastguard Worker static const char expected_substring[] = "Goodbye, world!";
1122*3ac0a46fSAndroid Build Coastguard Worker // Offset is the length of 'Hello, world!\r\n' + 2 control characters in the
1123*3ac0a46fSAndroid Build Coastguard Worker // original stream
1124*3ac0a46fSAndroid Build Coastguard Worker static const int offset = 17;
1125*3ac0a46fSAndroid Build Coastguard Worker memset(buffer, 0xbd, sizeof(buffer));
1126*3ac0a46fSAndroid Build Coastguard Worker num_chars = FPDFText_GetText(textpage, offset, 128, buffer);
1127*3ac0a46fSAndroid Build Coastguard Worker
1128*3ac0a46fSAndroid Build Coastguard Worker ASSERT_GE(num_chars, 0);
1129*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(sizeof(expected_substring), static_cast<size_t>(num_chars));
1130*3ac0a46fSAndroid Build Coastguard Worker EXPECT_TRUE(check_unsigned_shorts(expected_substring, buffer,
1131*3ac0a46fSAndroid Build Coastguard Worker sizeof(expected_substring)));
1132*3ac0a46fSAndroid Build Coastguard Worker
1133*3ac0a46fSAndroid Build Coastguard Worker FPDFText_ClosePage(textpage);
1134*3ac0a46fSAndroid Build Coastguard Worker UnloadPage(page);
1135*3ac0a46fSAndroid Build Coastguard Worker }
1136*3ac0a46fSAndroid Build Coastguard Worker
1137*3ac0a46fSAndroid Build Coastguard Worker // Testing that hyphen makers (0x0002) are replacing hard hyphens when
1138*3ac0a46fSAndroid Build Coastguard Worker // the word contains non-ASCII characters.
TEST_F(FPDFTextEmbedderTest,bug_1029)1139*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFTextEmbedderTest, bug_1029) {
1140*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(OpenDocument("bug_1029.pdf"));
1141*3ac0a46fSAndroid Build Coastguard Worker FPDF_PAGE page = LoadPage(0);
1142*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(page);
1143*3ac0a46fSAndroid Build Coastguard Worker
1144*3ac0a46fSAndroid Build Coastguard Worker FPDF_TEXTPAGE textpage = FPDFText_LoadPage(page);
1145*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(textpage);
1146*3ac0a46fSAndroid Build Coastguard Worker
1147*3ac0a46fSAndroid Build Coastguard Worker constexpr int page_range_offset = 171;
1148*3ac0a46fSAndroid Build Coastguard Worker constexpr int page_range_length = 56;
1149*3ac0a46fSAndroid Build Coastguard Worker
1150*3ac0a46fSAndroid Build Coastguard Worker // This text is:
1151*3ac0a46fSAndroid Build Coastguard Worker // 'METADATA table. When the split has committed, it noti' followed
1152*3ac0a46fSAndroid Build Coastguard Worker // by a 'soft hyphen' (0x0002) and then 'fi'.
1153*3ac0a46fSAndroid Build Coastguard Worker //
1154*3ac0a46fSAndroid Build Coastguard Worker // The original text has a fi ligature, but that is broken up into
1155*3ac0a46fSAndroid Build Coastguard Worker // two characters when the PDF is processed.
1156*3ac0a46fSAndroid Build Coastguard Worker constexpr unsigned int expected[] = {
1157*3ac0a46fSAndroid Build Coastguard Worker 0x004d, 0x0045, 0x0054, 0x0041, 0x0044, 0x0041, 0x0054, 0x0041,
1158*3ac0a46fSAndroid Build Coastguard Worker 0x0020, 0x0074, 0x0061, 0x0062, 0x006c, 0x0065, 0x002e, 0x0020,
1159*3ac0a46fSAndroid Build Coastguard Worker 0x0057, 0x0068, 0x0065, 0x006e, 0x0020, 0x0074, 0x0068, 0x0065,
1160*3ac0a46fSAndroid Build Coastguard Worker 0x0020, 0x0073, 0x0070, 0x006c, 0x0069, 0x0074, 0x0020, 0x0068,
1161*3ac0a46fSAndroid Build Coastguard Worker 0x0061, 0x0073, 0x0020, 0x0063, 0x006f, 0x006d, 0x006d, 0x0069,
1162*3ac0a46fSAndroid Build Coastguard Worker 0x0074, 0x0074, 0x0065, 0x0064, 0x002c, 0x0020, 0x0069, 0x0074,
1163*3ac0a46fSAndroid Build Coastguard Worker 0x0020, 0x006e, 0x006f, 0x0074, 0x0069, 0x0002, 0x0066, 0x0069};
1164*3ac0a46fSAndroid Build Coastguard Worker static_assert(page_range_length == std::size(expected),
1165*3ac0a46fSAndroid Build Coastguard Worker "Expected should be the same size as the range being "
1166*3ac0a46fSAndroid Build Coastguard Worker "extracted from page.");
1167*3ac0a46fSAndroid Build Coastguard Worker EXPECT_LT(page_range_offset + page_range_length,
1168*3ac0a46fSAndroid Build Coastguard Worker FPDFText_CountChars(textpage));
1169*3ac0a46fSAndroid Build Coastguard Worker
1170*3ac0a46fSAndroid Build Coastguard Worker for (int i = 0; i < page_range_length; ++i) {
1171*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(expected[i],
1172*3ac0a46fSAndroid Build Coastguard Worker FPDFText_GetUnicode(textpage, page_range_offset + i));
1173*3ac0a46fSAndroid Build Coastguard Worker }
1174*3ac0a46fSAndroid Build Coastguard Worker
1175*3ac0a46fSAndroid Build Coastguard Worker FPDFText_ClosePage(textpage);
1176*3ac0a46fSAndroid Build Coastguard Worker UnloadPage(page);
1177*3ac0a46fSAndroid Build Coastguard Worker }
1178*3ac0a46fSAndroid Build Coastguard Worker
TEST_F(FPDFTextEmbedderTest,CountRects)1179*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFTextEmbedderTest, CountRects) {
1180*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(OpenDocument("hello_world.pdf"));
1181*3ac0a46fSAndroid Build Coastguard Worker FPDF_PAGE page = LoadPage(0);
1182*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(page);
1183*3ac0a46fSAndroid Build Coastguard Worker
1184*3ac0a46fSAndroid Build Coastguard Worker FPDF_TEXTPAGE textpage = FPDFText_LoadPage(page);
1185*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(textpage);
1186*3ac0a46fSAndroid Build Coastguard Worker
1187*3ac0a46fSAndroid Build Coastguard Worker // Sanity check hello_world.pdf.
1188*3ac0a46fSAndroid Build Coastguard Worker // |num_chars| check includes the terminating NUL that is provided.
1189*3ac0a46fSAndroid Build Coastguard Worker {
1190*3ac0a46fSAndroid Build Coastguard Worker unsigned short buffer[128];
1191*3ac0a46fSAndroid Build Coastguard Worker int num_chars = FPDFText_GetText(textpage, 0, 128, buffer);
1192*3ac0a46fSAndroid Build Coastguard Worker ASSERT_EQ(kHelloGoodbyeTextSize, num_chars);
1193*3ac0a46fSAndroid Build Coastguard Worker EXPECT_TRUE(check_unsigned_shorts(kHelloGoodbyeText, buffer,
1194*3ac0a46fSAndroid Build Coastguard Worker kHelloGoodbyeTextSize));
1195*3ac0a46fSAndroid Build Coastguard Worker }
1196*3ac0a46fSAndroid Build Coastguard Worker
1197*3ac0a46fSAndroid Build Coastguard Worker // Now test FPDFText_CountRects().
1198*3ac0a46fSAndroid Build Coastguard Worker static const int kHelloWorldEnd = strlen("Hello, world!");
1199*3ac0a46fSAndroid Build Coastguard Worker static const int kGoodbyeWorldStart = kHelloWorldEnd + 2; // "\r\n"
1200*3ac0a46fSAndroid Build Coastguard Worker for (int start = 0; start < kHelloWorldEnd; ++start) {
1201*3ac0a46fSAndroid Build Coastguard Worker // Always grab some part of "hello world" and some part of "goodbye world"
1202*3ac0a46fSAndroid Build Coastguard Worker // Since -1 means "all".
1203*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(2, FPDFText_CountRects(textpage, start, -1));
1204*3ac0a46fSAndroid Build Coastguard Worker
1205*3ac0a46fSAndroid Build Coastguard Worker // No characters always means 0 rects.
1206*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(0, FPDFText_CountRects(textpage, start, 0));
1207*3ac0a46fSAndroid Build Coastguard Worker
1208*3ac0a46fSAndroid Build Coastguard Worker // 1 character stays within "hello world"
1209*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(1, FPDFText_CountRects(textpage, start, 1));
1210*3ac0a46fSAndroid Build Coastguard Worker
1211*3ac0a46fSAndroid Build Coastguard Worker // When |start| is 0, Having |kGoodbyeWorldStart| char count does not reach
1212*3ac0a46fSAndroid Build Coastguard Worker // "goodbye world".
1213*3ac0a46fSAndroid Build Coastguard Worker int expected_value = start ? 2 : 1;
1214*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(expected_value,
1215*3ac0a46fSAndroid Build Coastguard Worker FPDFText_CountRects(textpage, start, kGoodbyeWorldStart));
1216*3ac0a46fSAndroid Build Coastguard Worker
1217*3ac0a46fSAndroid Build Coastguard Worker // Extremely large character count will always return 2 rects because
1218*3ac0a46fSAndroid Build Coastguard Worker // |start| starts inside "hello world".
1219*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(2, FPDFText_CountRects(textpage, start, 500));
1220*3ac0a46fSAndroid Build Coastguard Worker }
1221*3ac0a46fSAndroid Build Coastguard Worker
1222*3ac0a46fSAndroid Build Coastguard Worker // Now test negative counts.
1223*3ac0a46fSAndroid Build Coastguard Worker for (int start = 0; start < kHelloWorldEnd; ++start) {
1224*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(2, FPDFText_CountRects(textpage, start, -100));
1225*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(2, FPDFText_CountRects(textpage, start, -2));
1226*3ac0a46fSAndroid Build Coastguard Worker }
1227*3ac0a46fSAndroid Build Coastguard Worker
1228*3ac0a46fSAndroid Build Coastguard Worker // Now test larger start values.
1229*3ac0a46fSAndroid Build Coastguard Worker const int kExpectedLength = strlen(kHelloGoodbyeText);
1230*3ac0a46fSAndroid Build Coastguard Worker for (int start = kGoodbyeWorldStart + 1; start < kExpectedLength; ++start) {
1231*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(1, FPDFText_CountRects(textpage, start, -1));
1232*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(0, FPDFText_CountRects(textpage, start, 0));
1233*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(1, FPDFText_CountRects(textpage, start, 1));
1234*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(1, FPDFText_CountRects(textpage, start, 2));
1235*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(1, FPDFText_CountRects(textpage, start, 500));
1236*3ac0a46fSAndroid Build Coastguard Worker }
1237*3ac0a46fSAndroid Build Coastguard Worker
1238*3ac0a46fSAndroid Build Coastguard Worker // Now test start values that starts beyond the end of the text.
1239*3ac0a46fSAndroid Build Coastguard Worker for (int start = kExpectedLength; start < 100; ++start) {
1240*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(0, FPDFText_CountRects(textpage, start, -1));
1241*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(0, FPDFText_CountRects(textpage, start, 0));
1242*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(0, FPDFText_CountRects(textpage, start, 1));
1243*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(0, FPDFText_CountRects(textpage, start, 2));
1244*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(0, FPDFText_CountRects(textpage, start, 500));
1245*3ac0a46fSAndroid Build Coastguard Worker }
1246*3ac0a46fSAndroid Build Coastguard Worker
1247*3ac0a46fSAndroid Build Coastguard Worker FPDFText_ClosePage(textpage);
1248*3ac0a46fSAndroid Build Coastguard Worker UnloadPage(page);
1249*3ac0a46fSAndroid Build Coastguard Worker }
1250*3ac0a46fSAndroid Build Coastguard Worker
TEST_F(FPDFTextEmbedderTest,GetText)1251*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFTextEmbedderTest, GetText) {
1252*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(OpenDocument("hello_world.pdf"));
1253*3ac0a46fSAndroid Build Coastguard Worker FPDF_PAGE page = LoadPage(0);
1254*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(page);
1255*3ac0a46fSAndroid Build Coastguard Worker
1256*3ac0a46fSAndroid Build Coastguard Worker FPDF_TEXTPAGE text_page = FPDFText_LoadPage(page);
1257*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(text_page);
1258*3ac0a46fSAndroid Build Coastguard Worker
1259*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(2, FPDFPage_CountObjects(page));
1260*3ac0a46fSAndroid Build Coastguard Worker FPDF_PAGEOBJECT text_object = FPDFPage_GetObject(page, 0);
1261*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(text_object);
1262*3ac0a46fSAndroid Build Coastguard Worker
1263*3ac0a46fSAndroid Build Coastguard Worker // Positive testing.
1264*3ac0a46fSAndroid Build Coastguard Worker constexpr char kHelloText[] = "Hello, world!";
1265*3ac0a46fSAndroid Build Coastguard Worker // Return value includes the terminating NUL that is provided.
1266*3ac0a46fSAndroid Build Coastguard Worker constexpr unsigned long kHelloUTF16Size = std::size(kHelloText) * 2;
1267*3ac0a46fSAndroid Build Coastguard Worker constexpr wchar_t kHelloWideText[] = L"Hello, world!";
1268*3ac0a46fSAndroid Build Coastguard Worker unsigned long size = FPDFTextObj_GetText(text_object, text_page, nullptr, 0);
1269*3ac0a46fSAndroid Build Coastguard Worker ASSERT_EQ(kHelloUTF16Size, size);
1270*3ac0a46fSAndroid Build Coastguard Worker
1271*3ac0a46fSAndroid Build Coastguard Worker std::vector<unsigned short> buffer(size);
1272*3ac0a46fSAndroid Build Coastguard Worker ASSERT_EQ(size,
1273*3ac0a46fSAndroid Build Coastguard Worker FPDFTextObj_GetText(text_object, text_page, buffer.data(), size));
1274*3ac0a46fSAndroid Build Coastguard Worker ASSERT_EQ(kHelloWideText, GetPlatformWString(buffer.data()));
1275*3ac0a46fSAndroid Build Coastguard Worker
1276*3ac0a46fSAndroid Build Coastguard Worker // Negative testing.
1277*3ac0a46fSAndroid Build Coastguard Worker ASSERT_EQ(0U, FPDFTextObj_GetText(nullptr, text_page, nullptr, 0));
1278*3ac0a46fSAndroid Build Coastguard Worker ASSERT_EQ(0U, FPDFTextObj_GetText(text_object, nullptr, nullptr, 0));
1279*3ac0a46fSAndroid Build Coastguard Worker ASSERT_EQ(0U, FPDFTextObj_GetText(nullptr, nullptr, nullptr, 0));
1280*3ac0a46fSAndroid Build Coastguard Worker
1281*3ac0a46fSAndroid Build Coastguard Worker // Buffer is too small, ensure it's not modified.
1282*3ac0a46fSAndroid Build Coastguard Worker buffer.resize(2);
1283*3ac0a46fSAndroid Build Coastguard Worker buffer[0] = 'x';
1284*3ac0a46fSAndroid Build Coastguard Worker buffer[1] = '\0';
1285*3ac0a46fSAndroid Build Coastguard Worker size =
1286*3ac0a46fSAndroid Build Coastguard Worker FPDFTextObj_GetText(text_object, text_page, buffer.data(), buffer.size());
1287*3ac0a46fSAndroid Build Coastguard Worker ASSERT_EQ(kHelloUTF16Size, size);
1288*3ac0a46fSAndroid Build Coastguard Worker ASSERT_EQ('x', buffer[0]);
1289*3ac0a46fSAndroid Build Coastguard Worker ASSERT_EQ('\0', buffer[1]);
1290*3ac0a46fSAndroid Build Coastguard Worker
1291*3ac0a46fSAndroid Build Coastguard Worker FPDFText_ClosePage(text_page);
1292*3ac0a46fSAndroid Build Coastguard Worker UnloadPage(page);
1293*3ac0a46fSAndroid Build Coastguard Worker }
1294*3ac0a46fSAndroid Build Coastguard Worker
TEST_F(FPDFTextEmbedderTest,CroppedText)1295*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFTextEmbedderTest, CroppedText) {
1296*3ac0a46fSAndroid Build Coastguard Worker static constexpr int kPageCount = 4;
1297*3ac0a46fSAndroid Build Coastguard Worker static constexpr FS_RECTF kBoxes[kPageCount] = {
1298*3ac0a46fSAndroid Build Coastguard Worker {50.0f, 150.0f, 150.0f, 50.0f},
1299*3ac0a46fSAndroid Build Coastguard Worker {50.0f, 150.0f, 150.0f, 50.0f},
1300*3ac0a46fSAndroid Build Coastguard Worker {60.0f, 150.0f, 150.0f, 60.0f},
1301*3ac0a46fSAndroid Build Coastguard Worker {60.0f, 150.0f, 150.0f, 60.0f},
1302*3ac0a46fSAndroid Build Coastguard Worker };
1303*3ac0a46fSAndroid Build Coastguard Worker static constexpr const char* kExpectedText[kPageCount] = {
1304*3ac0a46fSAndroid Build Coastguard Worker " world!\r\ndbye, world!",
1305*3ac0a46fSAndroid Build Coastguard Worker " world!\r\ndbye, world!",
1306*3ac0a46fSAndroid Build Coastguard Worker "bye, world!",
1307*3ac0a46fSAndroid Build Coastguard Worker "bye, world!",
1308*3ac0a46fSAndroid Build Coastguard Worker };
1309*3ac0a46fSAndroid Build Coastguard Worker
1310*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(OpenDocument("cropped_text.pdf"));
1311*3ac0a46fSAndroid Build Coastguard Worker ASSERT_EQ(kPageCount, FPDF_GetPageCount(document()));
1312*3ac0a46fSAndroid Build Coastguard Worker
1313*3ac0a46fSAndroid Build Coastguard Worker for (int i = 0; i < kPageCount; ++i) {
1314*3ac0a46fSAndroid Build Coastguard Worker FPDF_PAGE page = LoadPage(i);
1315*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(page);
1316*3ac0a46fSAndroid Build Coastguard Worker
1317*3ac0a46fSAndroid Build Coastguard Worker FS_RECTF box;
1318*3ac0a46fSAndroid Build Coastguard Worker EXPECT_TRUE(FPDF_GetPageBoundingBox(page, &box));
1319*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(kBoxes[i].left, box.left);
1320*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(kBoxes[i].top, box.top);
1321*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(kBoxes[i].right, box.right);
1322*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(kBoxes[i].bottom, box.bottom);
1323*3ac0a46fSAndroid Build Coastguard Worker
1324*3ac0a46fSAndroid Build Coastguard Worker {
1325*3ac0a46fSAndroid Build Coastguard Worker ScopedFPDFTextPage textpage(FPDFText_LoadPage(page));
1326*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(textpage);
1327*3ac0a46fSAndroid Build Coastguard Worker
1328*3ac0a46fSAndroid Build Coastguard Worker unsigned short buffer[128];
1329*3ac0a46fSAndroid Build Coastguard Worker memset(buffer, 0xbd, sizeof(buffer));
1330*3ac0a46fSAndroid Build Coastguard Worker int num_chars = FPDFText_GetText(textpage.get(), 0, 128, buffer);
1331*3ac0a46fSAndroid Build Coastguard Worker ASSERT_EQ(kHelloGoodbyeTextSize, num_chars);
1332*3ac0a46fSAndroid Build Coastguard Worker EXPECT_TRUE(check_unsigned_shorts(kHelloGoodbyeText, buffer,
1333*3ac0a46fSAndroid Build Coastguard Worker kHelloGoodbyeTextSize));
1334*3ac0a46fSAndroid Build Coastguard Worker
1335*3ac0a46fSAndroid Build Coastguard Worker int expected_char_count = strlen(kExpectedText[i]);
1336*3ac0a46fSAndroid Build Coastguard Worker ASSERT_EQ(expected_char_count,
1337*3ac0a46fSAndroid Build Coastguard Worker FPDFText_GetBoundedText(textpage.get(), box.left, box.top,
1338*3ac0a46fSAndroid Build Coastguard Worker box.right, box.bottom, nullptr, 0));
1339*3ac0a46fSAndroid Build Coastguard Worker
1340*3ac0a46fSAndroid Build Coastguard Worker memset(buffer, 0xbd, sizeof(buffer));
1341*3ac0a46fSAndroid Build Coastguard Worker ASSERT_EQ(expected_char_count + 1,
1342*3ac0a46fSAndroid Build Coastguard Worker FPDFText_GetBoundedText(textpage.get(), box.left, box.top,
1343*3ac0a46fSAndroid Build Coastguard Worker box.right, box.bottom, buffer, 128));
1344*3ac0a46fSAndroid Build Coastguard Worker EXPECT_TRUE(
1345*3ac0a46fSAndroid Build Coastguard Worker check_unsigned_shorts(kExpectedText[i], buffer, expected_char_count));
1346*3ac0a46fSAndroid Build Coastguard Worker }
1347*3ac0a46fSAndroid Build Coastguard Worker
1348*3ac0a46fSAndroid Build Coastguard Worker UnloadPage(page);
1349*3ac0a46fSAndroid Build Coastguard Worker }
1350*3ac0a46fSAndroid Build Coastguard Worker }
1351*3ac0a46fSAndroid Build Coastguard Worker
TEST_F(FPDFTextEmbedderTest,Bug_1139)1352*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFTextEmbedderTest, Bug_1139) {
1353*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(OpenDocument("bug_1139.pdf"));
1354*3ac0a46fSAndroid Build Coastguard Worker FPDF_PAGE page = LoadPage(0);
1355*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(page);
1356*3ac0a46fSAndroid Build Coastguard Worker
1357*3ac0a46fSAndroid Build Coastguard Worker FPDF_TEXTPAGE text_page = FPDFText_LoadPage(page);
1358*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(text_page);
1359*3ac0a46fSAndroid Build Coastguard Worker
1360*3ac0a46fSAndroid Build Coastguard Worker // -1 for CountChars not including the \0, but +1 for the extra control
1361*3ac0a46fSAndroid Build Coastguard Worker // character.
1362*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(kHelloGoodbyeTextSize, FPDFText_CountChars(text_page));
1363*3ac0a46fSAndroid Build Coastguard Worker
1364*3ac0a46fSAndroid Build Coastguard Worker // There is an extra control character at the beginning of the string, but it
1365*3ac0a46fSAndroid Build Coastguard Worker // should not appear in the output nor prevent extracting the text.
1366*3ac0a46fSAndroid Build Coastguard Worker unsigned short buffer[128];
1367*3ac0a46fSAndroid Build Coastguard Worker int num_chars = FPDFText_GetText(text_page, 0, 128, buffer);
1368*3ac0a46fSAndroid Build Coastguard Worker ASSERT_EQ(kHelloGoodbyeTextSize, num_chars);
1369*3ac0a46fSAndroid Build Coastguard Worker EXPECT_TRUE(
1370*3ac0a46fSAndroid Build Coastguard Worker check_unsigned_shorts(kHelloGoodbyeText, buffer, kHelloGoodbyeTextSize));
1371*3ac0a46fSAndroid Build Coastguard Worker FPDFText_ClosePage(text_page);
1372*3ac0a46fSAndroid Build Coastguard Worker UnloadPage(page);
1373*3ac0a46fSAndroid Build Coastguard Worker }
1374*3ac0a46fSAndroid Build Coastguard Worker
TEST_F(FPDFTextEmbedderTest,Bug_642)1375*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFTextEmbedderTest, Bug_642) {
1376*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(OpenDocument("bug_642.pdf"));
1377*3ac0a46fSAndroid Build Coastguard Worker FPDF_PAGE page = LoadPage(0);
1378*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(page);
1379*3ac0a46fSAndroid Build Coastguard Worker {
1380*3ac0a46fSAndroid Build Coastguard Worker ScopedFPDFTextPage text_page(FPDFText_LoadPage(page));
1381*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(text_page);
1382*3ac0a46fSAndroid Build Coastguard Worker
1383*3ac0a46fSAndroid Build Coastguard Worker constexpr char kText[] = "ABCD";
1384*3ac0a46fSAndroid Build Coastguard Worker constexpr size_t kTextSize = std::size(kText);
1385*3ac0a46fSAndroid Build Coastguard Worker // -1 for CountChars not including the \0
1386*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(static_cast<int>(kTextSize) - 1,
1387*3ac0a46fSAndroid Build Coastguard Worker FPDFText_CountChars(text_page.get()));
1388*3ac0a46fSAndroid Build Coastguard Worker
1389*3ac0a46fSAndroid Build Coastguard Worker unsigned short buffer[kTextSize];
1390*3ac0a46fSAndroid Build Coastguard Worker int num_chars =
1391*3ac0a46fSAndroid Build Coastguard Worker FPDFText_GetText(text_page.get(), 0, std::size(buffer) - 1, buffer);
1392*3ac0a46fSAndroid Build Coastguard Worker ASSERT_EQ(static_cast<int>(kTextSize), num_chars);
1393*3ac0a46fSAndroid Build Coastguard Worker EXPECT_TRUE(check_unsigned_shorts(kText, buffer, kTextSize));
1394*3ac0a46fSAndroid Build Coastguard Worker }
1395*3ac0a46fSAndroid Build Coastguard Worker
1396*3ac0a46fSAndroid Build Coastguard Worker UnloadPage(page);
1397*3ac0a46fSAndroid Build Coastguard Worker }
1398*3ac0a46fSAndroid Build Coastguard Worker
TEST_F(FPDFTextEmbedderTest,GetCharAngle)1399*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFTextEmbedderTest, GetCharAngle) {
1400*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(OpenDocument("rotated_text.pdf"));
1401*3ac0a46fSAndroid Build Coastguard Worker FPDF_PAGE page = LoadPage(0);
1402*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(page);
1403*3ac0a46fSAndroid Build Coastguard Worker
1404*3ac0a46fSAndroid Build Coastguard Worker FPDF_TEXTPAGE text_page = FPDFText_LoadPage(page);
1405*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(text_page);
1406*3ac0a46fSAndroid Build Coastguard Worker
1407*3ac0a46fSAndroid Build Coastguard Worker static constexpr int kSubstringsSize[] = {
1408*3ac0a46fSAndroid Build Coastguard Worker std::size("Hello,"), std::size(" world!\r\n"), std::size("Goodbye,")};
1409*3ac0a46fSAndroid Build Coastguard Worker
1410*3ac0a46fSAndroid Build Coastguard Worker // -1 for CountChars not including the \0, but +1 for the extra control
1411*3ac0a46fSAndroid Build Coastguard Worker // character.
1412*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(kHelloGoodbyeTextSize, FPDFText_CountChars(text_page));
1413*3ac0a46fSAndroid Build Coastguard Worker
1414*3ac0a46fSAndroid Build Coastguard Worker EXPECT_FLOAT_EQ(-1.0f, FPDFText_GetCharAngle(nullptr, 0));
1415*3ac0a46fSAndroid Build Coastguard Worker EXPECT_FLOAT_EQ(-1.0f, FPDFText_GetCharAngle(text_page, -1));
1416*3ac0a46fSAndroid Build Coastguard Worker EXPECT_FLOAT_EQ(-1.0f,
1417*3ac0a46fSAndroid Build Coastguard Worker FPDFText_GetCharAngle(text_page, kHelloGoodbyeTextSize + 1));
1418*3ac0a46fSAndroid Build Coastguard Worker
1419*3ac0a46fSAndroid Build Coastguard Worker // Test GetCharAngle for every quadrant
1420*3ac0a46fSAndroid Build Coastguard Worker EXPECT_NEAR(FXSYS_PI / 4.0, FPDFText_GetCharAngle(text_page, 0), 0.001);
1421*3ac0a46fSAndroid Build Coastguard Worker EXPECT_NEAR(3 * FXSYS_PI / 4.0,
1422*3ac0a46fSAndroid Build Coastguard Worker FPDFText_GetCharAngle(text_page, kSubstringsSize[0]), 0.001);
1423*3ac0a46fSAndroid Build Coastguard Worker EXPECT_NEAR(
1424*3ac0a46fSAndroid Build Coastguard Worker 5 * FXSYS_PI / 4.0,
1425*3ac0a46fSAndroid Build Coastguard Worker FPDFText_GetCharAngle(text_page, kSubstringsSize[0] + kSubstringsSize[1]),
1426*3ac0a46fSAndroid Build Coastguard Worker 0.001);
1427*3ac0a46fSAndroid Build Coastguard Worker EXPECT_NEAR(
1428*3ac0a46fSAndroid Build Coastguard Worker 7 * FXSYS_PI / 4.0,
1429*3ac0a46fSAndroid Build Coastguard Worker FPDFText_GetCharAngle(text_page, kSubstringsSize[0] + kSubstringsSize[1] +
1430*3ac0a46fSAndroid Build Coastguard Worker kSubstringsSize[2]),
1431*3ac0a46fSAndroid Build Coastguard Worker 0.001);
1432*3ac0a46fSAndroid Build Coastguard Worker
1433*3ac0a46fSAndroid Build Coastguard Worker FPDFText_ClosePage(text_page);
1434*3ac0a46fSAndroid Build Coastguard Worker UnloadPage(page);
1435*3ac0a46fSAndroid Build Coastguard Worker }
1436*3ac0a46fSAndroid Build Coastguard Worker
TEST_F(FPDFTextEmbedderTest,GetFontWeight)1437*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFTextEmbedderTest, GetFontWeight) {
1438*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(OpenDocument("font_weight.pdf"));
1439*3ac0a46fSAndroid Build Coastguard Worker FPDF_PAGE page = LoadPage(0);
1440*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(page);
1441*3ac0a46fSAndroid Build Coastguard Worker
1442*3ac0a46fSAndroid Build Coastguard Worker FPDF_TEXTPAGE text_page = FPDFText_LoadPage(page);
1443*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(text_page);
1444*3ac0a46fSAndroid Build Coastguard Worker
1445*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(2, FPDFText_CountChars(text_page));
1446*3ac0a46fSAndroid Build Coastguard Worker
1447*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(-1, FPDFText_GetFontWeight(nullptr, 0));
1448*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(-1, FPDFText_GetFontWeight(text_page, -1));
1449*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(-1, FPDFText_GetFontWeight(text_page, 314));
1450*3ac0a46fSAndroid Build Coastguard Worker
1451*3ac0a46fSAndroid Build Coastguard Worker // The font used for this text only specifies /StemV (80); the weight value
1452*3ac0a46fSAndroid Build Coastguard Worker // that is returned should be calculated from that (80*5 == 400).
1453*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(400, FPDFText_GetFontWeight(text_page, 0));
1454*3ac0a46fSAndroid Build Coastguard Worker
1455*3ac0a46fSAndroid Build Coastguard Worker // Using a /StemV value of 82, the estimate comes out to 410, even though
1456*3ac0a46fSAndroid Build Coastguard Worker // /FontWeight is 400.
1457*3ac0a46fSAndroid Build Coastguard Worker // TODO(crbug.com/pdfium/1420): Fix this the return value here.
1458*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(410, FPDFText_GetFontWeight(text_page, 1));
1459*3ac0a46fSAndroid Build Coastguard Worker
1460*3ac0a46fSAndroid Build Coastguard Worker FPDFText_ClosePage(text_page);
1461*3ac0a46fSAndroid Build Coastguard Worker UnloadPage(page);
1462*3ac0a46fSAndroid Build Coastguard Worker }
1463*3ac0a46fSAndroid Build Coastguard Worker
TEST_F(FPDFTextEmbedderTest,GetTextRenderMode)1464*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFTextEmbedderTest, GetTextRenderMode) {
1465*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(OpenDocument("text_render_mode.pdf"));
1466*3ac0a46fSAndroid Build Coastguard Worker FPDF_PAGE page = LoadPage(0);
1467*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(page);
1468*3ac0a46fSAndroid Build Coastguard Worker
1469*3ac0a46fSAndroid Build Coastguard Worker FPDF_TEXTPAGE text_page = FPDFText_LoadPage(page);
1470*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(text_page);
1471*3ac0a46fSAndroid Build Coastguard Worker
1472*3ac0a46fSAndroid Build Coastguard Worker ASSERT_EQ(12, FPDFText_CountChars(text_page));
1473*3ac0a46fSAndroid Build Coastguard Worker
1474*3ac0a46fSAndroid Build Coastguard Worker ASSERT_EQ(FPDF_TEXTRENDERMODE_UNKNOWN,
1475*3ac0a46fSAndroid Build Coastguard Worker FPDFText_GetTextRenderMode(nullptr, 0));
1476*3ac0a46fSAndroid Build Coastguard Worker ASSERT_EQ(FPDF_TEXTRENDERMODE_UNKNOWN,
1477*3ac0a46fSAndroid Build Coastguard Worker FPDFText_GetTextRenderMode(text_page, -1));
1478*3ac0a46fSAndroid Build Coastguard Worker ASSERT_EQ(FPDF_TEXTRENDERMODE_UNKNOWN,
1479*3ac0a46fSAndroid Build Coastguard Worker FPDFText_GetTextRenderMode(text_page, 314));
1480*3ac0a46fSAndroid Build Coastguard Worker
1481*3ac0a46fSAndroid Build Coastguard Worker ASSERT_EQ(FPDF_TEXTRENDERMODE_FILL, FPDFText_GetTextRenderMode(text_page, 0));
1482*3ac0a46fSAndroid Build Coastguard Worker
1483*3ac0a46fSAndroid Build Coastguard Worker ASSERT_EQ(FPDF_TEXTRENDERMODE_STROKE,
1484*3ac0a46fSAndroid Build Coastguard Worker FPDFText_GetTextRenderMode(text_page, 7));
1485*3ac0a46fSAndroid Build Coastguard Worker
1486*3ac0a46fSAndroid Build Coastguard Worker FPDFText_ClosePage(text_page);
1487*3ac0a46fSAndroid Build Coastguard Worker UnloadPage(page);
1488*3ac0a46fSAndroid Build Coastguard Worker }
1489*3ac0a46fSAndroid Build Coastguard Worker
TEST_F(FPDFTextEmbedderTest,GetFillColor)1490*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFTextEmbedderTest, GetFillColor) {
1491*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(OpenDocument("text_color.pdf"));
1492*3ac0a46fSAndroid Build Coastguard Worker FPDF_PAGE page = LoadPage(0);
1493*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(page);
1494*3ac0a46fSAndroid Build Coastguard Worker
1495*3ac0a46fSAndroid Build Coastguard Worker FPDF_TEXTPAGE text_page = FPDFText_LoadPage(page);
1496*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(text_page);
1497*3ac0a46fSAndroid Build Coastguard Worker
1498*3ac0a46fSAndroid Build Coastguard Worker ASSERT_EQ(1, FPDFText_CountChars(text_page));
1499*3ac0a46fSAndroid Build Coastguard Worker
1500*3ac0a46fSAndroid Build Coastguard Worker ASSERT_FALSE(
1501*3ac0a46fSAndroid Build Coastguard Worker FPDFText_GetFillColor(nullptr, 0, nullptr, nullptr, nullptr, nullptr));
1502*3ac0a46fSAndroid Build Coastguard Worker ASSERT_FALSE(
1503*3ac0a46fSAndroid Build Coastguard Worker FPDFText_GetFillColor(text_page, -1, nullptr, nullptr, nullptr, nullptr));
1504*3ac0a46fSAndroid Build Coastguard Worker ASSERT_FALSE(FPDFText_GetFillColor(text_page, 314, nullptr, nullptr, nullptr,
1505*3ac0a46fSAndroid Build Coastguard Worker nullptr));
1506*3ac0a46fSAndroid Build Coastguard Worker ASSERT_FALSE(
1507*3ac0a46fSAndroid Build Coastguard Worker FPDFText_GetFillColor(text_page, 0, nullptr, nullptr, nullptr, nullptr));
1508*3ac0a46fSAndroid Build Coastguard Worker
1509*3ac0a46fSAndroid Build Coastguard Worker unsigned int r;
1510*3ac0a46fSAndroid Build Coastguard Worker unsigned int g;
1511*3ac0a46fSAndroid Build Coastguard Worker unsigned int b;
1512*3ac0a46fSAndroid Build Coastguard Worker unsigned int a;
1513*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(FPDFText_GetFillColor(text_page, 0, &r, &g, &b, &a));
1514*3ac0a46fSAndroid Build Coastguard Worker ASSERT_EQ(0xffu, r);
1515*3ac0a46fSAndroid Build Coastguard Worker ASSERT_EQ(0u, g);
1516*3ac0a46fSAndroid Build Coastguard Worker ASSERT_EQ(0u, b);
1517*3ac0a46fSAndroid Build Coastguard Worker ASSERT_EQ(0xffu, a);
1518*3ac0a46fSAndroid Build Coastguard Worker
1519*3ac0a46fSAndroid Build Coastguard Worker FPDFText_ClosePage(text_page);
1520*3ac0a46fSAndroid Build Coastguard Worker UnloadPage(page);
1521*3ac0a46fSAndroid Build Coastguard Worker }
1522*3ac0a46fSAndroid Build Coastguard Worker
TEST_F(FPDFTextEmbedderTest,GetStrokeColor)1523*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFTextEmbedderTest, GetStrokeColor) {
1524*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(OpenDocument("text_color.pdf"));
1525*3ac0a46fSAndroid Build Coastguard Worker FPDF_PAGE page = LoadPage(0);
1526*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(page);
1527*3ac0a46fSAndroid Build Coastguard Worker
1528*3ac0a46fSAndroid Build Coastguard Worker FPDF_TEXTPAGE text_page = FPDFText_LoadPage(page);
1529*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(text_page);
1530*3ac0a46fSAndroid Build Coastguard Worker
1531*3ac0a46fSAndroid Build Coastguard Worker ASSERT_EQ(1, FPDFText_CountChars(text_page));
1532*3ac0a46fSAndroid Build Coastguard Worker
1533*3ac0a46fSAndroid Build Coastguard Worker ASSERT_FALSE(
1534*3ac0a46fSAndroid Build Coastguard Worker FPDFText_GetStrokeColor(nullptr, 0, nullptr, nullptr, nullptr, nullptr));
1535*3ac0a46fSAndroid Build Coastguard Worker ASSERT_FALSE(FPDFText_GetStrokeColor(text_page, -1, nullptr, nullptr, nullptr,
1536*3ac0a46fSAndroid Build Coastguard Worker nullptr));
1537*3ac0a46fSAndroid Build Coastguard Worker ASSERT_FALSE(FPDFText_GetStrokeColor(text_page, 314, nullptr, nullptr,
1538*3ac0a46fSAndroid Build Coastguard Worker nullptr, nullptr));
1539*3ac0a46fSAndroid Build Coastguard Worker ASSERT_FALSE(FPDFText_GetStrokeColor(text_page, 0, nullptr, nullptr, nullptr,
1540*3ac0a46fSAndroid Build Coastguard Worker nullptr));
1541*3ac0a46fSAndroid Build Coastguard Worker
1542*3ac0a46fSAndroid Build Coastguard Worker unsigned int r;
1543*3ac0a46fSAndroid Build Coastguard Worker unsigned int g;
1544*3ac0a46fSAndroid Build Coastguard Worker unsigned int b;
1545*3ac0a46fSAndroid Build Coastguard Worker unsigned int a;
1546*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(FPDFText_GetStrokeColor(text_page, 0, &r, &g, &b, &a));
1547*3ac0a46fSAndroid Build Coastguard Worker ASSERT_EQ(0u, r);
1548*3ac0a46fSAndroid Build Coastguard Worker ASSERT_EQ(0xffu, g);
1549*3ac0a46fSAndroid Build Coastguard Worker ASSERT_EQ(0u, b);
1550*3ac0a46fSAndroid Build Coastguard Worker ASSERT_EQ(0xffu, a);
1551*3ac0a46fSAndroid Build Coastguard Worker
1552*3ac0a46fSAndroid Build Coastguard Worker FPDFText_ClosePage(text_page);
1553*3ac0a46fSAndroid Build Coastguard Worker UnloadPage(page);
1554*3ac0a46fSAndroid Build Coastguard Worker }
1555*3ac0a46fSAndroid Build Coastguard Worker
TEST_F(FPDFTextEmbedderTest,GetMatrix)1556*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFTextEmbedderTest, GetMatrix) {
1557*3ac0a46fSAndroid Build Coastguard Worker constexpr char kExpectedText[] = "A1\r\nA2\r\nA3";
1558*3ac0a46fSAndroid Build Coastguard Worker constexpr size_t kExpectedTextSize = std::size(kExpectedText);
1559*3ac0a46fSAndroid Build Coastguard Worker constexpr FS_MATRIX kExpectedMatrices[] = {
1560*3ac0a46fSAndroid Build Coastguard Worker {12.0f, 0.0f, 0.0f, 10.0f, 66.0f, 90.0f},
1561*3ac0a46fSAndroid Build Coastguard Worker {12.0f, 0.0f, 0.0f, 10.0f, 66.0f, 90.0f},
1562*3ac0a46fSAndroid Build Coastguard Worker {1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f},
1563*3ac0a46fSAndroid Build Coastguard Worker {1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f},
1564*3ac0a46fSAndroid Build Coastguard Worker {12.0f, 0.0f, 0.0f, 10.0f, 38.0f, 60.0f},
1565*3ac0a46fSAndroid Build Coastguard Worker {12.0f, 0.0f, 0.0f, 10.0f, 38.0f, 60.0f},
1566*3ac0a46fSAndroid Build Coastguard Worker {1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f},
1567*3ac0a46fSAndroid Build Coastguard Worker {1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f},
1568*3ac0a46fSAndroid Build Coastguard Worker {1.0f, 0.0f, 0.0f, 0.833333, 60.0f, 130.0f},
1569*3ac0a46fSAndroid Build Coastguard Worker {1.0f, 0.0f, 0.0f, 0.833333, 60.0f, 130.0f},
1570*3ac0a46fSAndroid Build Coastguard Worker };
1571*3ac0a46fSAndroid Build Coastguard Worker constexpr size_t kExpectedCount = std::size(kExpectedMatrices);
1572*3ac0a46fSAndroid Build Coastguard Worker static_assert(kExpectedCount + 1 == kExpectedTextSize,
1573*3ac0a46fSAndroid Build Coastguard Worker "Bad expected matrix size");
1574*3ac0a46fSAndroid Build Coastguard Worker
1575*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(OpenDocument("font_matrix.pdf"));
1576*3ac0a46fSAndroid Build Coastguard Worker FPDF_PAGE page = LoadPage(0);
1577*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(page);
1578*3ac0a46fSAndroid Build Coastguard Worker
1579*3ac0a46fSAndroid Build Coastguard Worker {
1580*3ac0a46fSAndroid Build Coastguard Worker ScopedFPDFTextPage text_page(FPDFText_LoadPage(page));
1581*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(text_page);
1582*3ac0a46fSAndroid Build Coastguard Worker ASSERT_EQ(static_cast<int>(kExpectedCount),
1583*3ac0a46fSAndroid Build Coastguard Worker FPDFText_CountChars(text_page.get()));
1584*3ac0a46fSAndroid Build Coastguard Worker
1585*3ac0a46fSAndroid Build Coastguard Worker {
1586*3ac0a46fSAndroid Build Coastguard Worker // Check the characters.
1587*3ac0a46fSAndroid Build Coastguard Worker unsigned short buffer[kExpectedTextSize];
1588*3ac0a46fSAndroid Build Coastguard Worker ASSERT_EQ(static_cast<int>(kExpectedTextSize),
1589*3ac0a46fSAndroid Build Coastguard Worker FPDFText_GetText(text_page.get(), 0, kExpectedCount, buffer));
1590*3ac0a46fSAndroid Build Coastguard Worker EXPECT_TRUE(
1591*3ac0a46fSAndroid Build Coastguard Worker check_unsigned_shorts(kExpectedText, buffer, kExpectedTextSize));
1592*3ac0a46fSAndroid Build Coastguard Worker }
1593*3ac0a46fSAndroid Build Coastguard Worker
1594*3ac0a46fSAndroid Build Coastguard Worker // Check the character matrix.
1595*3ac0a46fSAndroid Build Coastguard Worker FS_MATRIX matrix;
1596*3ac0a46fSAndroid Build Coastguard Worker for (size_t i = 0; i < kExpectedCount; ++i) {
1597*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(FPDFText_GetMatrix(text_page.get(), i, &matrix)) << i;
1598*3ac0a46fSAndroid Build Coastguard Worker EXPECT_FLOAT_EQ(kExpectedMatrices[i].a, matrix.a) << i;
1599*3ac0a46fSAndroid Build Coastguard Worker EXPECT_FLOAT_EQ(kExpectedMatrices[i].b, matrix.b) << i;
1600*3ac0a46fSAndroid Build Coastguard Worker EXPECT_FLOAT_EQ(kExpectedMatrices[i].c, matrix.c) << i;
1601*3ac0a46fSAndroid Build Coastguard Worker EXPECT_FLOAT_EQ(kExpectedMatrices[i].d, matrix.d) << i;
1602*3ac0a46fSAndroid Build Coastguard Worker EXPECT_FLOAT_EQ(kExpectedMatrices[i].e, matrix.e) << i;
1603*3ac0a46fSAndroid Build Coastguard Worker EXPECT_FLOAT_EQ(kExpectedMatrices[i].f, matrix.f) << i;
1604*3ac0a46fSAndroid Build Coastguard Worker }
1605*3ac0a46fSAndroid Build Coastguard Worker
1606*3ac0a46fSAndroid Build Coastguard Worker // Check bad parameters.
1607*3ac0a46fSAndroid Build Coastguard Worker EXPECT_FALSE(FPDFText_GetMatrix(nullptr, 0, &matrix));
1608*3ac0a46fSAndroid Build Coastguard Worker EXPECT_FALSE(FPDFText_GetMatrix(text_page.get(), 10, &matrix));
1609*3ac0a46fSAndroid Build Coastguard Worker EXPECT_FALSE(FPDFText_GetMatrix(text_page.get(), -1, &matrix));
1610*3ac0a46fSAndroid Build Coastguard Worker EXPECT_FALSE(FPDFText_GetMatrix(text_page.get(), 0, nullptr));
1611*3ac0a46fSAndroid Build Coastguard Worker }
1612*3ac0a46fSAndroid Build Coastguard Worker
1613*3ac0a46fSAndroid Build Coastguard Worker UnloadPage(page);
1614*3ac0a46fSAndroid Build Coastguard Worker }
1615*3ac0a46fSAndroid Build Coastguard Worker
TEST_F(FPDFTextEmbedderTest,CharBox)1616*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFTextEmbedderTest, CharBox) {
1617*3ac0a46fSAndroid Build Coastguard Worker // For a size 12 letter 'A'.
1618*3ac0a46fSAndroid Build Coastguard Worker constexpr double kExpectedCharWidth = 8.460;
1619*3ac0a46fSAndroid Build Coastguard Worker constexpr double kExpectedCharHeight = 6.600;
1620*3ac0a46fSAndroid Build Coastguard Worker constexpr float kExpectedLooseCharWidth = 8.664f;
1621*3ac0a46fSAndroid Build Coastguard Worker constexpr float kExpectedLooseCharHeight = 12.0f;
1622*3ac0a46fSAndroid Build Coastguard Worker
1623*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(OpenDocument("font_matrix.pdf"));
1624*3ac0a46fSAndroid Build Coastguard Worker FPDF_PAGE page = LoadPage(0);
1625*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(page);
1626*3ac0a46fSAndroid Build Coastguard Worker
1627*3ac0a46fSAndroid Build Coastguard Worker {
1628*3ac0a46fSAndroid Build Coastguard Worker ScopedFPDFTextPage text_page(FPDFText_LoadPage(page));
1629*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(text_page);
1630*3ac0a46fSAndroid Build Coastguard Worker
1631*3ac0a46fSAndroid Build Coastguard Worker // Check the character box size.
1632*3ac0a46fSAndroid Build Coastguard Worker double left;
1633*3ac0a46fSAndroid Build Coastguard Worker double right;
1634*3ac0a46fSAndroid Build Coastguard Worker double bottom;
1635*3ac0a46fSAndroid Build Coastguard Worker double top;
1636*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(
1637*3ac0a46fSAndroid Build Coastguard Worker FPDFText_GetCharBox(text_page.get(), 0, &left, &right, &bottom, &top));
1638*3ac0a46fSAndroid Build Coastguard Worker EXPECT_NEAR(kExpectedCharWidth, right - left, 0.001);
1639*3ac0a46fSAndroid Build Coastguard Worker EXPECT_NEAR(kExpectedCharHeight, top - bottom, 0.001);
1640*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(
1641*3ac0a46fSAndroid Build Coastguard Worker FPDFText_GetCharBox(text_page.get(), 4, &left, &right, &bottom, &top));
1642*3ac0a46fSAndroid Build Coastguard Worker EXPECT_NEAR(kExpectedCharWidth, right - left, 0.001);
1643*3ac0a46fSAndroid Build Coastguard Worker EXPECT_NEAR(kExpectedCharHeight, top - bottom, 0.001);
1644*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(
1645*3ac0a46fSAndroid Build Coastguard Worker FPDFText_GetCharBox(text_page.get(), 8, &left, &right, &bottom, &top));
1646*3ac0a46fSAndroid Build Coastguard Worker EXPECT_NEAR(kExpectedCharWidth, right - left, 0.001);
1647*3ac0a46fSAndroid Build Coastguard Worker EXPECT_NEAR(kExpectedCharHeight, top - bottom, 0.001);
1648*3ac0a46fSAndroid Build Coastguard Worker
1649*3ac0a46fSAndroid Build Coastguard Worker // Check the loose character box size.
1650*3ac0a46fSAndroid Build Coastguard Worker FS_RECTF rect;
1651*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(FPDFText_GetLooseCharBox(text_page.get(), 0, &rect));
1652*3ac0a46fSAndroid Build Coastguard Worker EXPECT_FLOAT_EQ(kExpectedLooseCharWidth, rect.right - rect.left);
1653*3ac0a46fSAndroid Build Coastguard Worker EXPECT_FLOAT_EQ(kExpectedLooseCharHeight, rect.top - rect.bottom);
1654*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(FPDFText_GetLooseCharBox(text_page.get(), 4, &rect));
1655*3ac0a46fSAndroid Build Coastguard Worker EXPECT_FLOAT_EQ(kExpectedLooseCharWidth, rect.right - rect.left);
1656*3ac0a46fSAndroid Build Coastguard Worker EXPECT_FLOAT_EQ(kExpectedLooseCharHeight, rect.top - rect.bottom);
1657*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(FPDFText_GetLooseCharBox(text_page.get(), 8, &rect));
1658*3ac0a46fSAndroid Build Coastguard Worker EXPECT_FLOAT_EQ(kExpectedLooseCharWidth, rect.right - rect.left);
1659*3ac0a46fSAndroid Build Coastguard Worker EXPECT_NEAR(kExpectedLooseCharHeight, rect.top - rect.bottom, 0.00001);
1660*3ac0a46fSAndroid Build Coastguard Worker }
1661*3ac0a46fSAndroid Build Coastguard Worker
1662*3ac0a46fSAndroid Build Coastguard Worker UnloadPage(page);
1663*3ac0a46fSAndroid Build Coastguard Worker }
1664*3ac0a46fSAndroid Build Coastguard Worker
TEST_F(FPDFTextEmbedderTest,SmallType3Glyph)1665*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFTextEmbedderTest, SmallType3Glyph) {
1666*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(OpenDocument("bug_1591.pdf"));
1667*3ac0a46fSAndroid Build Coastguard Worker FPDF_PAGE page = LoadPage(0);
1668*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(page);
1669*3ac0a46fSAndroid Build Coastguard Worker
1670*3ac0a46fSAndroid Build Coastguard Worker {
1671*3ac0a46fSAndroid Build Coastguard Worker ScopedFPDFTextPage text_page(FPDFText_LoadPage(page));
1672*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(text_page);
1673*3ac0a46fSAndroid Build Coastguard Worker ASSERT_EQ(5, FPDFText_CountChars(text_page.get()));
1674*3ac0a46fSAndroid Build Coastguard Worker
1675*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(49u, FPDFText_GetUnicode(text_page.get(), 0));
1676*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(32u, FPDFText_GetUnicode(text_page.get(), 1));
1677*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(50u, FPDFText_GetUnicode(text_page.get(), 2));
1678*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(32u, FPDFText_GetUnicode(text_page.get(), 3));
1679*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(49u, FPDFText_GetUnicode(text_page.get(), 4));
1680*3ac0a46fSAndroid Build Coastguard Worker
1681*3ac0a46fSAndroid Build Coastguard Worker // Check the character box size.
1682*3ac0a46fSAndroid Build Coastguard Worker double left;
1683*3ac0a46fSAndroid Build Coastguard Worker double right;
1684*3ac0a46fSAndroid Build Coastguard Worker double bottom;
1685*3ac0a46fSAndroid Build Coastguard Worker double top;
1686*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(
1687*3ac0a46fSAndroid Build Coastguard Worker FPDFText_GetCharBox(text_page.get(), 0, &left, &right, &bottom, &top));
1688*3ac0a46fSAndroid Build Coastguard Worker EXPECT_DOUBLE_EQ(63.439998626708984, left);
1689*3ac0a46fSAndroid Build Coastguard Worker EXPECT_DOUBLE_EQ(65.360000610351562, right);
1690*3ac0a46fSAndroid Build Coastguard Worker EXPECT_DOUBLE_EQ(50.0, bottom);
1691*3ac0a46fSAndroid Build Coastguard Worker EXPECT_DOUBLE_EQ(61.520000457763672, top);
1692*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(
1693*3ac0a46fSAndroid Build Coastguard Worker FPDFText_GetCharBox(text_page.get(), 1, &left, &right, &bottom, &top));
1694*3ac0a46fSAndroid Build Coastguard Worker EXPECT_DOUBLE_EQ(62.007999420166016, left);
1695*3ac0a46fSAndroid Build Coastguard Worker EXPECT_DOUBLE_EQ(62.007999420166016, right);
1696*3ac0a46fSAndroid Build Coastguard Worker EXPECT_DOUBLE_EQ(50.0, bottom);
1697*3ac0a46fSAndroid Build Coastguard Worker EXPECT_DOUBLE_EQ(50.0, top);
1698*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(
1699*3ac0a46fSAndroid Build Coastguard Worker FPDFText_GetCharBox(text_page.get(), 2, &left, &right, &bottom, &top));
1700*3ac0a46fSAndroid Build Coastguard Worker EXPECT_DOUBLE_EQ(86.0, left);
1701*3ac0a46fSAndroid Build Coastguard Worker EXPECT_DOUBLE_EQ(88.400001525878906, right);
1702*3ac0a46fSAndroid Build Coastguard Worker EXPECT_DOUBLE_EQ(50.0, bottom);
1703*3ac0a46fSAndroid Build Coastguard Worker EXPECT_DOUBLE_EQ(50.240001678466797, top);
1704*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(
1705*3ac0a46fSAndroid Build Coastguard Worker FPDFText_GetCharBox(text_page.get(), 3, &left, &right, &bottom, &top));
1706*3ac0a46fSAndroid Build Coastguard Worker EXPECT_DOUBLE_EQ(86.010002136230469, left);
1707*3ac0a46fSAndroid Build Coastguard Worker EXPECT_DOUBLE_EQ(86.010002136230469, right);
1708*3ac0a46fSAndroid Build Coastguard Worker EXPECT_DOUBLE_EQ(50.0, bottom);
1709*3ac0a46fSAndroid Build Coastguard Worker EXPECT_DOUBLE_EQ(50.0, top);
1710*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(
1711*3ac0a46fSAndroid Build Coastguard Worker FPDFText_GetCharBox(text_page.get(), 4, &left, &right, &bottom, &top));
1712*3ac0a46fSAndroid Build Coastguard Worker EXPECT_DOUBLE_EQ(99.44000244140625, left);
1713*3ac0a46fSAndroid Build Coastguard Worker EXPECT_DOUBLE_EQ(101.36000061035156, right);
1714*3ac0a46fSAndroid Build Coastguard Worker EXPECT_DOUBLE_EQ(50.0, bottom);
1715*3ac0a46fSAndroid Build Coastguard Worker EXPECT_DOUBLE_EQ(61.520000457763672, top);
1716*3ac0a46fSAndroid Build Coastguard Worker }
1717*3ac0a46fSAndroid Build Coastguard Worker
1718*3ac0a46fSAndroid Build Coastguard Worker UnloadPage(page);
1719*3ac0a46fSAndroid Build Coastguard Worker }
1720*3ac0a46fSAndroid Build Coastguard Worker
TEST_F(FPDFTextEmbedderTest,BigtableTextExtraction)1721*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFTextEmbedderTest, BigtableTextExtraction) {
1722*3ac0a46fSAndroid Build Coastguard Worker constexpr char kExpectedText[] =
1723*3ac0a46fSAndroid Build Coastguard Worker "{fay,jeff,sanjay,wilsonh,kerr,m3b,tushar,\x02k es,gruber}@google.com";
1724*3ac0a46fSAndroid Build Coastguard Worker constexpr int kExpectedTextCount = std::size(kExpectedText) - 1;
1725*3ac0a46fSAndroid Build Coastguard Worker
1726*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(OpenDocument("bigtable_mini.pdf"));
1727*3ac0a46fSAndroid Build Coastguard Worker FPDF_PAGE page = LoadPage(0);
1728*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(page);
1729*3ac0a46fSAndroid Build Coastguard Worker
1730*3ac0a46fSAndroid Build Coastguard Worker {
1731*3ac0a46fSAndroid Build Coastguard Worker ScopedFPDFTextPage text_page(FPDFText_LoadPage(page));
1732*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(text_page);
1733*3ac0a46fSAndroid Build Coastguard Worker int char_count = FPDFText_CountChars(text_page.get());
1734*3ac0a46fSAndroid Build Coastguard Worker ASSERT_GE(char_count, 0);
1735*3ac0a46fSAndroid Build Coastguard Worker ASSERT_EQ(kExpectedTextCount, char_count);
1736*3ac0a46fSAndroid Build Coastguard Worker
1737*3ac0a46fSAndroid Build Coastguard Worker for (int i = 0; i < kExpectedTextCount; ++i) {
1738*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(static_cast<uint32_t>(kExpectedText[i]),
1739*3ac0a46fSAndroid Build Coastguard Worker FPDFText_GetUnicode(text_page.get(), i));
1740*3ac0a46fSAndroid Build Coastguard Worker }
1741*3ac0a46fSAndroid Build Coastguard Worker }
1742*3ac0a46fSAndroid Build Coastguard Worker
1743*3ac0a46fSAndroid Build Coastguard Worker UnloadPage(page);
1744*3ac0a46fSAndroid Build Coastguard Worker }
1745*3ac0a46fSAndroid Build Coastguard Worker
TEST_F(FPDFTextEmbedderTest,Bug1769)1746*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFTextEmbedderTest, Bug1769) {
1747*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(OpenDocument("bug_1769.pdf"));
1748*3ac0a46fSAndroid Build Coastguard Worker FPDF_PAGE page = LoadPage(0);
1749*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(page);
1750*3ac0a46fSAndroid Build Coastguard Worker
1751*3ac0a46fSAndroid Build Coastguard Worker {
1752*3ac0a46fSAndroid Build Coastguard Worker ScopedFPDFTextPage textpage(FPDFText_LoadPage(page));
1753*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(textpage);
1754*3ac0a46fSAndroid Build Coastguard Worker
1755*3ac0a46fSAndroid Build Coastguard Worker unsigned short buffer[128] = {};
1756*3ac0a46fSAndroid Build Coastguard Worker // TODO(crbug.com/pdfium/1769): Improve text extraction.
1757*3ac0a46fSAndroid Build Coastguard Worker // The first instance of "world" is visible to the human eye and should be
1758*3ac0a46fSAndroid Build Coastguard Worker // extracted as is. The second instance is not, so how it should be
1759*3ac0a46fSAndroid Build Coastguard Worker // extracted is debatable.
1760*3ac0a46fSAndroid Build Coastguard Worker ASSERT_EQ(10, FPDFText_GetText(textpage.get(), 0, 128, buffer));
1761*3ac0a46fSAndroid Build Coastguard Worker EXPECT_TRUE(check_unsigned_shorts("wo d wo d", buffer, 10));
1762*3ac0a46fSAndroid Build Coastguard Worker }
1763*3ac0a46fSAndroid Build Coastguard Worker
1764*3ac0a46fSAndroid Build Coastguard Worker UnloadPage(page);
1765*3ac0a46fSAndroid Build Coastguard Worker }
1766