blob: 7d174ff11d1d5c8ae44253edcc7d591893405df5 [file] [log] [blame]
Jane Liu4fd9a472017-06-01 18:56:09 -04001// Copyright 2017 PDFium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Jane Liu20eafda2017-06-07 10:33:24 -04005#include <memory>
6#include <string>
Jane Liu4fd9a472017-06-01 18:56:09 -04007#include <vector>
8
Jane Liubaa7ff42017-06-29 19:18:23 -04009#include "core/fxcrt/fx_system.h"
Jane Liu4fd9a472017-06-01 18:56:09 -040010#include "public/fpdf_annot.h"
Jane Liubaa7ff42017-06-29 19:18:23 -040011#include "public/fpdf_edit.h"
Jane Liu4fd9a472017-06-01 18:56:09 -040012#include "public/fpdfview.h"
13#include "testing/embedder_test.h"
14#include "testing/gtest/include/gtest/gtest.h"
15
Nicolas Pena3ff54002017-07-05 11:55:35 -040016class FPDFAnnotEmbeddertest : public EmbedderTest {};
Jane Liu4fd9a472017-06-01 18:56:09 -040017
Jane Liue17011d2017-06-21 12:18:37 -040018TEST_F(FPDFAnnotEmbeddertest, RenderAnnotWithOnlyRolloverAP) {
19 // Open a file with one annotation and load its first page.
20 ASSERT_TRUE(OpenDocument("annotation_highlight_rollover_ap.pdf"));
21 FPDF_PAGE page = FPDF_LoadPage(document(), 0);
22 ASSERT_TRUE(page);
23
24 // This annotation has a malformed appearance stream, which does not have its
25 // normal appearance defined, only its rollover appearance. In this case, its
26 // normal appearance should be generated, allowing the highlight annotation to
27 // still display.
Nicolas Pena3ff54002017-07-05 11:55:35 -040028 FPDF_BITMAP bitmap = RenderPageWithFlags(page, form_handle(), FPDF_ANNOT);
Jane Liue17011d2017-06-21 12:18:37 -040029 CompareBitmap(bitmap, 612, 792, "dc98f06da047bd8aabfa99562d2cbd1e");
30 FPDFBitmap_Destroy(bitmap);
31
32 UnloadPage(page);
33}
34
Jane Liu4fd9a472017-06-01 18:56:09 -040035TEST_F(FPDFAnnotEmbeddertest, ExtractHighlightLongContent) {
36 // Open a file with one annotation and load its first page.
37 ASSERT_TRUE(OpenDocument("annotation_highlight_long_content.pdf"));
38 FPDF_PAGE page = FPDF_LoadPage(document(), 0);
39 ASSERT_TRUE(page);
40
41 // Check that there is a total of 1 annotation on its first page.
42 EXPECT_EQ(1, FPDFPage_GetAnnotCount(page));
43
44 // Check that the annotation is of type "highlight".
Jane Liud60e9ad2017-06-26 11:28:36 -040045 FPDF_ANNOTATION annot = FPDFPage_GetAnnot(page, 0);
46 ASSERT_TRUE(annot);
Jane Liu4fd9a472017-06-01 18:56:09 -040047 EXPECT_EQ(FPDF_ANNOT_HIGHLIGHT, FPDFAnnot_GetSubtype(annot));
48
49 // Check that the annotation color is yellow.
50 unsigned int R;
51 unsigned int G;
52 unsigned int B;
53 unsigned int A;
54 EXPECT_TRUE(
55 FPDFAnnot_GetColor(annot, FPDFANNOT_COLORTYPE_Color, &R, &G, &B, &A));
56 EXPECT_EQ(255u, R);
57 EXPECT_EQ(255u, G);
58 EXPECT_EQ(0u, B);
59 EXPECT_EQ(255u, A);
60
61 // Check that the author is correct.
62 unsigned long len =
63 FPDFAnnot_GetText(annot, FPDFANNOT_TEXTTYPE_Author, nullptr, 0);
64 std::vector<char> buf(len);
65 EXPECT_EQ(28u, FPDFAnnot_GetText(annot, FPDFANNOT_TEXTTYPE_Author, buf.data(),
66 len));
67 EXPECT_STREQ(L"Jae Hyun Park",
68 GetPlatformWString(reinterpret_cast<unsigned short*>(buf.data()))
69 .c_str());
70
71 // Check that the content is correct.
72 len = FPDFAnnot_GetText(annot, FPDFANNOT_TEXTTYPE_Contents, nullptr, 0);
73 buf.clear();
74 buf.resize(len);
75 EXPECT_EQ(2690u, FPDFAnnot_GetText(annot, FPDFANNOT_TEXTTYPE_Contents,
76 buf.data(), len));
77 const wchar_t contents[] =
78 L"This is a note for that highlight annotation. Very long highlight "
79 "annotation. Long long long Long long longLong long longLong long "
80 "longLong long longLong long longLong long longLong long longLong long "
81 "longLong long longLong long longLong long longLong long longLong long "
82 "longLong long longLong long longLong long longLong long longLong long "
83 "longLong long longLong long longLong long longLong long longLong long "
84 "longLong long longLong long longLong long longLong long longLong long "
85 "longLong long longLong long longLong long longLong long longLong long "
86 "longLong long longLong long longLong long longLong long longLong long "
87 "longLong long longLong long longLong long longLong long longLong long "
88 "longLong long longLong long longLong long longLong long longLong long "
89 "longLong long longLong long longLong long longLong long longLong long "
90 "longLong long longLong long longLong long longLong long longLong long "
91 "longLong long longLong long longLong long longLong long longLong long "
92 "longLong long longLong long longLong long longLong long longLong long "
93 "longLong long longLong long longLong long longLong long longLong long "
94 "longLong long longLong long longLong long longLong long longLong long "
95 "longLong long longLong long longLong long longLong long longLong long "
96 "longLong long longLong long longLong long longLong long longLong long "
97 "longLong long long. END";
98 EXPECT_STREQ(contents,
99 GetPlatformWString(reinterpret_cast<unsigned short*>(buf.data()))
100 .c_str());
101
102 // Check that the quadpoints are correct.
Jane Liud60e9ad2017-06-26 11:28:36 -0400103 FS_QUADPOINTSF quadpoints = FPDFAnnot_GetAttachmentPoints(annot);
Jane Liu4fd9a472017-06-01 18:56:09 -0400104 EXPECT_EQ(115.802643f, quadpoints.x1);
105 EXPECT_EQ(718.913940f, quadpoints.y1);
106 EXPECT_EQ(157.211182f, quadpoints.x4);
107 EXPECT_EQ(706.264465f, quadpoints.y4);
108
Jane Liue10509a2017-06-20 16:47:41 -0400109 FPDFPage_CloseAnnot(annot);
Jane Liu4fd9a472017-06-01 18:56:09 -0400110 UnloadPage(page);
111}
112
113TEST_F(FPDFAnnotEmbeddertest, ExtractInkMultiple) {
114 // Open a file with three annotations and load its first page.
115 ASSERT_TRUE(OpenDocument("annotation_ink_multiple.pdf"));
116 FPDF_PAGE page = FPDF_LoadPage(document(), 0);
117 ASSERT_TRUE(page);
118
119 // Check that there is a total of 3 annotation on its first page.
120 EXPECT_EQ(3, FPDFPage_GetAnnotCount(page));
121
Jane Liu20eafda2017-06-07 10:33:24 -0400122 // Check that the third annotation is of type "ink".
Jane Liud60e9ad2017-06-26 11:28:36 -0400123 FPDF_ANNOTATION annot = FPDFPage_GetAnnot(page, 2);
124 ASSERT_TRUE(annot);
Jane Liu4fd9a472017-06-01 18:56:09 -0400125 EXPECT_EQ(FPDF_ANNOT_INK, FPDFAnnot_GetSubtype(annot));
126
127 // Check that the annotation color is blue with opacity.
128 unsigned int R;
129 unsigned int G;
130 unsigned int B;
131 unsigned int A;
132 EXPECT_TRUE(
133 FPDFAnnot_GetColor(annot, FPDFANNOT_COLORTYPE_Color, &R, &G, &B, &A));
134 EXPECT_EQ(0u, R);
135 EXPECT_EQ(0u, G);
136 EXPECT_EQ(255u, B);
137 EXPECT_EQ(76u, A);
138
139 // Check that there is no content.
140 EXPECT_EQ(2u,
141 FPDFAnnot_GetText(annot, FPDFANNOT_TEXTTYPE_Contents, nullptr, 0));
142
143 // Check that the rectange coordinates are correct.
144 // Note that upon rendering, the rectangle coordinates will be adjusted.
Jane Liud60e9ad2017-06-26 11:28:36 -0400145 FS_RECTF rect = FPDFAnnot_GetRect(annot);
Jane Liu4fd9a472017-06-01 18:56:09 -0400146 EXPECT_EQ(351.820404f, rect.left);
147 EXPECT_EQ(583.830688f, rect.bottom);
148 EXPECT_EQ(475.336090f, rect.right);
149 EXPECT_EQ(681.535034f, rect.top);
150
Jane Liue10509a2017-06-20 16:47:41 -0400151 FPDFPage_CloseAnnot(annot);
Jane Liu4fd9a472017-06-01 18:56:09 -0400152 UnloadPage(page);
153}
Jane Liu20eafda2017-06-07 10:33:24 -0400154
155TEST_F(FPDFAnnotEmbeddertest, AddIllegalSubtypeAnnotation) {
156 // Open a file with one annotation and load its first page.
157 ASSERT_TRUE(OpenDocument("annotation_highlight_long_content.pdf"));
158 FPDF_PAGE page = FPDF_LoadPage(document(), 0);
159 ASSERT_TRUE(page);
160
161 // Add an annotation with an illegal subtype.
Jane Liud60e9ad2017-06-26 11:28:36 -0400162 ASSERT_FALSE(FPDFPage_CreateAnnot(page, -1));
Jane Liu20eafda2017-06-07 10:33:24 -0400163
164 UnloadPage(page);
165}
166
Jane Liud321ef92017-06-14 09:56:22 -0400167TEST_F(FPDFAnnotEmbeddertest, AddFirstTextAnnotation) {
Jane Liu20eafda2017-06-07 10:33:24 -0400168 // Open a file with no annotation and load its first page.
169 ASSERT_TRUE(OpenDocument("hello_world.pdf"));
170 FPDF_PAGE page = FPDF_LoadPage(document(), 0);
171 ASSERT_TRUE(page);
172 EXPECT_EQ(0, FPDFPage_GetAnnotCount(page));
173
Jane Liueda65252017-06-07 11:31:27 -0400174 // Add a text annotation to the page.
Jane Liud60e9ad2017-06-26 11:28:36 -0400175 FPDF_ANNOTATION annot = FPDFPage_CreateAnnot(page, FPDF_ANNOT_TEXT);
176 ASSERT_TRUE(annot);
Jane Liu20eafda2017-06-07 10:33:24 -0400177
178 // Check that there is now 1 annotations on this page.
179 EXPECT_EQ(1, FPDFPage_GetAnnotCount(page));
180
181 // Check that the subtype of the annotation is correct.
182 EXPECT_EQ(FPDF_ANNOT_TEXT, FPDFAnnot_GetSubtype(annot));
Jane Liue10509a2017-06-20 16:47:41 -0400183 FPDFPage_CloseAnnot(annot);
184
Jane Liud60e9ad2017-06-26 11:28:36 -0400185 annot = FPDFPage_GetAnnot(page, 0);
186 ASSERT_TRUE(annot);
Jane Liu20eafda2017-06-07 10:33:24 -0400187 EXPECT_EQ(FPDF_ANNOT_TEXT, FPDFAnnot_GetSubtype(annot));
188
189 // Set the color of the annotation.
190 ASSERT_TRUE(
191 FPDFAnnot_SetColor(annot, FPDFANNOT_COLORTYPE_Color, 51, 102, 153, 204));
192 // Check that the color has been set correctly.
193 unsigned int R;
194 unsigned int G;
195 unsigned int B;
196 unsigned int A;
197 EXPECT_TRUE(
198 FPDFAnnot_GetColor(annot, FPDFANNOT_COLORTYPE_Color, &R, &G, &B, &A));
199 EXPECT_EQ(51u, R);
200 EXPECT_EQ(102u, G);
201 EXPECT_EQ(153u, B);
202 EXPECT_EQ(204u, A);
203
204 // Change the color of the annotation.
205 ASSERT_TRUE(
206 FPDFAnnot_SetColor(annot, FPDFANNOT_COLORTYPE_Color, 204, 153, 102, 51));
207 // Check that the color has been set correctly.
208 EXPECT_TRUE(
209 FPDFAnnot_GetColor(annot, FPDFANNOT_COLORTYPE_Color, &R, &G, &B, &A));
210 EXPECT_EQ(204u, R);
211 EXPECT_EQ(153u, G);
212 EXPECT_EQ(102u, B);
213 EXPECT_EQ(51u, A);
214
215 // Set the annotation rectangle.
Jane Liud60e9ad2017-06-26 11:28:36 -0400216 FS_RECTF rect = FPDFAnnot_GetRect(annot);
217 EXPECT_EQ(0.f, rect.left);
218 EXPECT_EQ(0.f, rect.right);
Jane Liu20eafda2017-06-07 10:33:24 -0400219 rect.left = 35;
220 rect.bottom = 150;
221 rect.right = 53;
222 rect.top = 165;
Jane Liu06462752017-06-27 16:41:14 -0400223 ASSERT_TRUE(FPDFAnnot_SetRect(annot, &rect));
Jane Liu20eafda2017-06-07 10:33:24 -0400224 // Check that the annotation rectangle has been set correctly.
Jane Liud60e9ad2017-06-26 11:28:36 -0400225 rect = FPDFAnnot_GetRect(annot);
Jane Liu20eafda2017-06-07 10:33:24 -0400226 EXPECT_EQ(35.f, rect.left);
227 EXPECT_EQ(150.f, rect.bottom);
228 EXPECT_EQ(53.f, rect.right);
229 EXPECT_EQ(165.f, rect.top);
230
231 // Set the content of the annotation.
232 const wchar_t contents[] = L"Hello! This is a customized content.";
233 std::unique_ptr<unsigned short, pdfium::FreeDeleter> text =
234 GetFPDFWideString(contents);
235 ASSERT_TRUE(
236 FPDFAnnot_SetText(annot, FPDFANNOT_TEXTTYPE_Contents, text.get()));
237 // Check that the content has been set correctly.
238 unsigned long len =
239 FPDFAnnot_GetText(annot, FPDFANNOT_TEXTTYPE_Contents, nullptr, 0);
240 std::vector<char> buf(len);
241 EXPECT_EQ(74u, FPDFAnnot_GetText(annot, FPDFANNOT_TEXTTYPE_Contents,
242 buf.data(), len));
243 EXPECT_STREQ(contents,
244 GetPlatformWString(reinterpret_cast<unsigned short*>(buf.data()))
245 .c_str());
246
Jane Liue10509a2017-06-20 16:47:41 -0400247 FPDFPage_CloseAnnot(annot);
Jane Liu20eafda2017-06-07 10:33:24 -0400248 UnloadPage(page);
249}
250
251TEST_F(FPDFAnnotEmbeddertest, AddAndSaveUnderlineAnnotation) {
252 // Open a file with one annotation and load its first page.
253 ASSERT_TRUE(OpenDocument("annotation_highlight_long_content.pdf"));
254 FPDF_PAGE page = FPDF_LoadPage(document(), 0);
255 ASSERT_TRUE(page);
256
257 // Check that there is a total of one annotation on its first page, and verify
258 // its quadpoints.
259 EXPECT_EQ(1, FPDFPage_GetAnnotCount(page));
Jane Liud60e9ad2017-06-26 11:28:36 -0400260 FPDF_ANNOTATION annot = FPDFPage_GetAnnot(page, 0);
261 ASSERT_TRUE(annot);
262 FS_QUADPOINTSF quadpoints = FPDFAnnot_GetAttachmentPoints(annot);
Jane Liu20eafda2017-06-07 10:33:24 -0400263 EXPECT_EQ(115.802643f, quadpoints.x1);
264 EXPECT_EQ(718.913940f, quadpoints.y1);
265 EXPECT_EQ(157.211182f, quadpoints.x4);
266 EXPECT_EQ(706.264465f, quadpoints.y4);
Jane Liue10509a2017-06-20 16:47:41 -0400267 FPDFPage_CloseAnnot(annot);
Jane Liu20eafda2017-06-07 10:33:24 -0400268
269 // Add an underline annotation to the page and set its quadpoints.
Jane Liud60e9ad2017-06-26 11:28:36 -0400270 annot = FPDFPage_CreateAnnot(page, FPDF_ANNOT_UNDERLINE);
271 ASSERT_TRUE(annot);
Jane Liu20eafda2017-06-07 10:33:24 -0400272 quadpoints.x1 = 140.802643f;
273 quadpoints.x3 = 140.802643f;
Jane Liu06462752017-06-27 16:41:14 -0400274 ASSERT_TRUE(FPDFAnnot_SetAttachmentPoints(annot, &quadpoints));
Jane Liue10509a2017-06-20 16:47:41 -0400275 FPDFPage_CloseAnnot(annot);
Jane Liu20eafda2017-06-07 10:33:24 -0400276
277 // Save the document, closing the page and document.
278 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
279 FPDF_ClosePage(page);
280
281 // Open the saved document.
Nicolas Pena3ff54002017-07-05 11:55:35 -0400282 const char md5[] = "184b67b322edaee27994b3232544b8b3";
283 TestSaved(612, 792, md5);
Jane Liu20eafda2017-06-07 10:33:24 -0400284
285 // Check that the saved document has 2 annotations on the first page
Nicolas Pena3ff54002017-07-05 11:55:35 -0400286 EXPECT_EQ(2, FPDFPage_GetAnnotCount(m_SavedPage));
Jane Liu20eafda2017-06-07 10:33:24 -0400287
288 // Check that the second annotation is an underline annotation and verify
289 // its quadpoints.
Nicolas Pena3ff54002017-07-05 11:55:35 -0400290 FPDF_ANNOTATION new_annot = FPDFPage_GetAnnot(m_SavedPage, 1);
Jane Liud60e9ad2017-06-26 11:28:36 -0400291 ASSERT_TRUE(new_annot);
Jane Liu20eafda2017-06-07 10:33:24 -0400292 EXPECT_EQ(FPDF_ANNOT_UNDERLINE, FPDFAnnot_GetSubtype(new_annot));
Jane Liud60e9ad2017-06-26 11:28:36 -0400293 FS_QUADPOINTSF new_quadpoints = FPDFAnnot_GetAttachmentPoints(new_annot);
Jane Liu20eafda2017-06-07 10:33:24 -0400294 EXPECT_NEAR(quadpoints.x1, new_quadpoints.x1, 0.001f);
295 EXPECT_NEAR(quadpoints.y1, new_quadpoints.y1, 0.001f);
296 EXPECT_NEAR(quadpoints.x4, new_quadpoints.x4, 0.001f);
297 EXPECT_NEAR(quadpoints.y4, new_quadpoints.y4, 0.001f);
298
Jane Liue10509a2017-06-20 16:47:41 -0400299 FPDFPage_CloseAnnot(new_annot);
Nicolas Pena3ff54002017-07-05 11:55:35 -0400300 CloseSaved();
Jane Liu20eafda2017-06-07 10:33:24 -0400301}
Jane Liu06462752017-06-27 16:41:14 -0400302
303TEST_F(FPDFAnnotEmbeddertest, ModifyRectQuadpointsWithAP) {
304 // Open a file with four annotations and load its first page.
305 ASSERT_TRUE(OpenDocument("annotation_highlight_square_with_ap.pdf"));
306 FPDF_PAGE page = FPDF_LoadPage(document(), 0);
307 ASSERT_TRUE(page);
308 EXPECT_EQ(4, FPDFPage_GetAnnotCount(page));
309
310 // Retrieve the highlight annotation which has its AP stream already defined.
311 FPDF_ANNOTATION annot = FPDFPage_GetAnnot(page, 0);
312 ASSERT_TRUE(annot);
313 EXPECT_EQ(FPDF_ANNOT_HIGHLIGHT, FPDFAnnot_GetSubtype(annot));
314
315 // Check that color cannot be set when an AP stream is defined already.
316 EXPECT_FALSE(
317 FPDFAnnot_SetColor(annot, FPDFANNOT_COLORTYPE_Color, 51, 102, 153, 204));
318
319 // Check that when getting the attachment points, bounding box points are
320 // returned since this is a markup annotation with AP defined.
321 FS_QUADPOINTSF quadpoints = FPDFAnnot_GetAttachmentPoints(annot);
322 EXPECT_NEAR(0.f, quadpoints.x1, 0.001f);
323 EXPECT_NEAR(16.9955f, quadpoints.y1, 0.001f);
324 EXPECT_NEAR(68.5953f, quadpoints.x4, 0.001f);
325 EXPECT_NEAR(0.f, quadpoints.y4, 0.001f);
326
327 // Check that when new attachment points define a smaller bounding box, the
328 // bounding box does not get updated.
329 quadpoints.x1 = 1.0f;
330 quadpoints.x3 = 1.0f;
331 ASSERT_TRUE(FPDFAnnot_SetAttachmentPoints(annot, &quadpoints));
332 FS_QUADPOINTSF new_quadpoints = FPDFAnnot_GetAttachmentPoints(annot);
333 EXPECT_NE(quadpoints.x1, new_quadpoints.x1);
334
335 // Check that the bounding box gets updated successfully when valid attachment
336 // points are set.
337 quadpoints.x1 = 0.f;
338 quadpoints.y1 = 721.792f;
339 quadpoints.x2 = 133.055f;
340 quadpoints.y2 = 721.792f;
341 quadpoints.x3 = 0.f;
342 quadpoints.x4 = 133.055f;
343 ASSERT_TRUE(FPDFAnnot_SetAttachmentPoints(annot, &quadpoints));
344 new_quadpoints = FPDFAnnot_GetAttachmentPoints(annot);
345 EXPECT_EQ(quadpoints.x1, new_quadpoints.x1);
346 EXPECT_EQ(quadpoints.y1, new_quadpoints.y1);
347 EXPECT_EQ(quadpoints.x4, new_quadpoints.x4);
348 EXPECT_EQ(quadpoints.y4, new_quadpoints.y4);
349
350 // Check that when getting the annotation rectangle, rectangle points are
351 // returned, but not bounding box points.
352 FS_RECTF rect = FPDFAnnot_GetRect(annot);
353 EXPECT_NEAR(67.7299f, rect.left, 0.001f);
354 EXPECT_NEAR(704.296f, rect.bottom, 0.001f);
355 EXPECT_NEAR(136.325f, rect.right, 0.001f);
356 EXPECT_NEAR(721.292f, rect.top, 0.001f);
357
358 // Check that the rectangle gets updated successfully when a valid rectangle
359 // is set, and that the bounding box is not modified.
360 rect.left = 0.f;
361 rect.bottom = 0.f;
362 rect.right = 134.055f;
363 rect.top = 722.792f;
364 ASSERT_TRUE(FPDFAnnot_SetRect(annot, &rect));
365 FS_RECTF new_rect = FPDFAnnot_GetRect(annot);
366 EXPECT_EQ(rect.right, new_rect.right);
367 new_quadpoints = FPDFAnnot_GetAttachmentPoints(annot);
368 EXPECT_NE(rect.right, new_quadpoints.x2);
369
370 FPDFPage_CloseAnnot(annot);
371
372 // Retrieve the square annotation which has its AP stream already defined.
373 annot = FPDFPage_GetAnnot(page, 2);
374 ASSERT_TRUE(annot);
375 EXPECT_EQ(FPDF_ANNOT_SQUARE, FPDFAnnot_GetSubtype(annot));
376
377 // Check that the rectangle and the bounding box get updated successfully when
378 // a valid rectangle is set, since this is not a markup annotation.
379 rect = FPDFAnnot_GetRect(annot);
380 rect.right += 1.f;
381 ASSERT_TRUE(FPDFAnnot_SetRect(annot, &rect));
382 new_rect = FPDFAnnot_GetRect(annot);
383 EXPECT_EQ(rect.right, new_rect.right);
384
385 FPDFPage_CloseAnnot(annot);
386 UnloadPage(page);
387}
Jane Liu8ce58f52017-06-29 13:40:22 -0400388
389TEST_F(FPDFAnnotEmbeddertest, RemoveAnnotation) {
390 // Open a file with 3 annotations on its first page.
391 ASSERT_TRUE(OpenDocument("annotation_ink_multiple.pdf"));
392 FPDF_PAGE page = FPDF_LoadPage(document(), 0);
393 ASSERT_TRUE(page);
394 EXPECT_EQ(3, FPDFPage_GetAnnotCount(page));
395
396 // Check that the annotations have the expected rectangle coordinates.
397 FPDF_ANNOTATION annot = FPDFPage_GetAnnot(page, 0);
398 FS_RECTF rect = FPDFAnnot_GetRect(annot);
399 EXPECT_NEAR(86.1971f, rect.left, 0.001f);
400 FPDFPage_CloseAnnot(annot);
401
402 annot = FPDFPage_GetAnnot(page, 1);
403 rect = FPDFAnnot_GetRect(annot);
404 EXPECT_NEAR(149.8127f, rect.left, 0.001f);
405 FPDFPage_CloseAnnot(annot);
406
407 annot = FPDFPage_GetAnnot(page, 2);
408 rect = FPDFAnnot_GetRect(annot);
409 EXPECT_NEAR(351.8204f, rect.left, 0.001f);
410 FPDFPage_CloseAnnot(annot);
411
412 // Check that nothing happens when attempting to remove an annotation with an
413 // out-of-bound index.
414 EXPECT_FALSE(FPDFPage_RemoveAnnot(page, 4));
415 EXPECT_FALSE(FPDFPage_RemoveAnnot(page, -1));
416 EXPECT_EQ(3, FPDFPage_GetAnnotCount(page));
417
418 // Remove the second annotation.
419 EXPECT_TRUE(FPDFPage_RemoveAnnot(page, 1));
420 EXPECT_EQ(2, FPDFPage_GetAnnotCount(page));
421 EXPECT_FALSE(FPDFPage_GetAnnot(page, 2));
422
423 // Save the document, closing the page and document.
424 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
425 FPDF_ClosePage(page);
426
Nicolas Pena3ff54002017-07-05 11:55:35 -0400427 // TODO(npm): TestSaved changes annot rect dimensions by 1??
Jane Liu8ce58f52017-06-29 13:40:22 -0400428 // Open the saved document.
429 std::string new_file = GetString();
430 FPDF_FILEACCESS file_access;
431 memset(&file_access, 0, sizeof(file_access));
432 file_access.m_FileLen = new_file.size();
433 file_access.m_GetBlock = GetBlockFromString;
434 file_access.m_Param = &new_file;
435 FPDF_DOCUMENT new_doc = FPDF_LoadCustomDocument(&file_access, nullptr);
436 ASSERT_TRUE(new_doc);
437 FPDF_PAGE new_page = FPDF_LoadPage(new_doc, 0);
438 ASSERT_TRUE(new_page);
439
440 // Check that the saved document has 2 annotations on the first page.
441 EXPECT_EQ(2, FPDFPage_GetAnnotCount(new_page));
442
443 // Check that the remaining 2 annotations are the original 1st and 3rd ones by
444 // verifying their rectangle coordinates.
445 annot = FPDFPage_GetAnnot(new_page, 0);
446 rect = FPDFAnnot_GetRect(annot);
447 EXPECT_NEAR(86.1971f, rect.left, 0.001f);
448 FPDFPage_CloseAnnot(annot);
449
450 annot = FPDFPage_GetAnnot(new_page, 1);
451 rect = FPDFAnnot_GetRect(annot);
452 EXPECT_NEAR(351.8204f, rect.left, 0.001f);
453 FPDFPage_CloseAnnot(annot);
Jane Liubaa7ff42017-06-29 19:18:23 -0400454 FPDF_ClosePage(new_page);
455 FPDF_CloseDocument(new_doc);
456}
Jane Liu8ce58f52017-06-29 13:40:22 -0400457
Jane Liubaa7ff42017-06-29 19:18:23 -0400458TEST_F(FPDFAnnotEmbeddertest, AddAndModifyPath) {
459#if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
460 const char md5[] = "c35408717759562d1f8bf33d317483d2";
461 const char md5_2[] = "cf3cea74bd46497520ff6c4d1ea228c8";
462 const char md5_3[] = "ee5372b31fede117fc83b9384598aa25";
463#elif _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_
464 const char md5[] = "bdf96279ab82d9f484874db3f0c03429";
465 const char md5_2[] = "5f2b32b7aa93bc1e62a7a7971f54bdd7";
466 const char md5_3[] = "272661f3e5c9516aac4b5beb3ae1b36a";
467#else
468 const char md5[] = "07d4168715553b4294525f840c40aa1c";
469 const char md5_2[] = "dd5ba8996af67d0e5add418195e4d61b";
470 const char md5_3[] = "c60c2cc2c4e7b13be90bd77cc4502f97";
471#endif
472
473 // Open a file with two annotations and load its first page.
474 ASSERT_TRUE(OpenDocument("annotation_stamp_with_ap.pdf"));
475 FPDF_PAGE page = FPDF_LoadPage(document(), 0);
476 ASSERT_TRUE(page);
477 EXPECT_EQ(2, FPDFPage_GetAnnotCount(page));
478
479 // Check that the page renders correctly.
480 FPDF_BITMAP bitmap = RenderPageWithFlags(page, form_handle_, FPDF_ANNOT);
481 CompareBitmap(bitmap, 595, 842, md5);
482 FPDFBitmap_Destroy(bitmap);
483
484 // Retrieve the stamp annotation which has its AP stream already defined.
485 FPDF_ANNOTATION annot = FPDFPage_GetAnnot(page, 0);
486 ASSERT_TRUE(annot);
487
488 // Check that this annotation has one path object and retrieve it.
Jane Liu36567742017-07-06 11:13:35 -0400489 EXPECT_EQ(1, FPDFAnnot_GetObjectCount(annot));
490 FPDF_PAGEOBJECT path = FPDFAnnot_GetObject(annot, 1);
Jane Liubaa7ff42017-06-29 19:18:23 -0400491 EXPECT_FALSE(path);
Jane Liu36567742017-07-06 11:13:35 -0400492 path = FPDFAnnot_GetObject(annot, 0);
493 EXPECT_EQ(FPDF_PAGEOBJ_PATH, FPDFPageObj_GetType(path));
Jane Liubaa7ff42017-06-29 19:18:23 -0400494 EXPECT_TRUE(path);
495
496 // Modify the color of the path object.
497 EXPECT_TRUE(FPDFPath_SetStrokeColor(path, 0, 0, 0, 255));
Jane Liu36567742017-07-06 11:13:35 -0400498 EXPECT_TRUE(FPDFAnnot_UpdateObject(annot, path));
Jane Liubaa7ff42017-06-29 19:18:23 -0400499 FPDFPage_CloseAnnot(annot);
500
501 // Check that the page with the modified annotation renders correctly.
502 bitmap = RenderPageWithFlags(page, form_handle_, FPDF_ANNOT);
503 CompareBitmap(bitmap, 595, 842, md5_2);
504 FPDFBitmap_Destroy(bitmap);
505
506 // Create another stamp annotation and set its annotation rectangle.
507 annot = FPDFPage_CreateAnnot(page, FPDF_ANNOT_STAMP);
508 ASSERT_TRUE(annot);
509 FS_RECTF rect;
510 rect.left = 200.f;
511 rect.bottom = 400.f;
512 rect.right = 500.f;
513 rect.top = 600.f;
514 EXPECT_TRUE(FPDFAnnot_SetRect(annot, &rect));
515
516 // Add a new path to the annotation.
517 FPDF_PAGEOBJECT check = FPDFPageObj_CreateNewPath(200, 500);
518 EXPECT_TRUE(FPDFPath_LineTo(check, 300, 400));
519 EXPECT_TRUE(FPDFPath_LineTo(check, 500, 600));
520 EXPECT_TRUE(FPDFPath_MoveTo(check, 350, 550));
521 EXPECT_TRUE(FPDFPath_LineTo(check, 450, 450));
522 EXPECT_TRUE(FPDFPath_SetStrokeColor(check, 0, 255, 255, 180));
523 EXPECT_TRUE(FPDFPath_SetStrokeWidth(check, 8.35f));
524 EXPECT_TRUE(FPDFPath_SetDrawMode(check, 0, 1));
Jane Liu36567742017-07-06 11:13:35 -0400525 EXPECT_TRUE(FPDFAnnot_AppendObject(annot, check));
526 EXPECT_EQ(1, FPDFAnnot_GetObjectCount(annot));
Jane Liubaa7ff42017-06-29 19:18:23 -0400527
528 // Check that the annotation's bounding box came from its rectangle.
529 FS_RECTF new_rect = FPDFAnnot_GetRect(annot);
530 EXPECT_EQ(rect.left, new_rect.left);
531 EXPECT_EQ(rect.bottom, new_rect.bottom);
532 EXPECT_EQ(rect.right, new_rect.right);
533 EXPECT_EQ(rect.top, new_rect.top);
534
535 // Save the document, closing the page and document.
536 FPDFPage_CloseAnnot(annot);
537 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
538 FPDF_ClosePage(page);
539
540 // Open the saved document.
Nicolas Pena3ff54002017-07-05 11:55:35 -0400541 TestSaved(595, 842, md5_3);
Jane Liubaa7ff42017-06-29 19:18:23 -0400542
Jane Liu36567742017-07-06 11:13:35 -0400543 // Check that the document has a correct count of annotations and objects.
Nicolas Pena3ff54002017-07-05 11:55:35 -0400544 EXPECT_EQ(3, FPDFPage_GetAnnotCount(m_SavedPage));
545 annot = FPDFPage_GetAnnot(m_SavedPage, 2);
Jane Liubaa7ff42017-06-29 19:18:23 -0400546 ASSERT_TRUE(annot);
Jane Liu36567742017-07-06 11:13:35 -0400547 EXPECT_EQ(1, FPDFAnnot_GetObjectCount(annot));
Jane Liubaa7ff42017-06-29 19:18:23 -0400548
549 // Check that the new annotation's rectangle is as defined.
550 new_rect = FPDFAnnot_GetRect(annot);
551 EXPECT_EQ(rect.left, new_rect.left);
552 EXPECT_EQ(rect.bottom, new_rect.bottom);
553 EXPECT_EQ(rect.right, new_rect.right);
554 EXPECT_EQ(rect.top, new_rect.top);
555
Jane Liubaa7ff42017-06-29 19:18:23 -0400556 FPDFPage_CloseAnnot(annot);
Nicolas Pena3ff54002017-07-05 11:55:35 -0400557 CloseSaved();
Jane Liu8ce58f52017-06-29 13:40:22 -0400558}
Jane Liub137e752017-07-05 15:04:33 -0400559
560TEST_F(FPDFAnnotEmbeddertest, ModifyAnnotationFlags) {
561 // Open a file with an annotation and load its first page.
562 ASSERT_TRUE(OpenDocument("annotation_highlight_rollover_ap.pdf"));
563 FPDF_PAGE page = FPDF_LoadPage(document(), 0);
564 ASSERT_TRUE(page);
565
566 // Check that the page renders correctly.
567 FPDF_BITMAP bitmap = RenderPageWithFlags(page, form_handle_, FPDF_ANNOT);
568 CompareBitmap(bitmap, 612, 792, "dc98f06da047bd8aabfa99562d2cbd1e");
569 FPDFBitmap_Destroy(bitmap);
570
571 // Retrieve the annotation.
572 FPDF_ANNOTATION annot = FPDFPage_GetAnnot(page, 0);
573 ASSERT_TRUE(annot);
574
575 // Check that the original flag values are as expected.
576 int flags = FPDFAnnot_GetFlags(annot);
577 EXPECT_FALSE(flags & FPDF_ANNOT_FLAG_HIDDEN);
578 EXPECT_TRUE(flags & FPDF_ANNOT_FLAG_PRINT);
579
580 // Set the HIDDEN flag.
581 flags |= FPDF_ANNOT_FLAG_HIDDEN;
582 EXPECT_TRUE(FPDFAnnot_SetFlags(annot, flags));
583 flags = FPDFAnnot_GetFlags(annot);
584 EXPECT_TRUE(flags & FPDF_ANNOT_FLAG_HIDDEN);
585 EXPECT_TRUE(flags & FPDF_ANNOT_FLAG_PRINT);
586
587 // Check that the page renders correctly without rendering the annotation.
588 bitmap = RenderPageWithFlags(page, form_handle_, FPDF_ANNOT);
589 CompareBitmap(bitmap, 612, 792, "1940568c9ba33bac5d0b1ee9558c76b3");
590 FPDFBitmap_Destroy(bitmap);
591
592 // Unset the HIDDEN flag.
593 EXPECT_TRUE(FPDFAnnot_SetFlags(annot, FPDF_ANNOT_FLAG_NONE));
594 EXPECT_FALSE(FPDFAnnot_GetFlags(annot));
595 flags &= ~FPDF_ANNOT_FLAG_HIDDEN;
596 EXPECT_TRUE(FPDFAnnot_SetFlags(annot, flags));
597 flags = FPDFAnnot_GetFlags(annot);
598 EXPECT_FALSE(flags & FPDF_ANNOT_FLAG_HIDDEN);
599 EXPECT_TRUE(flags & FPDF_ANNOT_FLAG_PRINT);
600
601 // Check that the page renders correctly as before.
602 bitmap = RenderPageWithFlags(page, form_handle_, FPDF_ANNOT);
603 CompareBitmap(bitmap, 612, 792, "dc98f06da047bd8aabfa99562d2cbd1e");
604 FPDFBitmap_Destroy(bitmap);
605
606 FPDFPage_CloseAnnot(annot);
607 UnloadPage(page);
608}
Jane Liu36567742017-07-06 11:13:35 -0400609
610TEST_F(FPDFAnnotEmbeddertest, AddAndModifyImage) {
611#if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
612 const char md5[] = "c35408717759562d1f8bf33d317483d2";
613 const char md5_2[] = "ff012f5697436dfcaec25b32d1333596";
614 const char md5_3[] = "86cf8cb2755a7a2046a543e66d9c1e61";
615#elif _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_
616 const char md5[] = "bdf96279ab82d9f484874db3f0c03429";
617 const char md5_2[] = "048a9af8b6239b59a19dacd8e1688e0a";
618 const char md5_3[] = "3be8aa2ebc927e32060e7116dd937a14";
619#else
620 const char md5[] = "07d4168715553b4294525f840c40aa1c";
621 const char md5_2[] = "9685b2a0cf11ee730125f88ab10ff1d0";
622 const char md5_3[] = "0763407baf3656b8061bbbe698e9fd89";
623#endif
624
625 // Open a file with two annotations and load its first page.
626 ASSERT_TRUE(OpenDocument("annotation_stamp_with_ap.pdf"));
627 FPDF_PAGE page = FPDF_LoadPage(document(), 0);
628 ASSERT_TRUE(page);
629 EXPECT_EQ(2, FPDFPage_GetAnnotCount(page));
630
631 // Check that the page renders correctly.
632 FPDF_BITMAP bitmap = RenderPageWithFlags(page, form_handle_, FPDF_ANNOT);
633 CompareBitmap(bitmap, 595, 842, md5);
634 FPDFBitmap_Destroy(bitmap);
635
636 // Create a stamp annotation and set its annotation rectangle.
637 FPDF_ANNOTATION annot = FPDFPage_CreateAnnot(page, FPDF_ANNOT_STAMP);
638 ASSERT_TRUE(annot);
639 FS_RECTF rect;
640 rect.left = 200.f;
641 rect.bottom = 600.f;
642 rect.right = 400.f;
643 rect.top = 800.f;
644 EXPECT_TRUE(FPDFAnnot_SetRect(annot, &rect));
645
646 // Add a solid-color translucent image object to the new annotation.
647 constexpr int kBitmapSize = 200;
648 FPDF_BITMAP image_bitmap = FPDFBitmap_Create(kBitmapSize, kBitmapSize, 1);
649 FPDFBitmap_FillRect(image_bitmap, 0, 0, kBitmapSize, kBitmapSize, 0xeeeecccc);
650 EXPECT_EQ(kBitmapSize, FPDFBitmap_GetWidth(image_bitmap));
651 EXPECT_EQ(kBitmapSize, FPDFBitmap_GetHeight(image_bitmap));
652 FPDF_PAGEOBJECT image_object = FPDFPageObj_NewImageObj(document());
653 ASSERT_TRUE(FPDFImageObj_SetBitmap(&page, 0, image_object, image_bitmap));
654 ASSERT_TRUE(FPDFImageObj_SetMatrix(image_object, kBitmapSize, 0, 0,
655 kBitmapSize, 0, 0));
656 FPDFPageObj_Transform(image_object, 1, 0, 0, 1, 200, 600);
657 EXPECT_TRUE(FPDFAnnot_AppendObject(annot, image_object));
658 FPDFPage_CloseAnnot(annot);
659
660 // Check that the page renders correctly with the new image object.
661 bitmap = RenderPageWithFlags(page, form_handle_, FPDF_ANNOT);
662 CompareBitmap(bitmap, 595, 842, md5_2);
663 FPDFBitmap_Destroy(bitmap);
664
665 // Retrieve the newly added stamp annotation and its image object.
666 annot = FPDFPage_GetAnnot(page, 2);
667 ASSERT_TRUE(annot);
668 EXPECT_EQ(1, FPDFAnnot_GetObjectCount(annot));
669 image_object = FPDFAnnot_GetObject(annot, 0);
670 EXPECT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(image_object));
671
672 // Modify the image in the new annotation.
673 FPDFBitmap_FillRect(image_bitmap, 0, 0, kBitmapSize, kBitmapSize, 0xff000000);
674 ASSERT_TRUE(FPDFImageObj_SetBitmap(&page, 0, image_object, image_bitmap));
675 EXPECT_TRUE(FPDFAnnot_UpdateObject(annot, image_object));
676 FPDFPage_CloseAnnot(annot);
677
678 // Save the document, closing the page and document.
679 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
680 FPDF_ClosePage(page);
681
682 // Test that the saved document renders the modified image object correctly.
683 TestSaved(595, 842, md5_3);
684
685 FPDFBitmap_Destroy(image_bitmap);
686 CloseSaved();
687}
688
689TEST_F(FPDFAnnotEmbeddertest, AddAndModifyText) {
690#if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
691 const char md5[] = "c35408717759562d1f8bf33d317483d2";
692 const char md5_2[] = "e5680ed048c2cfd9a1d27212cdf41286";
693 const char md5_3[] = "79f5cfb0b07caaf936f65f6a7a57ce77";
694#elif _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_
695 const char md5[] = "bdf96279ab82d9f484874db3f0c03429";
696 const char md5_2[] = "fa5709c115d4ebd502df91841b44b3ef";
697 const char md5_3[] = "9f6fa52dc477ccf52be4184d8589ef3f";
698#else
699 const char md5[] = "07d4168715553b4294525f840c40aa1c";
700 const char md5_2[] = "40a4c5e0561b062882b47253be3393ef";
701 const char md5_3[] = "f8ce0682add01f6d273890ac64d90fa6";
702#endif
703
704 // Open a file with two annotations and load its first page.
705 ASSERT_TRUE(OpenDocument("annotation_stamp_with_ap.pdf"));
706 FPDF_PAGE page = FPDF_LoadPage(document(), 0);
707 ASSERT_TRUE(page);
708 EXPECT_EQ(2, FPDFPage_GetAnnotCount(page));
709
710 // Check that the page renders correctly.
711 FPDF_BITMAP bitmap = RenderPageWithFlags(page, form_handle_, FPDF_ANNOT);
712 CompareBitmap(bitmap, 595, 842, md5);
713 FPDFBitmap_Destroy(bitmap);
714
715 // Create a stamp annotation and set its annotation rectangle.
716 FPDF_ANNOTATION annot = FPDFPage_CreateAnnot(page, FPDF_ANNOT_STAMP);
717 ASSERT_TRUE(annot);
718 FS_RECTF rect;
719 rect.left = 200.f;
720 rect.bottom = 550.f;
721 rect.right = 450.f;
722 rect.top = 650.f;
723 EXPECT_TRUE(FPDFAnnot_SetRect(annot, &rect));
724
725 // Add a translucent text object to the new annotation.
726 FPDF_PAGEOBJECT text_object =
727 FPDFPageObj_NewTextObj(document(), "Arial", 12.0f);
728 EXPECT_TRUE(text_object);
729 std::unique_ptr<unsigned short, pdfium::FreeDeleter> text =
730 GetFPDFWideString(L"I'm a translucent text laying on other text.");
731 EXPECT_TRUE(FPDFText_SetText(text_object, text.get()));
732 EXPECT_TRUE(FPDFText_SetFillColor(text_object, 0, 0, 255, 150));
733 FPDFPageObj_Transform(text_object, 1, 0, 0, 1, 200, 600);
734 EXPECT_TRUE(FPDFAnnot_AppendObject(annot, text_object));
735 FPDFPage_CloseAnnot(annot);
736
737 // Check that the page renders correctly with the new text object.
738 bitmap = RenderPageWithFlags(page, form_handle_, FPDF_ANNOT);
739 CompareBitmap(bitmap, 595, 842, md5_2);
740 FPDFBitmap_Destroy(bitmap);
741
742 // Retrieve the newly added stamp annotation and its text object.
743 annot = FPDFPage_GetAnnot(page, 2);
744 ASSERT_TRUE(annot);
745 EXPECT_EQ(1, FPDFAnnot_GetObjectCount(annot));
746 text_object = FPDFAnnot_GetObject(annot, 0);
747 EXPECT_EQ(FPDF_PAGEOBJ_TEXT, FPDFPageObj_GetType(text_object));
748
749 // Modify the text in the new annotation.
750 std::unique_ptr<unsigned short, pdfium::FreeDeleter> new_text =
751 GetFPDFWideString(L"New text!");
752 EXPECT_TRUE(FPDFText_SetText(text_object, new_text.get()));
753 EXPECT_TRUE(FPDFAnnot_UpdateObject(annot, text_object));
754 FPDFPage_CloseAnnot(annot);
755
756 // Check that the page renders correctly with the modified text object.
757 bitmap = RenderPageWithFlags(page, form_handle_, FPDF_ANNOT);
758 CompareBitmap(bitmap, 595, 842, md5_3);
759 FPDFBitmap_Destroy(bitmap);
760
761 // Remove the new annotation, and check that the page renders as before.
762 EXPECT_TRUE(FPDFPage_RemoveAnnot(page, 2));
763 bitmap = RenderPageWithFlags(page, form_handle_, FPDF_ANNOT);
764 CompareBitmap(bitmap, 595, 842, md5);
765 FPDFBitmap_Destroy(bitmap);
766
767 UnloadPage(page);
768}