1 // Copyright 2017 The PDFium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "xfa/fwl/cfwl_edit.h"
6
7 #include <memory>
8
9 #include "core/fxcrt/widestring.h"
10 #include "core/fxge/cfx_defaultrenderdevice.h"
11 #include "public/fpdf_ext.h"
12 #include "public/fpdf_formfill.h"
13 #include "public/fpdf_fwlevent.h"
14 #include "testing/embedder_test.h"
15 #include "testing/embedder_test_environment.h"
16 #include "testing/embedder_test_timer_handling_delegate.h"
17 #include "testing/gtest/include/gtest/gtest.h"
18 #include "testing/xfa_js_embedder_test.h"
19
20 namespace {
21
22 const char kEmailRecommendedFilledChecksum[] =
23 "211e4e46eb347aa2bc7c425556d600b0";
24
25 } // namespace
26
27 class CFWLEditEmbedderTest : public XFAJSEmbedderTest {
28 protected:
SetUp()29 void SetUp() override {
30 EmbedderTest::SetUp();
31 SetDelegate(&delegate_);
32
33 // Arbitrary, picked nice even number, 2020-09-13 12:26:40.
34 FSDK_SetTimeFunction([]() -> time_t { return 1600000000; });
35 FSDK_SetLocaltimeFunction([](const time_t* t) { return gmtime(t); });
36 }
37
TearDown()38 void TearDown() override {
39 FSDK_SetTimeFunction(nullptr);
40 FSDK_SetLocaltimeFunction(nullptr);
41 // TODO(crbug.com/pdfium/11): A page might not have been loaded if a test
42 // is skipped at runtime. This check for a non-null page should be able to
43 // removed once none of the tests are being skipped for Skia.
44 if (page())
45 UnloadPage(page());
46 EmbedderTest::TearDown();
47 }
48
CreateAndInitializeFormPDF(const char * filename)49 void CreateAndInitializeFormPDF(const char* filename) {
50 ASSERT_TRUE(OpenDocument(filename));
51 page_ = LoadPage(0);
52 ASSERT_TRUE(page_);
53 }
54
page() const55 FPDF_PAGE page() const { return page_; }
delegate() const56 EmbedderTestTimerHandlingDelegate delegate() const { return delegate_; }
57
58 private:
59 FPDF_PAGE page_ = nullptr;
60 EmbedderTestTimerHandlingDelegate delegate_;
61 };
62
TEST_F(CFWLEditEmbedderTest,Trivial)63 TEST_F(CFWLEditEmbedderTest, Trivial) {
64 CreateAndInitializeFormPDF("xfa/email_recommended.pdf");
65 ASSERT_EQ(0u, delegate().GetAlerts().size());
66 }
67
TEST_F(CFWLEditEmbedderTest,LeftClickMouseSelection)68 TEST_F(CFWLEditEmbedderTest, LeftClickMouseSelection) {
69 CreateAndInitializeFormPDF("xfa/email_recommended.pdf");
70 FORM_OnLButtonDown(form_handle(), page(), 0, 115, 58);
71 for (size_t i = 0; i < 10; ++i)
72 FORM_OnChar(form_handle(), page(), 'a' + i, 0);
73
74 // Mouse selection
75 FORM_OnLButtonDown(form_handle(), page(), 0, 128, 58);
76 FORM_OnLButtonDown(form_handle(), page(), FWL_EVENTFLAG_ShiftKey, 152, 58);
77
78 // 12 == (2 * strlen(defgh)) + 2 (for \0\0)
79 EXPECT_EQ(12UL, FORM_GetSelectedText(form_handle(), page(), nullptr, 0));
80
81 unsigned short buf[128];
82 unsigned long len = FORM_GetSelectedText(form_handle(), page(), &buf, 128);
83 EXPECT_STREQ(L"defgh", WideString::FromUTF16LE(buf, len).c_str());
84 }
85
TEST_F(CFWLEditEmbedderTest,DragMouseSelection)86 TEST_F(CFWLEditEmbedderTest, DragMouseSelection) {
87 // TODO(crbug.com/pdfium/11): Fix this test and enable for Skia variants.
88 if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer())
89 return;
90
91 CreateAndInitializeFormPDF("xfa/email_recommended.pdf");
92 FORM_OnLButtonDown(form_handle(), page(), 0, 115, 58);
93 for (size_t i = 0; i < 10; ++i)
94 FORM_OnChar(form_handle(), page(), 'a' + i, 0);
95
96 // Mouse selection
97 FORM_OnLButtonDown(form_handle(), page(), 0, 128, 58);
98 FORM_OnMouseMove(form_handle(), page(), FWL_EVENTFLAG_ShiftKey, 152, 58);
99
100 // 12 == (2 * strlen(defgh)) + 2 (for \0\0)
101 EXPECT_EQ(12UL, FORM_GetSelectedText(form_handle(), page(), nullptr, 0));
102
103 unsigned short buf[128];
104 unsigned long len = FORM_GetSelectedText(form_handle(), page(), &buf, 128);
105 EXPECT_STREQ(L"defgh", WideString::FromUTF16LE(buf, len).c_str());
106
107 // TODO(hnakashima): This is incorrect. Visually 'abcdefgh' are selected.
108 const char kDraggedMD5[] = "f131526c8edd04e44de17b2647ec54c8";
109 {
110 ScopedFPDFBitmap page_bitmap =
111 RenderLoadedPageWithFlags(page(), FPDF_ANNOT);
112 CompareBitmap(page_bitmap.get(), 612, 792, kDraggedMD5);
113 }
114 }
115
TEST_F(CFWLEditEmbedderTest,SimpleFill)116 TEST_F(CFWLEditEmbedderTest, SimpleFill) {
117 // TODO(crbug.com/pdfium/11): Fix this test and enable for Skia variants.
118 if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer())
119 return;
120
121 CreateAndInitializeFormPDF("xfa/email_recommended.pdf");
122 const char kBlankMD5[] = "8dda78a3afaf9f7b5210eb81cacc4600";
123 {
124 ScopedFPDFBitmap page_bitmap =
125 RenderLoadedPageWithFlags(page(), FPDF_ANNOT);
126 CompareBitmap(page_bitmap.get(), 612, 792, kBlankMD5);
127 }
128
129 FORM_OnLButtonDown(form_handle(), page(), 0, 115, 58);
130 for (size_t i = 0; i < 10; ++i)
131 FORM_OnChar(form_handle(), page(), 'a' + i, 0);
132
133 {
134 ScopedFPDFBitmap page_bitmap =
135 RenderLoadedPageWithFlags(page(), FPDF_ANNOT);
136 CompareBitmap(page_bitmap.get(), 612, 792, kEmailRecommendedFilledChecksum);
137 }
138 }
139
TEST_F(CFWLEditEmbedderTest,FillWithNewLineWithoutMultiline)140 TEST_F(CFWLEditEmbedderTest, FillWithNewLineWithoutMultiline) {
141 // TODO(crbug.com/pdfium/11): Fix this test and enable for Skia variants.
142 if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer())
143 return;
144
145 CreateAndInitializeFormPDF("xfa/email_recommended.pdf");
146 FORM_OnLButtonDown(form_handle(), page(), 0, 115, 58);
147 for (size_t i = 0; i < 5; ++i)
148 FORM_OnChar(form_handle(), page(), 'a' + i, 0);
149 FORM_OnChar(form_handle(), page(), '\r', 0);
150 for (size_t i = 5; i < 10; ++i)
151 FORM_OnChar(form_handle(), page(), 'a' + i, 0);
152
153 {
154 ScopedFPDFBitmap page_bitmap =
155 RenderLoadedPageWithFlags(page(), FPDF_ANNOT);
156 CompareBitmap(page_bitmap.get(), 612, 792, kEmailRecommendedFilledChecksum);
157 }
158 }
159
160 // Disabled due to flakiness.
TEST_F(CFWLEditEmbedderTest,DISABLED_FillWithNewLineWithMultiline)161 TEST_F(CFWLEditEmbedderTest, DISABLED_FillWithNewLineWithMultiline) {
162 CreateAndInitializeFormPDF("xfa/xfa_multiline_textfield.pdf");
163 FORM_OnLButtonDown(form_handle(), page(), 0, 115, 58);
164
165 for (size_t i = 0; i < 5; ++i)
166 FORM_OnChar(form_handle(), page(), 'a' + i, 0);
167 FORM_OnChar(form_handle(), page(), '\r', 0);
168 for (size_t i = 5; i < 10; ++i)
169 FORM_OnChar(form_handle(), page(), 'a' + i, 0);
170
171 // Should look like:
172 // abcde
173 // fghij|
174 {
175 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
176 const char kFilledMultilineMD5[] = "fc1f4d5fdb2c5755005fc525b0a60ec9";
177 #else
178 const char kFilledMultilineMD5[] = "a5654e027d8b1667c20f3b86d1918003";
179 #endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
180 ScopedFPDFBitmap page_bitmap =
181 RenderLoadedPageWithFlags(page(), FPDF_ANNOT);
182 CompareBitmap(page_bitmap.get(), 612, 792, kFilledMultilineMD5);
183 }
184
185 for (size_t i = 0; i < 4; ++i)
186 FORM_OnKeyDown(form_handle(), page(), FWL_VKEY_Left, 0);
187
188 // Should look like:
189 // abcde
190 // f|ghij
191
192 // Two backspaces is a workaround because left arrow does not behave well
193 // in the first character of a line. It skips back to the previous line.
194 for (size_t i = 0; i < 2; ++i)
195 FORM_OnChar(form_handle(), page(), '\b', 0);
196
197 // Should look like:
198 // abcde|ghij
199 {
200 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
201 const char kMultilineBackspaceMD5[] = "8bb62a8100ff1e1cc113d4033e0d824e";
202 #else
203 const char kMultilineBackspaceMD5[] = "a2f1dcab92bb1fb7c2f9ccc70100c989";
204 #endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
205 ScopedFPDFBitmap page_bitmap =
206 RenderLoadedPageWithFlags(page(), FPDF_ANNOT);
207 CompareBitmap(page_bitmap.get(), 612, 792, kMultilineBackspaceMD5);
208 }
209 }
210
TEST_F(CFWLEditEmbedderTest,DateTimePickerTest)211 TEST_F(CFWLEditEmbedderTest, DateTimePickerTest) {
212 // TODO(crbug.com/pdfium/11): Fix this test and enable for Skia variants.
213 if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer())
214 return;
215
216 CreateAndInitializeFormPDF("xfa/xfa_date_time_edit.pdf");
217
218 // Give focus to date time widget, creating down-arrow button.
219 FORM_OnLButtonDown(form_handle(), page(), 0, 115, 58);
220 FORM_OnLButtonUp(form_handle(), page(), 0, 115, 58);
221 const char kSelectedMD5[] = "1036b8837a9dba75c6bd8f9347ae2eb2";
222 {
223 ScopedFPDFBitmap page_bitmap =
224 RenderLoadedPageWithFlags(page(), FPDF_ANNOT);
225 CompareBitmap(page_bitmap.get(), 612, 792, kSelectedMD5);
226 }
227
228 // Click down-arrow button, bringing up calendar widget.
229 FORM_OnLButtonDown(form_handle(), page(), 0, 446, 54);
230 FORM_OnLButtonUp(form_handle(), page(), 0, 446, 54);
231 {
232 ScopedFPDFBitmap page_bitmap =
233 RenderLoadedPageWithFlags(page(), FPDF_ANNOT);
234
235 // TODO(tsepez): hermetic fonts.
236 // const char kCalendarOpenMD5[] = "02de64e7e83c82c1ef0ae484d671a51d";
237 // CompareBitmap(page_bitmap.get(), 612, 792, kCalendarOpenMD5);
238 }
239
240 // Click on date on calendar, putting result into field as text.
241 FORM_OnLButtonDown(form_handle(), page(), 0, 100, 162);
242 FORM_OnLButtonUp(form_handle(), page(), 0, 100, 162);
243 {
244 ScopedFPDFBitmap page_bitmap =
245 RenderLoadedPageWithFlags(page(), FPDF_ANNOT);
246
247 // TODO(tsepez): hermetic fonts.
248 // const char kFilledMD5[] = "1bce66c11f1c87b8d639ce0076ac36d3";
249 // CompareBitmap(page_bitmap.get(), 612, 792, kFilledMD5);
250 }
251 }
252
TEST_F(CFWLEditEmbedderTest,ImageEditTest)253 TEST_F(CFWLEditEmbedderTest, ImageEditTest) {
254 CreateAndInitializeFormPDF("xfa/xfa_image_edit.pdf");
255 FORM_OnLButtonDown(form_handle(), page(), 0, 115, 58);
256 const char* filled_checksum = []() {
257 if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer())
258 return "23658ed124114f05518372d41c80e41b";
259 return "101cf6223fa2403fba4c413a8310ab02";
260 }();
261 ScopedFPDFBitmap page_bitmap = RenderLoadedPageWithFlags(page(), FPDF_ANNOT);
262 CompareBitmap(page_bitmap.get(), 612, 792, filled_checksum);
263 }
264
TEST_F(CFWLEditEmbedderTest,ComboBoxTest)265 TEST_F(CFWLEditEmbedderTest, ComboBoxTest) {
266 CreateAndInitializeFormPDF("xfa/xfa_combobox.pdf");
267
268 // Give focus to widget.
269 FORM_OnLButtonDown(form_handle(), page(), 0, 115, 58);
270 FORM_OnLButtonUp(form_handle(), page(), 0, 115, 58);
271 {
272 const char* filled_checksum = []() {
273 if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer())
274 return "8c555487e09ee4acf3ace77db5929bdc";
275 return "dad642ae8a5afce2591ffbcabbfc58dd";
276 }();
277 ScopedFPDFBitmap page_bitmap =
278 RenderLoadedPageWithFlags(page(), FPDF_ANNOT);
279 CompareBitmap(page_bitmap.get(), 612, 792, filled_checksum);
280 }
281
282 // Click on down-arrow button, dropdown list appears.
283 FORM_OnLButtonDown(form_handle(), page(), 0, 438, 53);
284 FORM_OnLButtonUp(form_handle(), page(), 0, 438, 53);
285 {
286 ScopedFPDFBitmap page_bitmap =
287 RenderLoadedPageWithFlags(page(), FPDF_ANNOT);
288 // TODO(tsepez): hermetic fonts.
289 // const char kFilledMD5[] = "dad642ae8a5afce2591ffbcabbfc58dd";
290 // CompareBitmap(page_bitmap.get(), 612, 792, kFilledMD5);
291 }
292
293 // Enter drop-down list, selection highlighted.
294 FORM_OnMouseMove(form_handle(), page(), 0, 253, 107);
295 {
296 ScopedFPDFBitmap page_bitmap =
297 RenderLoadedPageWithFlags(page(), FPDF_ANNOT);
298 // TODO(tsepez): hermetic fonts.
299 // const char kFilledMD5[] = "dad642ae8a5afce2591ffbcabbfc58dd";
300 // CompareBitmap(page_bitmap.get(), 612, 792, kFilledMD5);
301 }
302
303 // Click on selection, putting result into field.
304 FORM_OnLButtonDown(form_handle(), page(), 0, 253, 107);
305 FORM_OnLButtonUp(form_handle(), page(), 0, 253, 107);
306 {
307 ScopedFPDFBitmap page_bitmap =
308 RenderLoadedPageWithFlags(page(), FPDF_ANNOT);
309 // TODO(tsepez): hermetic fonts.
310 // const char kFilledMD5[] = "dad642ae8a5afce2591ffbcabbfc58dd";
311 // CompareBitmap(page_bitmap.get(), 612, 792, kFilledMD5);
312 }
313 }
314