blob: 40081e6d753c9cc4c7f3dfbe1930f84b1304d7b4 [file] [log] [blame]
Tom Sepezd483eb42016-01-06 10:03:59 -08001// Copyright 2016 PDFium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Dan Sinclair85c8e7f2016-11-21 13:50:32 -05005#include <memory>
6#include <string>
Nicolas Penad03ca422017-03-06 13:54:33 -05007#include <utility>
Dan Sinclair85c8e7f2016-11-21 13:50:32 -05008
Nicolas Penabe90aae2017-02-27 10:41:41 -05009#include "core/fpdfapi/font/cpdf_font.h"
Nicolas Penaa4ad01f2017-02-15 16:26:48 -050010#include "core/fpdfapi/page/cpdf_page.h"
Nicolas Penabe90aae2017-02-27 10:41:41 -050011#include "core/fpdfapi/parser/cpdf_array.h"
Nicolas Penaa4ad01f2017-02-15 16:26:48 -050012#include "core/fpdfapi/parser/cpdf_dictionary.h"
Nicolas Penad03ca422017-03-06 13:54:33 -050013#include "core/fpdfapi/parser/cpdf_number.h"
Nicolas Penabe90aae2017-02-27 10:41:41 -050014#include "core/fpdfapi/parser/cpdf_stream.h"
Nicolas Pena0fc185e2017-02-08 12:13:20 -050015#include "core/fxcrt/fx_system.h"
Nicolas Penaa4ad01f2017-02-15 16:26:48 -050016#include "fpdfsdk/fsdk_define.h"
Nicolas Penab3161852017-05-02 14:12:50 -040017#include "public/cpp/fpdf_deleters.h"
Jane Liueda65252017-06-07 11:31:27 -040018#include "public/fpdf_annot.h"
Tom Sepezd483eb42016-01-06 10:03:59 -080019#include "public/fpdf_edit.h"
20#include "public/fpdfview.h"
21#include "testing/embedder_test.h"
Tom Sepez0aec19b2016-01-07 12:22:44 -080022#include "testing/gmock/include/gmock/gmock-matchers.h"
Tom Sepezd483eb42016-01-06 10:03:59 -080023#include "testing/gtest/include/gtest/gtest.h"
Tom Sepez0aec19b2016-01-07 12:22:44 -080024#include "testing/test_support.h"
Tom Sepezd483eb42016-01-06 10:03:59 -080025
Nicolas Penad03ca422017-03-06 13:54:33 -050026class FPDFEditEmbeddertest : public EmbedderTest, public TestSaver {
27 protected:
28 FPDF_DOCUMENT CreateNewDocument() {
29 document_ = FPDF_CreateNewDocument();
Tom Sepez41066c12017-05-18 09:28:49 -070030 cpdf_doc_ = CPDFDocumentFromFPDFDocument(document_);
Nicolas Penad03ca422017-03-06 13:54:33 -050031 return document_;
32 }
33
34 void CheckFontDescriptor(CPDF_Dictionary* font_dict,
35 int font_type,
36 bool bold,
37 bool italic,
38 uint32_t size,
39 const uint8_t* data) {
40 CPDF_Dictionary* font_desc = font_dict->GetDictFor("FontDescriptor");
41 ASSERT_TRUE(font_desc);
42 EXPECT_EQ("FontDescriptor", font_desc->GetStringFor("Type"));
43 EXPECT_EQ(font_dict->GetStringFor("BaseFont"),
44 font_desc->GetStringFor("FontName"));
45
46 // Check that the font descriptor has the required keys according to spec
47 // 1.7 Table 5.19
48 ASSERT_TRUE(font_desc->KeyExist("Flags"));
49 int font_flags = font_desc->GetIntegerFor("Flags");
50 if (bold)
51 EXPECT_TRUE(font_flags & FXFONT_BOLD);
52 else
53 EXPECT_FALSE(font_flags & FXFONT_BOLD);
54 if (italic)
55 EXPECT_TRUE(font_flags & FXFONT_ITALIC);
56 else
57 EXPECT_FALSE(font_flags & FXFONT_ITALIC);
58 EXPECT_TRUE(font_flags & FXFONT_NONSYMBOLIC);
59 ASSERT_TRUE(font_desc->KeyExist("FontBBox"));
60 EXPECT_EQ(4U, font_desc->GetArrayFor("FontBBox")->GetCount());
61 EXPECT_TRUE(font_desc->KeyExist("ItalicAngle"));
62 EXPECT_TRUE(font_desc->KeyExist("Ascent"));
63 EXPECT_TRUE(font_desc->KeyExist("Descent"));
64 EXPECT_TRUE(font_desc->KeyExist("CapHeight"));
65 EXPECT_TRUE(font_desc->KeyExist("StemV"));
66 CFX_ByteString present("FontFile");
67 CFX_ByteString absent("FontFile2");
68 if (font_type == FPDF_FONT_TRUETYPE)
69 std::swap(present, absent);
70 EXPECT_TRUE(font_desc->KeyExist(present));
71 EXPECT_FALSE(font_desc->KeyExist(absent));
72
73 // Check that the font stream is the one that was provided
74 CPDF_Stream* font_stream = font_desc->GetStreamFor(present);
75 ASSERT_EQ(size, font_stream->GetRawSize());
76 uint8_t* stream_data = font_stream->GetRawData();
77 for (size_t j = 0; j < size; j++)
78 EXPECT_EQ(data[j], stream_data[j]) << " at byte " << j;
79 }
80
81 void CheckCompositeFontWidths(CPDF_Array* widths_array,
82 CPDF_Font* typed_font) {
83 // Check that W array is in a format that conforms to PDF spec 1.7 section
84 // "Glyph Metrics in CIDFonts" (these checks are not
85 // implementation-specific).
86 EXPECT_GT(widths_array->GetCount(), 1U);
87 int num_cids_checked = 0;
88 int cur_cid = 0;
89 for (size_t idx = 0; idx < widths_array->GetCount(); idx++) {
90 int cid = widths_array->GetNumberAt(idx);
91 EXPECT_GE(cid, cur_cid);
92 ASSERT_FALSE(++idx == widths_array->GetCount());
93 CPDF_Object* next = widths_array->GetObjectAt(idx);
94 if (next->IsArray()) {
95 // We are in the c [w1 w2 ...] case
96 CPDF_Array* arr = next->AsArray();
97 int cnt = static_cast<int>(arr->GetCount());
98 size_t inner_idx = 0;
99 for (cur_cid = cid; cur_cid < cid + cnt; cur_cid++) {
100 int width = arr->GetNumberAt(inner_idx++);
101 EXPECT_EQ(width, typed_font->GetCharWidthF(cur_cid)) << " at cid "
102 << cur_cid;
103 }
104 num_cids_checked += cnt;
105 continue;
106 }
107 // Otherwise, are in the c_first c_last w case.
108 ASSERT_TRUE(next->IsNumber());
109 int last_cid = next->AsNumber()->GetInteger();
110 ASSERT_FALSE(++idx == widths_array->GetCount());
111 int width = widths_array->GetNumberAt(idx);
112 for (cur_cid = cid; cur_cid <= last_cid; cur_cid++) {
113 EXPECT_EQ(width, typed_font->GetCharWidthF(cur_cid)) << " at cid "
114 << cur_cid;
115 }
116 num_cids_checked += last_cid - cid + 1;
117 }
118 // Make sure we have a good amount of cids described
119 EXPECT_GT(num_cids_checked, 900);
120 }
121 CPDF_Document* cpdf_doc() { return cpdf_doc_; }
122
123 private:
124 CPDF_Document* cpdf_doc_;
125};
Tom Sepezd483eb42016-01-06 10:03:59 -0800126
etienneb7712c262016-04-26 08:13:45 -0700127namespace {
thestigdc7ec032016-11-21 15:32:52 -0800128
etienneb7712c262016-04-26 08:13:45 -0700129const char kExpectedPDF[] =
130 "%PDF-1.7\r\n"
131 "%\xA1\xB3\xC5\xD7\r\n"
132 "1 0 obj\r\n"
133 "<</Pages 2 0 R /Type/Catalog>>\r\n"
134 "endobj\r\n"
135 "2 0 obj\r\n"
136 "<</Count 1/Kids\\[ 4 0 R \\]/Type/Pages>>\r\n"
137 "endobj\r\n"
138 "3 0 obj\r\n"
139 "<</CreationDate\\(D:.*\\)/Creator\\(PDFium\\)>>\r\n"
140 "endobj\r\n"
141 "4 0 obj\r\n"
Nicolas Penad9d6c292017-06-06 16:12:10 -0400142 "<</MediaBox\\[ 0 0 640 480\\]/Parent 2 0 R /Resources<<>>"
143 "/Rotate 0/Type/Page"
etienneb7712c262016-04-26 08:13:45 -0700144 ">>\r\n"
145 "endobj\r\n"
etienneb7712c262016-04-26 08:13:45 -0700146 "xref\r\n"
Nicolas Penad9d6c292017-06-06 16:12:10 -0400147 "0 5\r\n"
etienneb7712c262016-04-26 08:13:45 -0700148 "0000000000 65535 f\r\n"
149 "0000000017 00000 n\r\n"
150 "0000000066 00000 n\r\n"
151 "0000000122 00000 n\r\n"
152 "0000000192 00000 n\r\n"
etienneb7712c262016-04-26 08:13:45 -0700153 "trailer\r\n"
154 "<<\r\n"
155 "/Root 1 0 R\r\n"
156 "/Info 3 0 R\r\n"
Nicolas Penad9d6c292017-06-06 16:12:10 -0400157 "/Size 5/ID\\[<.*><.*>\\]>>\r\n"
etienneb7712c262016-04-26 08:13:45 -0700158 "startxref\r\n"
Nicolas Penad9d6c292017-06-06 16:12:10 -0400159 "285\r\n"
etienneb7712c262016-04-26 08:13:45 -0700160 "%%EOF\r\n";
thestigdc7ec032016-11-21 15:32:52 -0800161
etienneb7712c262016-04-26 08:13:45 -0700162} // namespace
163
Tom Sepezd483eb42016-01-06 10:03:59 -0800164TEST_F(FPDFEditEmbeddertest, EmptyCreation) {
165 EXPECT_TRUE(CreateEmptyDocument());
weili9b777de2016-08-19 16:19:46 -0700166 FPDF_PAGE page = FPDFPage_New(document(), 0, 640.0, 480.0);
Tom Sepezd483eb42016-01-06 10:03:59 -0800167 EXPECT_NE(nullptr, page);
Nicolas Penad9d6c292017-06-06 16:12:10 -0400168 // The FPDFPage_GenerateContent call should do nothing.
Tom Sepezd483eb42016-01-06 10:03:59 -0800169 EXPECT_TRUE(FPDFPage_GenerateContent(page));
Tom Sepez0aec19b2016-01-07 12:22:44 -0800170 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
etienneb7712c262016-04-26 08:13:45 -0700171
Nicolas Penad9d6c292017-06-06 16:12:10 -0400172 EXPECT_THAT(GetString(), testing::MatchesRegex(std::string(
173 kExpectedPDF, sizeof(kExpectedPDF))));
weili9b777de2016-08-19 16:19:46 -0700174 FPDF_ClosePage(page);
Tom Sepezd483eb42016-01-06 10:03:59 -0800175}
thestigdc7ec032016-11-21 15:32:52 -0800176
177// Regression test for https://crbug.com/667012
178TEST_F(FPDFEditEmbeddertest, RasterizePDF) {
179 const char kAllBlackMd5sum[] = "5708fc5c4a8bd0abde99c8e8f0390615";
180
181 // Get the bitmap for the original document/
182 FPDF_BITMAP orig_bitmap;
183 {
184 EXPECT_TRUE(OpenDocument("black.pdf"));
185 FPDF_PAGE orig_page = LoadPage(0);
186 EXPECT_NE(nullptr, orig_page);
187 orig_bitmap = RenderPage(orig_page);
188 CompareBitmap(orig_bitmap, 612, 792, kAllBlackMd5sum);
189 UnloadPage(orig_page);
190 }
191
192 // Create a new document from |orig_bitmap| and save it.
193 {
194 FPDF_DOCUMENT temp_doc = FPDF_CreateNewDocument();
195 FPDF_PAGE temp_page = FPDFPage_New(temp_doc, 0, 612, 792);
196
197 // Add the bitmap to an image object and add the image object to the output
198 // page.
Lei Zhangcbd89572017-03-15 17:35:47 -0700199 FPDF_PAGEOBJECT temp_img = FPDFPageObj_NewImageObj(temp_doc);
thestigdc7ec032016-11-21 15:32:52 -0800200 EXPECT_TRUE(FPDFImageObj_SetBitmap(&temp_page, 1, temp_img, orig_bitmap));
201 EXPECT_TRUE(FPDFImageObj_SetMatrix(temp_img, 612, 0, 0, 792, 0, 0));
202 FPDFPage_InsertObject(temp_page, temp_img);
203 EXPECT_TRUE(FPDFPage_GenerateContent(temp_page));
204 EXPECT_TRUE(FPDF_SaveAsCopy(temp_doc, this, 0));
205 FPDF_ClosePage(temp_page);
206 FPDF_CloseDocument(temp_doc);
207 }
208 FPDFBitmap_Destroy(orig_bitmap);
209
210 // Get the generated content. Make sure it is at least as big as the original
211 // PDF.
212 std::string new_file = GetString();
213 EXPECT_GT(new_file.size(), 923U);
214
215 // Read |new_file| in, and verify its rendered bitmap.
216 {
217 FPDF_FILEACCESS file_access;
218 memset(&file_access, 0, sizeof(file_access));
219 file_access.m_FileLen = new_file.size();
220 file_access.m_GetBlock = GetBlockFromString;
221 file_access.m_Param = &new_file;
222
223 FPDF_DOCUMENT new_doc = FPDF_LoadCustomDocument(&file_access, nullptr);
224 EXPECT_EQ(1, FPDF_GetPageCount(document_));
225 FPDF_PAGE new_page = FPDF_LoadPage(new_doc, 0);
226 EXPECT_NE(nullptr, new_page);
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500227 FPDF_BITMAP new_bitmap = RenderPage(new_page);
thestigdc7ec032016-11-21 15:32:52 -0800228 CompareBitmap(new_bitmap, 612, 792, kAllBlackMd5sum);
229 FPDF_ClosePage(new_page);
230 FPDF_CloseDocument(new_doc);
231 FPDFBitmap_Destroy(new_bitmap);
232 }
233}
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500234
235TEST_F(FPDFEditEmbeddertest, AddPaths) {
236 // Start with a blank page
Nicolas Penad03ca422017-03-06 13:54:33 -0500237 FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500238
239 // We will first add a red rectangle
240 FPDF_PAGEOBJECT red_rect = FPDFPageObj_CreateNewRect(10, 10, 20, 20);
241 ASSERT_NE(nullptr, red_rect);
242 // Expect false when trying to set colors out of range
243 EXPECT_FALSE(FPDFPath_SetStrokeColor(red_rect, 100, 100, 100, 300));
244 EXPECT_FALSE(FPDFPath_SetFillColor(red_rect, 200, 256, 200, 0));
245
246 // Fill rectangle with red and insert to the page
247 EXPECT_TRUE(FPDFPath_SetFillColor(red_rect, 255, 0, 0, 255));
248 EXPECT_TRUE(FPDFPath_SetDrawMode(red_rect, FPDF_FILLMODE_ALTERNATE, 0));
249 FPDFPage_InsertObject(page, red_rect);
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500250 FPDF_BITMAP page_bitmap = RenderPage(page);
251 CompareBitmap(page_bitmap, 612, 792, "66d02eaa6181e2c069ce2ea99beda497");
252 FPDFBitmap_Destroy(page_bitmap);
253
254 // Now add to that a green rectangle with some medium alpha
255 FPDF_PAGEOBJECT green_rect = FPDFPageObj_CreateNewRect(100, 100, 40, 40);
256 EXPECT_TRUE(FPDFPath_SetFillColor(green_rect, 0, 255, 0, 128));
Miklos Vajnaed4705b2017-04-05 09:24:50 +0200257
Miklos Vajna1ef04c92017-05-08 18:14:19 +0200258 // Make sure the type of the rectangle is a path.
259 EXPECT_EQ(FPDF_PAGEOBJ_PATH, FPDFPageObj_GetType(green_rect));
260
Miklos Vajnaed4705b2017-04-05 09:24:50 +0200261 // Make sure we get back the same color we set previously.
262 unsigned int R;
263 unsigned int G;
264 unsigned int B;
265 unsigned int A;
266 EXPECT_TRUE(FPDFPath_GetFillColor(green_rect, &R, &G, &B, &A));
267 EXPECT_EQ(0U, R);
268 EXPECT_EQ(255U, G);
269 EXPECT_EQ(0U, B);
270 EXPECT_EQ(128U, A);
271
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500272 EXPECT_TRUE(FPDFPath_SetDrawMode(green_rect, FPDF_FILLMODE_WINDING, 0));
273 FPDFPage_InsertObject(page, green_rect);
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500274 page_bitmap = RenderPage(page);
275 CompareBitmap(page_bitmap, 612, 792, "7b0b87604594e773add528fae567a558");
276 FPDFBitmap_Destroy(page_bitmap);
277
278 // Add a black triangle.
279 FPDF_PAGEOBJECT black_path = FPDFPageObj_CreateNewPath(400, 100);
280 EXPECT_TRUE(FPDFPath_SetFillColor(black_path, 0, 0, 0, 200));
281 EXPECT_TRUE(FPDFPath_SetDrawMode(black_path, FPDF_FILLMODE_ALTERNATE, 0));
282 EXPECT_TRUE(FPDFPath_LineTo(black_path, 400, 200));
283 EXPECT_TRUE(FPDFPath_LineTo(black_path, 300, 100));
284 EXPECT_TRUE(FPDFPath_Close(black_path));
285 FPDFPage_InsertObject(page, black_path);
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500286 page_bitmap = RenderPage(page);
287 CompareBitmap(page_bitmap, 612, 792, "eadc8020a14dfcf091da2688733d8806");
288 FPDFBitmap_Destroy(page_bitmap);
289
290 // Now add a more complex blue path.
291 FPDF_PAGEOBJECT blue_path = FPDFPageObj_CreateNewPath(200, 200);
292 EXPECT_TRUE(FPDFPath_SetFillColor(blue_path, 0, 0, 255, 255));
293 EXPECT_TRUE(FPDFPath_SetDrawMode(blue_path, FPDF_FILLMODE_WINDING, 0));
294 EXPECT_TRUE(FPDFPath_LineTo(blue_path, 230, 230));
295 EXPECT_TRUE(FPDFPath_BezierTo(blue_path, 250, 250, 280, 280, 300, 300));
296 EXPECT_TRUE(FPDFPath_LineTo(blue_path, 325, 325));
297 EXPECT_TRUE(FPDFPath_LineTo(blue_path, 350, 325));
298 EXPECT_TRUE(FPDFPath_BezierTo(blue_path, 375, 330, 390, 360, 400, 400));
299 EXPECT_TRUE(FPDFPath_Close(blue_path));
300 FPDFPage_InsertObject(page, blue_path);
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500301 page_bitmap = RenderPage(page);
302 CompareBitmap(page_bitmap, 612, 792, "9823e1a21bd9b72b6a442ba4f12af946");
303 FPDFBitmap_Destroy(page_bitmap);
304
305 // Now save the result, closing the page and document
Nicolas Pena207b7272017-05-26 17:37:06 -0400306 EXPECT_TRUE(FPDFPage_GenerateContent(page));
Nicolas Penad03ca422017-03-06 13:54:33 -0500307 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500308 FPDF_ClosePage(page);
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500309 std::string new_file = GetString();
310
311 // Render the saved result
312 FPDF_FILEACCESS file_access;
313 memset(&file_access, 0, sizeof(file_access));
314 file_access.m_FileLen = new_file.size();
315 file_access.m_GetBlock = GetBlockFromString;
316 file_access.m_Param = &new_file;
317 FPDF_DOCUMENT new_doc = FPDF_LoadCustomDocument(&file_access, nullptr);
318 ASSERT_NE(nullptr, new_doc);
319 EXPECT_EQ(1, FPDF_GetPageCount(new_doc));
320 FPDF_PAGE new_page = FPDF_LoadPage(new_doc, 0);
321 ASSERT_NE(nullptr, new_page);
322 FPDF_BITMAP new_bitmap = RenderPage(new_page);
323 CompareBitmap(new_bitmap, 612, 792, "9823e1a21bd9b72b6a442ba4f12af946");
324 FPDFBitmap_Destroy(new_bitmap);
325 FPDF_ClosePage(new_page);
326 FPDF_CloseDocument(new_doc);
327}
328
329TEST_F(FPDFEditEmbeddertest, PathOnTopOfText) {
330 // Load document with some text
331 EXPECT_TRUE(OpenDocument("hello_world.pdf"));
332 FPDF_PAGE page = LoadPage(0);
333 EXPECT_NE(nullptr, page);
334
335 // Add an opaque rectangle on top of some of the text.
336 FPDF_PAGEOBJECT red_rect = FPDFPageObj_CreateNewRect(20, 100, 50, 50);
337 EXPECT_TRUE(FPDFPath_SetFillColor(red_rect, 255, 0, 0, 255));
338 EXPECT_TRUE(FPDFPath_SetDrawMode(red_rect, FPDF_FILLMODE_ALTERNATE, 0));
339 FPDFPage_InsertObject(page, red_rect);
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500340
341 // Add a transparent triangle on top of other part of the text.
342 FPDF_PAGEOBJECT black_path = FPDFPageObj_CreateNewPath(20, 50);
343 EXPECT_TRUE(FPDFPath_SetFillColor(black_path, 0, 0, 0, 100));
344 EXPECT_TRUE(FPDFPath_SetDrawMode(black_path, FPDF_FILLMODE_ALTERNATE, 0));
345 EXPECT_TRUE(FPDFPath_LineTo(black_path, 30, 80));
346 EXPECT_TRUE(FPDFPath_LineTo(black_path, 40, 10));
347 EXPECT_TRUE(FPDFPath_Close(black_path));
348 FPDFPage_InsertObject(page, black_path);
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500349
350 // Render and check the result. Text is slightly different on Mac.
351 FPDF_BITMAP bitmap = RenderPage(page);
352#if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
Lei Zhang0d6d1782017-03-24 15:52:00 -0700353 const char md5[] = "f9e6fa74230f234286bfcada9f7606d8";
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500354#else
Lei Zhang3de50052017-03-29 21:02:13 -0700355 const char md5[] = "2fdfc5dda29374cfba4349362e38ebdb";
Nicolas Pena5bcd9a32017-03-22 11:04:35 -0400356#endif
Lei Zhang0d6d1782017-03-24 15:52:00 -0700357 CompareBitmap(bitmap, 200, 200, md5);
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500358 FPDFBitmap_Destroy(bitmap);
359 UnloadPage(page);
360}
Nicolas Pena2eb1a702017-02-09 18:17:33 -0500361
wileyryae858aa42017-05-31 14:49:05 -0500362TEST_F(FPDFEditEmbeddertest, EditOverExistingContent) {
363 // Load document with existing content
364 EXPECT_TRUE(OpenDocument("bug_717.pdf"));
365 FPDF_PAGE page = LoadPage(0);
366 EXPECT_NE(nullptr, page);
367
368 // Add a transparent rectangle on top of the existing content
369 FPDF_PAGEOBJECT red_rect2 = FPDFPageObj_CreateNewRect(90, 700, 25, 50);
370 EXPECT_TRUE(FPDFPath_SetFillColor(red_rect2, 255, 0, 0, 100));
371 EXPECT_TRUE(FPDFPath_SetDrawMode(red_rect2, FPDF_FILLMODE_ALTERNATE, 0));
372 FPDFPage_InsertObject(page, red_rect2);
373
374 // Add an opaque rectangle on top of the existing content
375 FPDF_PAGEOBJECT red_rect = FPDFPageObj_CreateNewRect(115, 700, 25, 50);
376 EXPECT_TRUE(FPDFPath_SetFillColor(red_rect, 255, 0, 0, 255));
377 EXPECT_TRUE(FPDFPath_SetDrawMode(red_rect, FPDF_FILLMODE_ALTERNATE, 0));
378 FPDFPage_InsertObject(page, red_rect);
379
380 FPDF_BITMAP bitmap = RenderPage(page);
381 CompareBitmap(bitmap, 612, 792, "ad04e5bd0f471a9a564fb034bd0fb073");
382 FPDFBitmap_Destroy(bitmap);
383 EXPECT_TRUE(FPDFPage_GenerateContent(page));
384
385 // Now save the result, closing the page and document
386 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
387 FPDF_ClosePage(page);
388
389 // Render the saved result
390 std::string new_file = GetString();
391 FPDF_FILEACCESS file_access;
392 memset(&file_access, 0, sizeof(file_access));
393 file_access.m_FileLen = new_file.size();
394 file_access.m_GetBlock = GetBlockFromString;
395 file_access.m_Param = &new_file;
396 FPDF_DOCUMENT new_doc = FPDF_LoadCustomDocument(&file_access, nullptr);
397 ASSERT_NE(nullptr, new_doc);
398 EXPECT_EQ(1, FPDF_GetPageCount(new_doc));
399 FPDF_PAGE new_page = FPDF_LoadPage(new_doc, 0);
400 ASSERT_NE(nullptr, new_page);
401 FPDF_BITMAP new_bitmap = RenderPage(new_page);
402 CompareBitmap(new_bitmap, 612, 792, "ad04e5bd0f471a9a564fb034bd0fb073");
403 FPDFBitmap_Destroy(new_bitmap);
404
405 ClearString();
406 // Add another opaque rectangle on top of the existing content
407 FPDF_PAGEOBJECT green_rect = FPDFPageObj_CreateNewRect(150, 700, 25, 50);
408 EXPECT_TRUE(FPDFPath_SetFillColor(green_rect, 0, 255, 0, 255));
409 EXPECT_TRUE(FPDFPath_SetDrawMode(green_rect, FPDF_FILLMODE_ALTERNATE, 0));
410 FPDFPage_InsertObject(new_page, green_rect);
411
412 // Add another transparent rectangle on top of existing content
413 FPDF_PAGEOBJECT green_rect2 = FPDFPageObj_CreateNewRect(175, 700, 25, 50);
414 EXPECT_TRUE(FPDFPath_SetFillColor(green_rect2, 0, 255, 0, 100));
415 EXPECT_TRUE(FPDFPath_SetDrawMode(green_rect2, FPDF_FILLMODE_ALTERNATE, 0));
416 FPDFPage_InsertObject(new_page, green_rect2);
417 new_bitmap = RenderPage(new_page);
418 CompareBitmap(new_bitmap, 612, 792, "4b5b00f824620f8c9b8801ebb98e1cdd");
419 FPDFBitmap_Destroy(new_bitmap);
420 EXPECT_TRUE(FPDFPage_GenerateContent(new_page));
421
422 // Now save the result, closing the page and document
423 EXPECT_TRUE(FPDF_SaveAsCopy(new_doc, this, 0));
424 FPDF_ClosePage(new_page);
425 FPDF_CloseDocument(new_doc);
426
427 // Render the saved result
428 new_file = GetString();
429 memset(&file_access, 0, sizeof(file_access));
430 file_access.m_FileLen = new_file.size();
431 file_access.m_GetBlock = GetBlockFromString;
432 file_access.m_Param = &new_file;
433 new_doc = FPDF_LoadCustomDocument(&file_access, nullptr);
434 ASSERT_NE(nullptr, new_doc);
435 EXPECT_EQ(1, FPDF_GetPageCount(new_doc));
436 new_page = FPDF_LoadPage(new_doc, 0);
437 ASSERT_NE(nullptr, new_page);
438 new_bitmap = RenderPage(new_page);
439 CompareBitmap(new_bitmap, 612, 792, "4b5b00f824620f8c9b8801ebb98e1cdd");
440 FPDFBitmap_Destroy(new_bitmap);
441
442 FPDF_ClosePage(new_page);
443 FPDF_CloseDocument(new_doc);
444}
445
Nicolas Pena2eb1a702017-02-09 18:17:33 -0500446TEST_F(FPDFEditEmbeddertest, AddStrokedPaths) {
447 // Start with a blank page
Nicolas Penad03ca422017-03-06 13:54:33 -0500448 FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
Nicolas Pena2eb1a702017-02-09 18:17:33 -0500449
450 // Add a large stroked rectangle (fill color should not affect it).
451 FPDF_PAGEOBJECT rect = FPDFPageObj_CreateNewRect(20, 20, 200, 400);
452 EXPECT_TRUE(FPDFPath_SetFillColor(rect, 255, 0, 0, 255));
453 EXPECT_TRUE(FPDFPath_SetStrokeColor(rect, 0, 255, 0, 255));
454 EXPECT_TRUE(FPDFPath_SetStrokeWidth(rect, 15.0f));
455 EXPECT_TRUE(FPDFPath_SetDrawMode(rect, 0, 1));
456 FPDFPage_InsertObject(page, rect);
Nicolas Pena2eb1a702017-02-09 18:17:33 -0500457 FPDF_BITMAP page_bitmap = RenderPage(page);
458 CompareBitmap(page_bitmap, 612, 792, "64bd31f862a89e0a9e505a5af6efd506");
459 FPDFBitmap_Destroy(page_bitmap);
460
461 // Add crossed-checkmark
462 FPDF_PAGEOBJECT check = FPDFPageObj_CreateNewPath(300, 500);
463 EXPECT_TRUE(FPDFPath_LineTo(check, 400, 400));
464 EXPECT_TRUE(FPDFPath_LineTo(check, 600, 600));
465 EXPECT_TRUE(FPDFPath_MoveTo(check, 400, 600));
466 EXPECT_TRUE(FPDFPath_LineTo(check, 600, 400));
467 EXPECT_TRUE(FPDFPath_SetStrokeColor(check, 128, 128, 128, 180));
468 EXPECT_TRUE(FPDFPath_SetStrokeWidth(check, 8.35f));
469 EXPECT_TRUE(FPDFPath_SetDrawMode(check, 0, 1));
470 FPDFPage_InsertObject(page, check);
Nicolas Pena2eb1a702017-02-09 18:17:33 -0500471 page_bitmap = RenderPage(page);
472 CompareBitmap(page_bitmap, 612, 792, "4b6f3b9d25c4e194821217d5016c3724");
473 FPDFBitmap_Destroy(page_bitmap);
474
475 // Add stroked and filled oval-ish path.
476 FPDF_PAGEOBJECT path = FPDFPageObj_CreateNewPath(250, 100);
477 EXPECT_TRUE(FPDFPath_BezierTo(path, 180, 166, 180, 233, 250, 300));
478 EXPECT_TRUE(FPDFPath_LineTo(path, 255, 305));
479 EXPECT_TRUE(FPDFPath_BezierTo(path, 325, 233, 325, 166, 255, 105));
480 EXPECT_TRUE(FPDFPath_Close(path));
481 EXPECT_TRUE(FPDFPath_SetFillColor(path, 200, 128, 128, 100));
482 EXPECT_TRUE(FPDFPath_SetStrokeColor(path, 128, 200, 128, 150));
483 EXPECT_TRUE(FPDFPath_SetStrokeWidth(path, 10.5f));
484 EXPECT_TRUE(FPDFPath_SetDrawMode(path, FPDF_FILLMODE_ALTERNATE, 1));
485 FPDFPage_InsertObject(page, path);
Nicolas Pena2eb1a702017-02-09 18:17:33 -0500486 page_bitmap = RenderPage(page);
487 CompareBitmap(page_bitmap, 612, 792, "ff3e6a22326754944cc6e56609acd73b");
488 FPDFBitmap_Destroy(page_bitmap);
489 FPDF_ClosePage(page);
Nicolas Pena2eb1a702017-02-09 18:17:33 -0500490}
Nicolas Pena49058402017-02-14 18:26:20 -0500491
492TEST_F(FPDFEditEmbeddertest, AddStandardFontText) {
493 // Start with a blank page
Nicolas Penad03ca422017-03-06 13:54:33 -0500494 FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
Nicolas Pena49058402017-02-14 18:26:20 -0500495
496 // Add some text to the page
Nicolas Penab3161852017-05-02 14:12:50 -0400497 FPDF_PAGEOBJECT text_object1 =
498 FPDFPageObj_NewTextObj(document(), "Arial", 12.0f);
499 EXPECT_TRUE(text_object1);
500 std::unique_ptr<unsigned short, pdfium::FreeDeleter> text1 =
501 GetFPDFWideString(L"I'm at the bottom of the page");
502 EXPECT_TRUE(FPDFText_SetText(text_object1, text1.get()));
503 FPDFPageObj_Transform(text_object1, 1, 0, 0, 1, 20, 20);
504 FPDFPage_InsertObject(page, text_object1);
Nicolas Pena49058402017-02-14 18:26:20 -0500505 FPDF_BITMAP page_bitmap = RenderPage(page);
506#if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
Lei Zhang0d6d1782017-03-24 15:52:00 -0700507 const char md5[] = "a4dddc1a3930fa694bbff9789dab4161";
Nicolas Pena49058402017-02-14 18:26:20 -0500508#else
Lei Zhang3de50052017-03-29 21:02:13 -0700509 const char md5[] = "6e8a9b0682f60fd3ff1bf087b093d30d";
Nicolas Pena5bcd9a32017-03-22 11:04:35 -0400510#endif
Lei Zhang0d6d1782017-03-24 15:52:00 -0700511 CompareBitmap(page_bitmap, 612, 792, md5);
Nicolas Pena49058402017-02-14 18:26:20 -0500512 FPDFBitmap_Destroy(page_bitmap);
513
514 // Try another font
Nicolas Penab3161852017-05-02 14:12:50 -0400515 FPDF_PAGEOBJECT text_object2 =
Nicolas Penad03ca422017-03-06 13:54:33 -0500516 FPDFPageObj_NewTextObj(document(), "TimesNewRomanBold", 15.0f);
Nicolas Penab3161852017-05-02 14:12:50 -0400517 EXPECT_TRUE(text_object2);
518 std::unique_ptr<unsigned short, pdfium::FreeDeleter> text2 =
519 GetFPDFWideString(L"Hi, I'm Bold. Times New Roman Bold.");
520 EXPECT_TRUE(FPDFText_SetText(text_object2, text2.get()));
521 FPDFPageObj_Transform(text_object2, 1, 0, 0, 1, 100, 600);
522 FPDFPage_InsertObject(page, text_object2);
Nicolas Pena49058402017-02-14 18:26:20 -0500523 page_bitmap = RenderPage(page);
524#if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
Lei Zhang0d6d1782017-03-24 15:52:00 -0700525 const char md5_2[] = "a5c4ace4c6f27644094813fe1441a21c";
Lei Zhang3de50052017-03-29 21:02:13 -0700526#elif _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_
527 const char md5_2[] = "56863642d4d8b418cfd810fdb5a5d92f";
Nicolas Pena49058402017-02-14 18:26:20 -0500528#else
Lei Zhang3de50052017-03-29 21:02:13 -0700529 const char md5_2[] = "0c83875429688bda45a55a692d5aa781";
Nicolas Pena5bcd9a32017-03-22 11:04:35 -0400530#endif
Lei Zhang0d6d1782017-03-24 15:52:00 -0700531 CompareBitmap(page_bitmap, 612, 792, md5_2);
Nicolas Pena49058402017-02-14 18:26:20 -0500532 FPDFBitmap_Destroy(page_bitmap);
533
534 // And some randomly transformed text
Nicolas Penab3161852017-05-02 14:12:50 -0400535 FPDF_PAGEOBJECT text_object3 =
Nicolas Penad03ca422017-03-06 13:54:33 -0500536 FPDFPageObj_NewTextObj(document(), "Courier-Bold", 20.0f);
Nicolas Penab3161852017-05-02 14:12:50 -0400537 EXPECT_TRUE(text_object3);
538 std::unique_ptr<unsigned short, pdfium::FreeDeleter> text3 =
539 GetFPDFWideString(L"Can you read me? <:)>");
540 EXPECT_TRUE(FPDFText_SetText(text_object3, text3.get()));
541 FPDFPageObj_Transform(text_object3, 1, 1.5, 2, 0.5, 200, 200);
542 FPDFPage_InsertObject(page, text_object3);
Nicolas Pena49058402017-02-14 18:26:20 -0500543 page_bitmap = RenderPage(page);
544#if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
Lei Zhang0d6d1782017-03-24 15:52:00 -0700545 const char md5_3[] = "40b3ef04f915ff4c4208948001763544";
Lei Zhang3de50052017-03-29 21:02:13 -0700546#elif _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_
Lei Zhangb8e89e32017-05-02 11:53:08 -0700547 const char md5_3[] = "d69d419def35a098d9c10f8317d6709b";
Nicolas Pena49058402017-02-14 18:26:20 -0500548#else
Lei Zhangb8e89e32017-05-02 11:53:08 -0700549 const char md5_3[] = "8b300d3c6dfc12fa9af97e12ed5bd80a";
Nicolas Pena5bcd9a32017-03-22 11:04:35 -0400550#endif
Lei Zhang0d6d1782017-03-24 15:52:00 -0700551 CompareBitmap(page_bitmap, 612, 792, md5_3);
Nicolas Pena49058402017-02-14 18:26:20 -0500552 FPDFBitmap_Destroy(page_bitmap);
553
554 // TODO(npm): Why are there issues with text rotated by 90 degrees?
555 // TODO(npm): FPDF_SaveAsCopy not giving the desired result after this.
556 FPDF_ClosePage(page);
Nicolas Pena49058402017-02-14 18:26:20 -0500557}
Nicolas Penaa4ad01f2017-02-15 16:26:48 -0500558
559TEST_F(FPDFEditEmbeddertest, DoubleGenerating) {
560 // Start with a blank page
Nicolas Penad03ca422017-03-06 13:54:33 -0500561 FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
Nicolas Penaa4ad01f2017-02-15 16:26:48 -0500562
563 // Add a red rectangle with some non-default alpha
564 FPDF_PAGEOBJECT rect = FPDFPageObj_CreateNewRect(10, 10, 100, 100);
565 EXPECT_TRUE(FPDFPath_SetFillColor(rect, 255, 0, 0, 128));
566 EXPECT_TRUE(FPDFPath_SetDrawMode(rect, FPDF_FILLMODE_WINDING, 0));
567 FPDFPage_InsertObject(page, rect);
568 EXPECT_TRUE(FPDFPage_GenerateContent(page));
569
570 // Check the ExtGState
571 CPDF_Page* the_page = CPDFPageFromFPDFPage(page);
572 CPDF_Dictionary* graphics_dict =
573 the_page->m_pResources->GetDictFor("ExtGState");
574 ASSERT_TRUE(graphics_dict);
575 EXPECT_EQ(1, static_cast<int>(graphics_dict->GetCount()));
576
577 // Check the bitmap
578 FPDF_BITMAP page_bitmap = RenderPage(page);
579 CompareBitmap(page_bitmap, 612, 792, "5384da3406d62360ffb5cac4476fff1c");
580 FPDFBitmap_Destroy(page_bitmap);
581
582 // Never mind, my new favorite color is blue, increase alpha
583 EXPECT_TRUE(FPDFPath_SetFillColor(rect, 0, 0, 255, 180));
584 EXPECT_TRUE(FPDFPage_GenerateContent(page));
585 EXPECT_EQ(2, static_cast<int>(graphics_dict->GetCount()));
586
587 // Check that bitmap displays changed content
588 page_bitmap = RenderPage(page);
589 CompareBitmap(page_bitmap, 612, 792, "2e51656f5073b0bee611d9cd086aa09c");
590 FPDFBitmap_Destroy(page_bitmap);
591
592 // And now generate, without changes
593 EXPECT_TRUE(FPDFPage_GenerateContent(page));
594 EXPECT_EQ(2, static_cast<int>(graphics_dict->GetCount()));
595 page_bitmap = RenderPage(page);
596 CompareBitmap(page_bitmap, 612, 792, "2e51656f5073b0bee611d9cd086aa09c");
597 FPDFBitmap_Destroy(page_bitmap);
598
599 // Add some text to the page
Nicolas Penab3161852017-05-02 14:12:50 -0400600 FPDF_PAGEOBJECT text_object =
601 FPDFPageObj_NewTextObj(document(), "Arial", 12.0f);
602 std::unique_ptr<unsigned short, pdfium::FreeDeleter> text =
603 GetFPDFWideString(L"Something something #text# something");
604 EXPECT_TRUE(FPDFText_SetText(text_object, text.get()));
605 FPDFPageObj_Transform(text_object, 1, 0, 0, 1, 300, 300);
606 FPDFPage_InsertObject(page, text_object);
Nicolas Penaa4ad01f2017-02-15 16:26:48 -0500607 EXPECT_TRUE(FPDFPage_GenerateContent(page));
608 CPDF_Dictionary* font_dict = the_page->m_pResources->GetDictFor("Font");
609 ASSERT_TRUE(font_dict);
610 EXPECT_EQ(1, static_cast<int>(font_dict->GetCount()));
611
612 // Generate yet again, check dicts are reasonably sized
613 EXPECT_TRUE(FPDFPage_GenerateContent(page));
614 EXPECT_EQ(2, static_cast<int>(graphics_dict->GetCount()));
615 EXPECT_EQ(1, static_cast<int>(font_dict->GetCount()));
616 FPDF_ClosePage(page);
Nicolas Penaa4ad01f2017-02-15 16:26:48 -0500617}
Nicolas Penabe90aae2017-02-27 10:41:41 -0500618
Nicolas Penad03ca422017-03-06 13:54:33 -0500619TEST_F(FPDFEditEmbeddertest, LoadSimpleType1Font) {
620 CreateNewDocument();
621 // TODO(npm): use other fonts after disallowing loading any font as any type
622 const CPDF_Font* stock_font =
623 CPDF_Font::GetStockFont(cpdf_doc(), "Times-Bold");
Lei Zhangd74da7b2017-05-04 13:30:29 -0700624 const uint8_t* data = stock_font->GetFont()->GetFontData();
625 const uint32_t size = stock_font->GetFont()->GetSize();
Nicolas Penab3161852017-05-02 14:12:50 -0400626 std::unique_ptr<void, FPDFFontDeleter> font(
627 FPDFText_LoadFont(document(), data, size, FPDF_FONT_TYPE1, false));
628 ASSERT_TRUE(font.get());
Nicolas Pena46abb662017-05-17 17:23:22 -0400629 CPDF_Font* typed_font = static_cast<CPDF_Font*>(font.get());
Nicolas Penad03ca422017-03-06 13:54:33 -0500630 EXPECT_TRUE(typed_font->IsType1Font());
Nicolas Penabe90aae2017-02-27 10:41:41 -0500631
Nicolas Penad03ca422017-03-06 13:54:33 -0500632 CPDF_Dictionary* font_dict = typed_font->GetFontDict();
Nicolas Penabe90aae2017-02-27 10:41:41 -0500633 EXPECT_EQ("Font", font_dict->GetStringFor("Type"));
634 EXPECT_EQ("Type1", font_dict->GetStringFor("Subtype"));
635 EXPECT_EQ("Times New Roman Bold", font_dict->GetStringFor("BaseFont"));
636 ASSERT_TRUE(font_dict->KeyExist("FirstChar"));
637 ASSERT_TRUE(font_dict->KeyExist("LastChar"));
638 EXPECT_EQ(32, font_dict->GetIntegerFor("FirstChar"));
Nicolas Penad03ca422017-03-06 13:54:33 -0500639 EXPECT_EQ(255, font_dict->GetIntegerFor("LastChar"));
640
Nicolas Penabe90aae2017-02-27 10:41:41 -0500641 CPDF_Array* widths_array = font_dict->GetArrayFor("Widths");
Nicolas Penad03ca422017-03-06 13:54:33 -0500642 ASSERT_TRUE(widths_array);
643 ASSERT_EQ(224U, widths_array->GetCount());
Nicolas Penabe90aae2017-02-27 10:41:41 -0500644 EXPECT_EQ(250, widths_array->GetNumberAt(0));
Nicolas Penad03ca422017-03-06 13:54:33 -0500645 EXPECT_EQ(569, widths_array->GetNumberAt(11));
646 EXPECT_EQ(500, widths_array->GetNumberAt(223));
647 CheckFontDescriptor(font_dict, FPDF_FONT_TYPE1, true, false, size, data);
648}
Nicolas Penabe90aae2017-02-27 10:41:41 -0500649
Nicolas Penad03ca422017-03-06 13:54:33 -0500650TEST_F(FPDFEditEmbeddertest, LoadSimpleTrueTypeFont) {
651 CreateNewDocument();
652 const CPDF_Font* stock_font = CPDF_Font::GetStockFont(cpdf_doc(), "Courier");
Lei Zhangd74da7b2017-05-04 13:30:29 -0700653 const uint8_t* data = stock_font->GetFont()->GetFontData();
654 const uint32_t size = stock_font->GetFont()->GetSize();
Nicolas Penab3161852017-05-02 14:12:50 -0400655 std::unique_ptr<void, FPDFFontDeleter> font(
656 FPDFText_LoadFont(document(), data, size, FPDF_FONT_TRUETYPE, false));
657 ASSERT_TRUE(font.get());
Nicolas Pena46abb662017-05-17 17:23:22 -0400658 CPDF_Font* typed_font = static_cast<CPDF_Font*>(font.get());
Nicolas Penad03ca422017-03-06 13:54:33 -0500659 EXPECT_TRUE(typed_font->IsTrueTypeFont());
Nicolas Penabe90aae2017-02-27 10:41:41 -0500660
Nicolas Penad03ca422017-03-06 13:54:33 -0500661 CPDF_Dictionary* font_dict = typed_font->GetFontDict();
662 EXPECT_EQ("Font", font_dict->GetStringFor("Type"));
663 EXPECT_EQ("TrueType", font_dict->GetStringFor("Subtype"));
664 EXPECT_EQ("Courier New", font_dict->GetStringFor("BaseFont"));
665 ASSERT_TRUE(font_dict->KeyExist("FirstChar"));
666 ASSERT_TRUE(font_dict->KeyExist("LastChar"));
667 EXPECT_EQ(32, font_dict->GetIntegerFor("FirstChar"));
668 EXPECT_EQ(255, font_dict->GetIntegerFor("LastChar"));
Nicolas Penabe90aae2017-02-27 10:41:41 -0500669
Nicolas Penad03ca422017-03-06 13:54:33 -0500670 CPDF_Array* widths_array = font_dict->GetArrayFor("Widths");
671 ASSERT_TRUE(widths_array);
672 ASSERT_EQ(224U, widths_array->GetCount());
673 EXPECT_EQ(600, widths_array->GetNumberAt(33));
674 EXPECT_EQ(600, widths_array->GetNumberAt(74));
675 EXPECT_EQ(600, widths_array->GetNumberAt(223));
676 CheckFontDescriptor(font_dict, FPDF_FONT_TRUETYPE, false, false, size, data);
677}
678
679TEST_F(FPDFEditEmbeddertest, LoadCIDType0Font) {
680 CreateNewDocument();
681 const CPDF_Font* stock_font =
682 CPDF_Font::GetStockFont(cpdf_doc(), "Times-Roman");
Lei Zhangd74da7b2017-05-04 13:30:29 -0700683 const uint8_t* data = stock_font->GetFont()->GetFontData();
684 const uint32_t size = stock_font->GetFont()->GetSize();
Nicolas Penab3161852017-05-02 14:12:50 -0400685 std::unique_ptr<void, FPDFFontDeleter> font(
686 FPDFText_LoadFont(document(), data, size, FPDF_FONT_TYPE1, 1));
687 ASSERT_TRUE(font.get());
Nicolas Pena46abb662017-05-17 17:23:22 -0400688 CPDF_Font* typed_font = static_cast<CPDF_Font*>(font.get());
Nicolas Penad03ca422017-03-06 13:54:33 -0500689 EXPECT_TRUE(typed_font->IsCIDFont());
690
691 // Check font dictionary entries
692 CPDF_Dictionary* font_dict = typed_font->GetFontDict();
693 EXPECT_EQ("Font", font_dict->GetStringFor("Type"));
694 EXPECT_EQ("Type0", font_dict->GetStringFor("Subtype"));
695 EXPECT_EQ("Times New Roman-Identity-H", font_dict->GetStringFor("BaseFont"));
696 EXPECT_EQ("Identity-H", font_dict->GetStringFor("Encoding"));
697 CPDF_Array* descendant_array = font_dict->GetArrayFor("DescendantFonts");
698 ASSERT_TRUE(descendant_array);
699 EXPECT_EQ(1U, descendant_array->GetCount());
700
701 // Check the CIDFontDict
702 CPDF_Dictionary* cidfont_dict = descendant_array->GetDictAt(0);
703 EXPECT_EQ("Font", cidfont_dict->GetStringFor("Type"));
704 EXPECT_EQ("CIDFontType0", cidfont_dict->GetStringFor("Subtype"));
705 EXPECT_EQ("Times New Roman", cidfont_dict->GetStringFor("BaseFont"));
706 CPDF_Dictionary* cidinfo_dict = cidfont_dict->GetDictFor("CIDSystemInfo");
707 ASSERT_TRUE(cidinfo_dict);
708 EXPECT_EQ("Adobe", cidinfo_dict->GetStringFor("Registry"));
709 EXPECT_EQ("Identity", cidinfo_dict->GetStringFor("Ordering"));
710 EXPECT_EQ(0, cidinfo_dict->GetNumberFor("Supplement"));
711 CheckFontDescriptor(cidfont_dict, FPDF_FONT_TYPE1, false, false, size, data);
712
713 // Check widths
714 CPDF_Array* widths_array = cidfont_dict->GetArrayFor("W");
715 ASSERT_TRUE(widths_array);
Nicolas Penaf45ade32017-05-03 10:23:49 -0400716 EXPECT_GT(widths_array->GetCount(), 1U);
Nicolas Penad03ca422017-03-06 13:54:33 -0500717 CheckCompositeFontWidths(widths_array, typed_font);
718}
719
720TEST_F(FPDFEditEmbeddertest, LoadCIDType2Font) {
721 CreateNewDocument();
722 const CPDF_Font* stock_font =
723 CPDF_Font::GetStockFont(cpdf_doc(), "Helvetica-Oblique");
Lei Zhangd74da7b2017-05-04 13:30:29 -0700724 const uint8_t* data = stock_font->GetFont()->GetFontData();
725 const uint32_t size = stock_font->GetFont()->GetSize();
Nicolas Penad03ca422017-03-06 13:54:33 -0500726
Nicolas Penab3161852017-05-02 14:12:50 -0400727 std::unique_ptr<void, FPDFFontDeleter> font(
728 FPDFText_LoadFont(document(), data, size, FPDF_FONT_TRUETYPE, 1));
729 ASSERT_TRUE(font.get());
Nicolas Pena46abb662017-05-17 17:23:22 -0400730 CPDF_Font* typed_font = static_cast<CPDF_Font*>(font.get());
Nicolas Penad03ca422017-03-06 13:54:33 -0500731 EXPECT_TRUE(typed_font->IsCIDFont());
732
733 // Check font dictionary entries
734 CPDF_Dictionary* font_dict = typed_font->GetFontDict();
735 EXPECT_EQ("Font", font_dict->GetStringFor("Type"));
736 EXPECT_EQ("Type0", font_dict->GetStringFor("Subtype"));
737 EXPECT_EQ("Arial Italic", font_dict->GetStringFor("BaseFont"));
738 EXPECT_EQ("Identity-H", font_dict->GetStringFor("Encoding"));
739 CPDF_Array* descendant_array = font_dict->GetArrayFor("DescendantFonts");
740 ASSERT_TRUE(descendant_array);
741 EXPECT_EQ(1U, descendant_array->GetCount());
742
743 // Check the CIDFontDict
744 CPDF_Dictionary* cidfont_dict = descendant_array->GetDictAt(0);
745 EXPECT_EQ("Font", cidfont_dict->GetStringFor("Type"));
746 EXPECT_EQ("CIDFontType2", cidfont_dict->GetStringFor("Subtype"));
747 EXPECT_EQ("Arial Italic", cidfont_dict->GetStringFor("BaseFont"));
748 CPDF_Dictionary* cidinfo_dict = cidfont_dict->GetDictFor("CIDSystemInfo");
749 ASSERT_TRUE(cidinfo_dict);
750 EXPECT_EQ("Adobe", cidinfo_dict->GetStringFor("Registry"));
751 EXPECT_EQ("Identity", cidinfo_dict->GetStringFor("Ordering"));
752 EXPECT_EQ(0, cidinfo_dict->GetNumberFor("Supplement"));
753 CheckFontDescriptor(cidfont_dict, FPDF_FONT_TRUETYPE, false, true, size,
754 data);
755
756 // Check widths
757 CPDF_Array* widths_array = cidfont_dict->GetArrayFor("W");
758 ASSERT_TRUE(widths_array);
759 CheckCompositeFontWidths(widths_array, typed_font);
Nicolas Penabe90aae2017-02-27 10:41:41 -0500760}
rbpotterce8e51e2017-04-28 12:42:47 -0700761
762TEST_F(FPDFEditEmbeddertest, NormalizeNegativeRotation) {
763 // Load document with a -90 degree rotation
764 EXPECT_TRUE(OpenDocument("bug_713197.pdf"));
765 FPDF_PAGE page = LoadPage(0);
766 EXPECT_NE(nullptr, page);
767
768 EXPECT_EQ(3, FPDFPage_GetRotation(page));
769 UnloadPage(page);
770}
Nicolas Penab3161852017-05-02 14:12:50 -0400771
772TEST_F(FPDFEditEmbeddertest, AddTrueTypeFontText) {
773 // Start with a blank page
774 FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
775 {
776 const CPDF_Font* stock_font = CPDF_Font::GetStockFont(cpdf_doc(), "Arial");
Lei Zhangd74da7b2017-05-04 13:30:29 -0700777 const uint8_t* data = stock_font->GetFont()->GetFontData();
778 const uint32_t size = stock_font->GetFont()->GetSize();
Nicolas Penab3161852017-05-02 14:12:50 -0400779 std::unique_ptr<void, FPDFFontDeleter> font(
780 FPDFText_LoadFont(document(), data, size, FPDF_FONT_TRUETYPE, 0));
781 ASSERT_TRUE(font.get());
782
783 // Add some text to the page
784 FPDF_PAGEOBJECT text_object =
785 FPDFPageObj_CreateTextObj(document(), font.get(), 12.0f);
786 EXPECT_TRUE(text_object);
787 std::unique_ptr<unsigned short, pdfium::FreeDeleter> text =
788 GetFPDFWideString(L"I am testing my loaded font, WEE.");
789 EXPECT_TRUE(FPDFText_SetText(text_object, text.get()));
790 FPDFPageObj_Transform(text_object, 1, 0, 0, 1, 400, 400);
791 FPDFPage_InsertObject(page, text_object);
Nicolas Penab3161852017-05-02 14:12:50 -0400792 FPDF_BITMAP page_bitmap = RenderPage(page);
793#if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
794 const char md5[] = "17d2b6cd574cf66170b09c8927529a94";
795#else
796 const char md5[] = "28e5b10743660dcdfd1618db47b39d32";
797#endif // _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
798 CompareBitmap(page_bitmap, 612, 792, md5);
799 FPDFBitmap_Destroy(page_bitmap);
800
801 // Add some more text, same font
802 FPDF_PAGEOBJECT text_object2 =
803 FPDFPageObj_CreateTextObj(document(), font.get(), 15.0f);
804 std::unique_ptr<unsigned short, pdfium::FreeDeleter> text2 =
805 GetFPDFWideString(L"Bigger font size");
806 EXPECT_TRUE(FPDFText_SetText(text_object2, text2.get()));
807 FPDFPageObj_Transform(text_object2, 1, 0, 0, 1, 200, 200);
808 FPDFPage_InsertObject(page, text_object2);
Nicolas Penab3161852017-05-02 14:12:50 -0400809 }
810 FPDF_BITMAP page_bitmap2 = RenderPage(page);
811#if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
812 const char md5_2[] = "8eded4193ff1f0f77b8b600a825e97ea";
813#else
814 const char md5_2[] = "a068eef4110d607f77c87ea8340fa2a5";
815#endif // _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
816 CompareBitmap(page_bitmap2, 612, 792, md5_2);
817 FPDFBitmap_Destroy(page_bitmap2);
818
Nicolas Pena207b7272017-05-26 17:37:06 -0400819 EXPECT_TRUE(FPDFPage_GenerateContent(page));
Nicolas Penab3161852017-05-02 14:12:50 -0400820 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
821 FPDF_ClosePage(page);
822 std::string new_file = GetString();
823
824 // Render the saved result
825 FPDF_FILEACCESS file_access;
826 memset(&file_access, 0, sizeof(file_access));
827 file_access.m_FileLen = new_file.size();
828 file_access.m_GetBlock = GetBlockFromString;
829 file_access.m_Param = &new_file;
830 FPDF_DOCUMENT new_doc = FPDF_LoadCustomDocument(&file_access, nullptr);
831 ASSERT_NE(nullptr, new_doc);
832 EXPECT_EQ(1, FPDF_GetPageCount(new_doc));
833 FPDF_PAGE new_page = FPDF_LoadPage(new_doc, 0);
834 ASSERT_NE(nullptr, new_page);
835 FPDF_BITMAP new_bitmap = RenderPage(new_page);
836 CompareBitmap(new_bitmap, 612, 792, md5_2);
837 FPDFBitmap_Destroy(new_bitmap);
838 FPDF_ClosePage(new_page);
839 FPDF_CloseDocument(new_doc);
840}
Nicolas Penaf45ade32017-05-03 10:23:49 -0400841
Jane Liueda65252017-06-07 11:31:27 -0400842TEST_F(FPDFEditEmbeddertest, TransformAnnot) {
843 // Open a file with one annotation and load its first page.
844 ASSERT_TRUE(OpenDocument("annotation_highlight_long_content.pdf"));
845 FPDF_PAGE page = FPDF_LoadPage(document(), 0);
846 ASSERT_TRUE(page);
847
848 // Add an underline annotation to the page without specifying its rectangle.
849 FPDF_ANNOTATION annot;
850 ASSERT_TRUE(FPDFPage_CreateAnnot(page, FPDF_ANNOT_UNDERLINE, &annot));
851
852 // FPDFPage_TransformAnnots() should run without errors when modifying
853 // annotation rectangles.
854 FPDFPage_TransformAnnots(page, 1, 2, 3, 4, 5, 6);
855
856 UnloadPage(page);
857}
858
Nicolas Penaf45ade32017-05-03 10:23:49 -0400859// TODO(npm): Add tests using Japanese fonts in other OS.
860#if _FXM_PLATFORM_ == _FXM_PLATFORM_LINUX_
861TEST_F(FPDFEditEmbeddertest, AddCIDFontText) {
862 // Start with a blank page
863 FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
864 CFX_Font CIDfont;
865 {
866 // First, get the data from the font
867 CIDfont.LoadSubst("IPAGothic", 1, 0, 400, 0, 932, 0);
868 EXPECT_EQ("IPAGothic", CIDfont.GetFaceName());
869 const uint8_t* data = CIDfont.GetFontData();
870 const uint32_t size = CIDfont.GetSize();
871
872 // Load the data into a FPDF_Font.
873 std::unique_ptr<void, FPDFFontDeleter> font(
874 FPDFText_LoadFont(document(), data, size, FPDF_FONT_TRUETYPE, 1));
875 ASSERT_TRUE(font.get());
876
877 // Add some text to the page
878 FPDF_PAGEOBJECT text_object =
879 FPDFPageObj_CreateTextObj(document(), font.get(), 12.0f);
880 ASSERT_TRUE(text_object);
881 std::wstring wstr = L"ABCDEFGhijklmnop.";
882 std::unique_ptr<unsigned short, pdfium::FreeDeleter> text =
883 GetFPDFWideString(wstr);
884 EXPECT_TRUE(FPDFText_SetText(text_object, text.get()));
885 FPDFPageObj_Transform(text_object, 1, 0, 0, 1, 200, 200);
886 FPDFPage_InsertObject(page, text_object);
887
888 // And add some Japanese characters
889 FPDF_PAGEOBJECT text_object2 =
890 FPDFPageObj_CreateTextObj(document(), font.get(), 18.0f);
891 ASSERT_TRUE(text_object2);
892 std::wstring wstr2 =
893 L"\u3053\u3093\u306B\u3061\u306f\u4e16\u754C\u3002\u3053\u3053\u306B1"
894 L"\u756A";
895 std::unique_ptr<unsigned short, pdfium::FreeDeleter> text2 =
896 GetFPDFWideString(wstr2);
897 EXPECT_TRUE(FPDFText_SetText(text_object2, text2.get()));
898 FPDFPageObj_Transform(text_object2, 1, 0, 0, 1, 100, 500);
899 FPDFPage_InsertObject(page, text_object2);
900 }
901
Nicolas Pena207b7272017-05-26 17:37:06 -0400902 // Check that the text renders properly.
Nicolas Penaf45ade32017-05-03 10:23:49 -0400903 FPDF_BITMAP page_bitmap = RenderPage(page);
904 const char md5[] = "2bc6c1aaa2252e73246a75775ccf38c2";
905 CompareBitmap(page_bitmap, 612, 792, md5);
906 FPDFBitmap_Destroy(page_bitmap);
907
908 // Save the document, close the page.
Nicolas Pena207b7272017-05-26 17:37:06 -0400909 EXPECT_TRUE(FPDFPage_GenerateContent(page));
Nicolas Penaf45ade32017-05-03 10:23:49 -0400910 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
911 FPDF_ClosePage(page);
912 std::string new_file = GetString();
913
914 // Render the saved result
915 FPDF_FILEACCESS file_access;
916 memset(&file_access, 0, sizeof(file_access));
917 file_access.m_FileLen = new_file.size();
918 file_access.m_GetBlock = GetBlockFromString;
919 file_access.m_Param = &new_file;
920 FPDF_DOCUMENT new_doc = FPDF_LoadCustomDocument(&file_access, nullptr);
921 ASSERT_NE(nullptr, new_doc);
922 EXPECT_EQ(1, FPDF_GetPageCount(new_doc));
923 FPDF_PAGE new_page = FPDF_LoadPage(new_doc, 0);
924 ASSERT_NE(nullptr, new_page);
925 FPDF_BITMAP new_bitmap = RenderPage(new_page);
926 CompareBitmap(new_bitmap, 612, 792, md5);
927 FPDFBitmap_Destroy(new_bitmap);
928 FPDF_ClosePage(new_page);
929 FPDF_CloseDocument(new_doc);
930}
931#endif // _FXM_PLATFORM_ == _FXM_PLATFORM_LINUX_