blob: f52848c81dedab448612589f64ea888be0d595bc [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"
Tom Sepezd483eb42016-01-06 10:03:59 -080018#include "public/fpdf_edit.h"
19#include "public/fpdfview.h"
20#include "testing/embedder_test.h"
Tom Sepez0aec19b2016-01-07 12:22:44 -080021#include "testing/gmock/include/gmock/gmock-matchers.h"
Tom Sepezd483eb42016-01-06 10:03:59 -080022#include "testing/gtest/include/gtest/gtest.h"
Tom Sepez0aec19b2016-01-07 12:22:44 -080023#include "testing/test_support.h"
Tom Sepezd483eb42016-01-06 10:03:59 -080024
Nicolas Penad03ca422017-03-06 13:54:33 -050025class FPDFEditEmbeddertest : public EmbedderTest, public TestSaver {
26 protected:
27 FPDF_DOCUMENT CreateNewDocument() {
28 document_ = FPDF_CreateNewDocument();
Tom Sepez41066c12017-05-18 09:28:49 -070029 cpdf_doc_ = CPDFDocumentFromFPDFDocument(document_);
Nicolas Penad03ca422017-03-06 13:54:33 -050030 return document_;
31 }
32
33 void CheckFontDescriptor(CPDF_Dictionary* font_dict,
34 int font_type,
35 bool bold,
36 bool italic,
37 uint32_t size,
38 const uint8_t* data) {
39 CPDF_Dictionary* font_desc = font_dict->GetDictFor("FontDescriptor");
40 ASSERT_TRUE(font_desc);
41 EXPECT_EQ("FontDescriptor", font_desc->GetStringFor("Type"));
42 EXPECT_EQ(font_dict->GetStringFor("BaseFont"),
43 font_desc->GetStringFor("FontName"));
44
45 // Check that the font descriptor has the required keys according to spec
46 // 1.7 Table 5.19
47 ASSERT_TRUE(font_desc->KeyExist("Flags"));
48 int font_flags = font_desc->GetIntegerFor("Flags");
49 if (bold)
50 EXPECT_TRUE(font_flags & FXFONT_BOLD);
51 else
52 EXPECT_FALSE(font_flags & FXFONT_BOLD);
53 if (italic)
54 EXPECT_TRUE(font_flags & FXFONT_ITALIC);
55 else
56 EXPECT_FALSE(font_flags & FXFONT_ITALIC);
57 EXPECT_TRUE(font_flags & FXFONT_NONSYMBOLIC);
58 ASSERT_TRUE(font_desc->KeyExist("FontBBox"));
59 EXPECT_EQ(4U, font_desc->GetArrayFor("FontBBox")->GetCount());
60 EXPECT_TRUE(font_desc->KeyExist("ItalicAngle"));
61 EXPECT_TRUE(font_desc->KeyExist("Ascent"));
62 EXPECT_TRUE(font_desc->KeyExist("Descent"));
63 EXPECT_TRUE(font_desc->KeyExist("CapHeight"));
64 EXPECT_TRUE(font_desc->KeyExist("StemV"));
65 CFX_ByteString present("FontFile");
66 CFX_ByteString absent("FontFile2");
67 if (font_type == FPDF_FONT_TRUETYPE)
68 std::swap(present, absent);
69 EXPECT_TRUE(font_desc->KeyExist(present));
70 EXPECT_FALSE(font_desc->KeyExist(absent));
71
72 // Check that the font stream is the one that was provided
73 CPDF_Stream* font_stream = font_desc->GetStreamFor(present);
74 ASSERT_EQ(size, font_stream->GetRawSize());
75 uint8_t* stream_data = font_stream->GetRawData();
76 for (size_t j = 0; j < size; j++)
77 EXPECT_EQ(data[j], stream_data[j]) << " at byte " << j;
78 }
79
80 void CheckCompositeFontWidths(CPDF_Array* widths_array,
81 CPDF_Font* typed_font) {
82 // Check that W array is in a format that conforms to PDF spec 1.7 section
83 // "Glyph Metrics in CIDFonts" (these checks are not
84 // implementation-specific).
85 EXPECT_GT(widths_array->GetCount(), 1U);
86 int num_cids_checked = 0;
87 int cur_cid = 0;
88 for (size_t idx = 0; idx < widths_array->GetCount(); idx++) {
89 int cid = widths_array->GetNumberAt(idx);
90 EXPECT_GE(cid, cur_cid);
91 ASSERT_FALSE(++idx == widths_array->GetCount());
92 CPDF_Object* next = widths_array->GetObjectAt(idx);
93 if (next->IsArray()) {
94 // We are in the c [w1 w2 ...] case
95 CPDF_Array* arr = next->AsArray();
96 int cnt = static_cast<int>(arr->GetCount());
97 size_t inner_idx = 0;
98 for (cur_cid = cid; cur_cid < cid + cnt; cur_cid++) {
99 int width = arr->GetNumberAt(inner_idx++);
100 EXPECT_EQ(width, typed_font->GetCharWidthF(cur_cid)) << " at cid "
101 << cur_cid;
102 }
103 num_cids_checked += cnt;
104 continue;
105 }
106 // Otherwise, are in the c_first c_last w case.
107 ASSERT_TRUE(next->IsNumber());
108 int last_cid = next->AsNumber()->GetInteger();
109 ASSERT_FALSE(++idx == widths_array->GetCount());
110 int width = widths_array->GetNumberAt(idx);
111 for (cur_cid = cid; cur_cid <= last_cid; cur_cid++) {
112 EXPECT_EQ(width, typed_font->GetCharWidthF(cur_cid)) << " at cid "
113 << cur_cid;
114 }
115 num_cids_checked += last_cid - cid + 1;
116 }
117 // Make sure we have a good amount of cids described
118 EXPECT_GT(num_cids_checked, 900);
119 }
120 CPDF_Document* cpdf_doc() { return cpdf_doc_; }
121
122 private:
123 CPDF_Document* cpdf_doc_;
124};
Tom Sepezd483eb42016-01-06 10:03:59 -0800125
etienneb7712c262016-04-26 08:13:45 -0700126namespace {
thestigdc7ec032016-11-21 15:32:52 -0800127
etienneb7712c262016-04-26 08:13:45 -0700128const char kExpectedPDF[] =
129 "%PDF-1.7\r\n"
130 "%\xA1\xB3\xC5\xD7\r\n"
131 "1 0 obj\r\n"
132 "<</Pages 2 0 R /Type/Catalog>>\r\n"
133 "endobj\r\n"
134 "2 0 obj\r\n"
135 "<</Count 1/Kids\\[ 4 0 R \\]/Type/Pages>>\r\n"
136 "endobj\r\n"
137 "3 0 obj\r\n"
138 "<</CreationDate\\(D:.*\\)/Creator\\(PDFium\\)>>\r\n"
139 "endobj\r\n"
140 "4 0 obj\r\n"
141 "<</Contents 5 0 R /MediaBox\\[ 0 0 640 480\\]"
142 "/Parent 2 0 R /Resources<<>>/Rotate 0/Type/Page"
143 ">>\r\n"
144 "endobj\r\n"
145 "5 0 obj\r\n"
146 "<</Filter/FlateDecode/Length 8>>stream\r\n"
147 // Character '_' is matching '\0' (see comment below).
148 "x\x9C\x3____\x1\r\n"
149 "endstream\r\n"
150 "endobj\r\n"
151 "xref\r\n"
152 "0 6\r\n"
153 "0000000000 65535 f\r\n"
154 "0000000017 00000 n\r\n"
155 "0000000066 00000 n\r\n"
156 "0000000122 00000 n\r\n"
157 "0000000192 00000 n\r\n"
158 "0000000301 00000 n\r\n"
159 "trailer\r\n"
160 "<<\r\n"
161 "/Root 1 0 R\r\n"
162 "/Info 3 0 R\r\n"
163 "/Size 6/ID\\[<.*><.*>\\]>>\r\n"
164 "startxref\r\n"
165 "379\r\n"
166 "%%EOF\r\n";
thestigdc7ec032016-11-21 15:32:52 -0800167
etienneb7712c262016-04-26 08:13:45 -0700168} // namespace
169
Tom Sepezd483eb42016-01-06 10:03:59 -0800170TEST_F(FPDFEditEmbeddertest, EmptyCreation) {
171 EXPECT_TRUE(CreateEmptyDocument());
weili9b777de2016-08-19 16:19:46 -0700172 FPDF_PAGE page = FPDFPage_New(document(), 0, 640.0, 480.0);
Tom Sepezd483eb42016-01-06 10:03:59 -0800173 EXPECT_NE(nullptr, page);
174 EXPECT_TRUE(FPDFPage_GenerateContent(page));
Tom Sepez0aec19b2016-01-07 12:22:44 -0800175 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
etienneb7712c262016-04-26 08:13:45 -0700176
177 // The MatchesRegexp doesn't support embedded NUL ('\0') characters. They are
178 // replaced by '_' for the purpose of the test.
179 std::string result = GetString();
180 std::replace(result.begin(), result.end(), '\0', '_');
181 EXPECT_THAT(result, testing::MatchesRegex(
182 std::string(kExpectedPDF, sizeof(kExpectedPDF))));
weili9b777de2016-08-19 16:19:46 -0700183 FPDF_ClosePage(page);
Tom Sepezd483eb42016-01-06 10:03:59 -0800184}
thestigdc7ec032016-11-21 15:32:52 -0800185
186// Regression test for https://crbug.com/667012
187TEST_F(FPDFEditEmbeddertest, RasterizePDF) {
188 const char kAllBlackMd5sum[] = "5708fc5c4a8bd0abde99c8e8f0390615";
189
190 // Get the bitmap for the original document/
191 FPDF_BITMAP orig_bitmap;
192 {
193 EXPECT_TRUE(OpenDocument("black.pdf"));
194 FPDF_PAGE orig_page = LoadPage(0);
195 EXPECT_NE(nullptr, orig_page);
196 orig_bitmap = RenderPage(orig_page);
197 CompareBitmap(orig_bitmap, 612, 792, kAllBlackMd5sum);
198 UnloadPage(orig_page);
199 }
200
201 // Create a new document from |orig_bitmap| and save it.
202 {
203 FPDF_DOCUMENT temp_doc = FPDF_CreateNewDocument();
204 FPDF_PAGE temp_page = FPDFPage_New(temp_doc, 0, 612, 792);
205
206 // Add the bitmap to an image object and add the image object to the output
207 // page.
Lei Zhangcbd89572017-03-15 17:35:47 -0700208 FPDF_PAGEOBJECT temp_img = FPDFPageObj_NewImageObj(temp_doc);
thestigdc7ec032016-11-21 15:32:52 -0800209 EXPECT_TRUE(FPDFImageObj_SetBitmap(&temp_page, 1, temp_img, orig_bitmap));
210 EXPECT_TRUE(FPDFImageObj_SetMatrix(temp_img, 612, 0, 0, 792, 0, 0));
211 FPDFPage_InsertObject(temp_page, temp_img);
212 EXPECT_TRUE(FPDFPage_GenerateContent(temp_page));
213 EXPECT_TRUE(FPDF_SaveAsCopy(temp_doc, this, 0));
214 FPDF_ClosePage(temp_page);
215 FPDF_CloseDocument(temp_doc);
216 }
217 FPDFBitmap_Destroy(orig_bitmap);
218
219 // Get the generated content. Make sure it is at least as big as the original
220 // PDF.
221 std::string new_file = GetString();
222 EXPECT_GT(new_file.size(), 923U);
223
224 // Read |new_file| in, and verify its rendered bitmap.
225 {
226 FPDF_FILEACCESS file_access;
227 memset(&file_access, 0, sizeof(file_access));
228 file_access.m_FileLen = new_file.size();
229 file_access.m_GetBlock = GetBlockFromString;
230 file_access.m_Param = &new_file;
231
232 FPDF_DOCUMENT new_doc = FPDF_LoadCustomDocument(&file_access, nullptr);
233 EXPECT_EQ(1, FPDF_GetPageCount(document_));
234 FPDF_PAGE new_page = FPDF_LoadPage(new_doc, 0);
235 EXPECT_NE(nullptr, new_page);
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500236 FPDF_BITMAP new_bitmap = RenderPage(new_page);
thestigdc7ec032016-11-21 15:32:52 -0800237 CompareBitmap(new_bitmap, 612, 792, kAllBlackMd5sum);
238 FPDF_ClosePage(new_page);
239 FPDF_CloseDocument(new_doc);
240 FPDFBitmap_Destroy(new_bitmap);
241 }
242}
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500243
244TEST_F(FPDFEditEmbeddertest, AddPaths) {
245 // Start with a blank page
Nicolas Penad03ca422017-03-06 13:54:33 -0500246 FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500247
248 // We will first add a red rectangle
249 FPDF_PAGEOBJECT red_rect = FPDFPageObj_CreateNewRect(10, 10, 20, 20);
250 ASSERT_NE(nullptr, red_rect);
251 // Expect false when trying to set colors out of range
252 EXPECT_FALSE(FPDFPath_SetStrokeColor(red_rect, 100, 100, 100, 300));
253 EXPECT_FALSE(FPDFPath_SetFillColor(red_rect, 200, 256, 200, 0));
254
255 // Fill rectangle with red and insert to the page
256 EXPECT_TRUE(FPDFPath_SetFillColor(red_rect, 255, 0, 0, 255));
257 EXPECT_TRUE(FPDFPath_SetDrawMode(red_rect, FPDF_FILLMODE_ALTERNATE, 0));
258 FPDFPage_InsertObject(page, red_rect);
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500259 FPDF_BITMAP page_bitmap = RenderPage(page);
260 CompareBitmap(page_bitmap, 612, 792, "66d02eaa6181e2c069ce2ea99beda497");
261 FPDFBitmap_Destroy(page_bitmap);
262
263 // Now add to that a green rectangle with some medium alpha
264 FPDF_PAGEOBJECT green_rect = FPDFPageObj_CreateNewRect(100, 100, 40, 40);
265 EXPECT_TRUE(FPDFPath_SetFillColor(green_rect, 0, 255, 0, 128));
Miklos Vajnaed4705b2017-04-05 09:24:50 +0200266
Miklos Vajna1ef04c92017-05-08 18:14:19 +0200267 // Make sure the type of the rectangle is a path.
268 EXPECT_EQ(FPDF_PAGEOBJ_PATH, FPDFPageObj_GetType(green_rect));
269
Miklos Vajnaed4705b2017-04-05 09:24:50 +0200270 // Make sure we get back the same color we set previously.
271 unsigned int R;
272 unsigned int G;
273 unsigned int B;
274 unsigned int A;
275 EXPECT_TRUE(FPDFPath_GetFillColor(green_rect, &R, &G, &B, &A));
276 EXPECT_EQ(0U, R);
277 EXPECT_EQ(255U, G);
278 EXPECT_EQ(0U, B);
279 EXPECT_EQ(128U, A);
280
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500281 EXPECT_TRUE(FPDFPath_SetDrawMode(green_rect, FPDF_FILLMODE_WINDING, 0));
282 FPDFPage_InsertObject(page, green_rect);
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500283 page_bitmap = RenderPage(page);
284 CompareBitmap(page_bitmap, 612, 792, "7b0b87604594e773add528fae567a558");
285 FPDFBitmap_Destroy(page_bitmap);
286
287 // Add a black triangle.
288 FPDF_PAGEOBJECT black_path = FPDFPageObj_CreateNewPath(400, 100);
289 EXPECT_TRUE(FPDFPath_SetFillColor(black_path, 0, 0, 0, 200));
290 EXPECT_TRUE(FPDFPath_SetDrawMode(black_path, FPDF_FILLMODE_ALTERNATE, 0));
291 EXPECT_TRUE(FPDFPath_LineTo(black_path, 400, 200));
292 EXPECT_TRUE(FPDFPath_LineTo(black_path, 300, 100));
293 EXPECT_TRUE(FPDFPath_Close(black_path));
294 FPDFPage_InsertObject(page, black_path);
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500295 page_bitmap = RenderPage(page);
296 CompareBitmap(page_bitmap, 612, 792, "eadc8020a14dfcf091da2688733d8806");
297 FPDFBitmap_Destroy(page_bitmap);
298
299 // Now add a more complex blue path.
300 FPDF_PAGEOBJECT blue_path = FPDFPageObj_CreateNewPath(200, 200);
301 EXPECT_TRUE(FPDFPath_SetFillColor(blue_path, 0, 0, 255, 255));
302 EXPECT_TRUE(FPDFPath_SetDrawMode(blue_path, FPDF_FILLMODE_WINDING, 0));
303 EXPECT_TRUE(FPDFPath_LineTo(blue_path, 230, 230));
304 EXPECT_TRUE(FPDFPath_BezierTo(blue_path, 250, 250, 280, 280, 300, 300));
305 EXPECT_TRUE(FPDFPath_LineTo(blue_path, 325, 325));
306 EXPECT_TRUE(FPDFPath_LineTo(blue_path, 350, 325));
307 EXPECT_TRUE(FPDFPath_BezierTo(blue_path, 375, 330, 390, 360, 400, 400));
308 EXPECT_TRUE(FPDFPath_Close(blue_path));
309 FPDFPage_InsertObject(page, blue_path);
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500310 page_bitmap = RenderPage(page);
311 CompareBitmap(page_bitmap, 612, 792, "9823e1a21bd9b72b6a442ba4f12af946");
312 FPDFBitmap_Destroy(page_bitmap);
313
314 // Now save the result, closing the page and document
Nicolas Pena207b7272017-05-26 17:37:06 -0400315 EXPECT_TRUE(FPDFPage_GenerateContent(page));
Nicolas Penad03ca422017-03-06 13:54:33 -0500316 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500317 FPDF_ClosePage(page);
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500318 std::string new_file = GetString();
319
320 // Render the saved result
321 FPDF_FILEACCESS file_access;
322 memset(&file_access, 0, sizeof(file_access));
323 file_access.m_FileLen = new_file.size();
324 file_access.m_GetBlock = GetBlockFromString;
325 file_access.m_Param = &new_file;
326 FPDF_DOCUMENT new_doc = FPDF_LoadCustomDocument(&file_access, nullptr);
327 ASSERT_NE(nullptr, new_doc);
328 EXPECT_EQ(1, FPDF_GetPageCount(new_doc));
329 FPDF_PAGE new_page = FPDF_LoadPage(new_doc, 0);
330 ASSERT_NE(nullptr, new_page);
331 FPDF_BITMAP new_bitmap = RenderPage(new_page);
332 CompareBitmap(new_bitmap, 612, 792, "9823e1a21bd9b72b6a442ba4f12af946");
333 FPDFBitmap_Destroy(new_bitmap);
334 FPDF_ClosePage(new_page);
335 FPDF_CloseDocument(new_doc);
336}
337
338TEST_F(FPDFEditEmbeddertest, PathOnTopOfText) {
339 // Load document with some text
340 EXPECT_TRUE(OpenDocument("hello_world.pdf"));
341 FPDF_PAGE page = LoadPage(0);
342 EXPECT_NE(nullptr, page);
343
344 // Add an opaque rectangle on top of some of the text.
345 FPDF_PAGEOBJECT red_rect = FPDFPageObj_CreateNewRect(20, 100, 50, 50);
346 EXPECT_TRUE(FPDFPath_SetFillColor(red_rect, 255, 0, 0, 255));
347 EXPECT_TRUE(FPDFPath_SetDrawMode(red_rect, FPDF_FILLMODE_ALTERNATE, 0));
348 FPDFPage_InsertObject(page, red_rect);
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500349
350 // Add a transparent triangle on top of other part of the text.
351 FPDF_PAGEOBJECT black_path = FPDFPageObj_CreateNewPath(20, 50);
352 EXPECT_TRUE(FPDFPath_SetFillColor(black_path, 0, 0, 0, 100));
353 EXPECT_TRUE(FPDFPath_SetDrawMode(black_path, FPDF_FILLMODE_ALTERNATE, 0));
354 EXPECT_TRUE(FPDFPath_LineTo(black_path, 30, 80));
355 EXPECT_TRUE(FPDFPath_LineTo(black_path, 40, 10));
356 EXPECT_TRUE(FPDFPath_Close(black_path));
357 FPDFPage_InsertObject(page, black_path);
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500358
359 // Render and check the result. Text is slightly different on Mac.
360 FPDF_BITMAP bitmap = RenderPage(page);
361#if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
Lei Zhang0d6d1782017-03-24 15:52:00 -0700362 const char md5[] = "f9e6fa74230f234286bfcada9f7606d8";
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500363#else
Lei Zhang3de50052017-03-29 21:02:13 -0700364 const char md5[] = "2fdfc5dda29374cfba4349362e38ebdb";
Nicolas Pena5bcd9a32017-03-22 11:04:35 -0400365#endif
Lei Zhang0d6d1782017-03-24 15:52:00 -0700366 CompareBitmap(bitmap, 200, 200, md5);
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500367 FPDFBitmap_Destroy(bitmap);
368 UnloadPage(page);
369}
Nicolas Pena2eb1a702017-02-09 18:17:33 -0500370
wileyryae858aa42017-05-31 14:49:05 -0500371TEST_F(FPDFEditEmbeddertest, EditOverExistingContent) {
372 // Load document with existing content
373 EXPECT_TRUE(OpenDocument("bug_717.pdf"));
374 FPDF_PAGE page = LoadPage(0);
375 EXPECT_NE(nullptr, page);
376
377 // Add a transparent rectangle on top of the existing content
378 FPDF_PAGEOBJECT red_rect2 = FPDFPageObj_CreateNewRect(90, 700, 25, 50);
379 EXPECT_TRUE(FPDFPath_SetFillColor(red_rect2, 255, 0, 0, 100));
380 EXPECT_TRUE(FPDFPath_SetDrawMode(red_rect2, FPDF_FILLMODE_ALTERNATE, 0));
381 FPDFPage_InsertObject(page, red_rect2);
382
383 // Add an opaque rectangle on top of the existing content
384 FPDF_PAGEOBJECT red_rect = FPDFPageObj_CreateNewRect(115, 700, 25, 50);
385 EXPECT_TRUE(FPDFPath_SetFillColor(red_rect, 255, 0, 0, 255));
386 EXPECT_TRUE(FPDFPath_SetDrawMode(red_rect, FPDF_FILLMODE_ALTERNATE, 0));
387 FPDFPage_InsertObject(page, red_rect);
388
389 FPDF_BITMAP bitmap = RenderPage(page);
390 CompareBitmap(bitmap, 612, 792, "ad04e5bd0f471a9a564fb034bd0fb073");
391 FPDFBitmap_Destroy(bitmap);
392 EXPECT_TRUE(FPDFPage_GenerateContent(page));
393
394 // Now save the result, closing the page and document
395 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
396 FPDF_ClosePage(page);
397
398 // Render the saved result
399 std::string new_file = GetString();
400 FPDF_FILEACCESS file_access;
401 memset(&file_access, 0, sizeof(file_access));
402 file_access.m_FileLen = new_file.size();
403 file_access.m_GetBlock = GetBlockFromString;
404 file_access.m_Param = &new_file;
405 FPDF_DOCUMENT new_doc = FPDF_LoadCustomDocument(&file_access, nullptr);
406 ASSERT_NE(nullptr, new_doc);
407 EXPECT_EQ(1, FPDF_GetPageCount(new_doc));
408 FPDF_PAGE new_page = FPDF_LoadPage(new_doc, 0);
409 ASSERT_NE(nullptr, new_page);
410 FPDF_BITMAP new_bitmap = RenderPage(new_page);
411 CompareBitmap(new_bitmap, 612, 792, "ad04e5bd0f471a9a564fb034bd0fb073");
412 FPDFBitmap_Destroy(new_bitmap);
413
414 ClearString();
415 // Add another opaque rectangle on top of the existing content
416 FPDF_PAGEOBJECT green_rect = FPDFPageObj_CreateNewRect(150, 700, 25, 50);
417 EXPECT_TRUE(FPDFPath_SetFillColor(green_rect, 0, 255, 0, 255));
418 EXPECT_TRUE(FPDFPath_SetDrawMode(green_rect, FPDF_FILLMODE_ALTERNATE, 0));
419 FPDFPage_InsertObject(new_page, green_rect);
420
421 // Add another transparent rectangle on top of existing content
422 FPDF_PAGEOBJECT green_rect2 = FPDFPageObj_CreateNewRect(175, 700, 25, 50);
423 EXPECT_TRUE(FPDFPath_SetFillColor(green_rect2, 0, 255, 0, 100));
424 EXPECT_TRUE(FPDFPath_SetDrawMode(green_rect2, FPDF_FILLMODE_ALTERNATE, 0));
425 FPDFPage_InsertObject(new_page, green_rect2);
426 new_bitmap = RenderPage(new_page);
427 CompareBitmap(new_bitmap, 612, 792, "4b5b00f824620f8c9b8801ebb98e1cdd");
428 FPDFBitmap_Destroy(new_bitmap);
429 EXPECT_TRUE(FPDFPage_GenerateContent(new_page));
430
431 // Now save the result, closing the page and document
432 EXPECT_TRUE(FPDF_SaveAsCopy(new_doc, this, 0));
433 FPDF_ClosePage(new_page);
434 FPDF_CloseDocument(new_doc);
435
436 // Render the saved result
437 new_file = GetString();
438 memset(&file_access, 0, sizeof(file_access));
439 file_access.m_FileLen = new_file.size();
440 file_access.m_GetBlock = GetBlockFromString;
441 file_access.m_Param = &new_file;
442 new_doc = FPDF_LoadCustomDocument(&file_access, nullptr);
443 ASSERT_NE(nullptr, new_doc);
444 EXPECT_EQ(1, FPDF_GetPageCount(new_doc));
445 new_page = FPDF_LoadPage(new_doc, 0);
446 ASSERT_NE(nullptr, new_page);
447 new_bitmap = RenderPage(new_page);
448 CompareBitmap(new_bitmap, 612, 792, "4b5b00f824620f8c9b8801ebb98e1cdd");
449 FPDFBitmap_Destroy(new_bitmap);
450
451 FPDF_ClosePage(new_page);
452 FPDF_CloseDocument(new_doc);
453}
454
Nicolas Pena2eb1a702017-02-09 18:17:33 -0500455TEST_F(FPDFEditEmbeddertest, AddStrokedPaths) {
456 // Start with a blank page
Nicolas Penad03ca422017-03-06 13:54:33 -0500457 FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
Nicolas Pena2eb1a702017-02-09 18:17:33 -0500458
459 // Add a large stroked rectangle (fill color should not affect it).
460 FPDF_PAGEOBJECT rect = FPDFPageObj_CreateNewRect(20, 20, 200, 400);
461 EXPECT_TRUE(FPDFPath_SetFillColor(rect, 255, 0, 0, 255));
462 EXPECT_TRUE(FPDFPath_SetStrokeColor(rect, 0, 255, 0, 255));
463 EXPECT_TRUE(FPDFPath_SetStrokeWidth(rect, 15.0f));
464 EXPECT_TRUE(FPDFPath_SetDrawMode(rect, 0, 1));
465 FPDFPage_InsertObject(page, rect);
Nicolas Pena2eb1a702017-02-09 18:17:33 -0500466 FPDF_BITMAP page_bitmap = RenderPage(page);
467 CompareBitmap(page_bitmap, 612, 792, "64bd31f862a89e0a9e505a5af6efd506");
468 FPDFBitmap_Destroy(page_bitmap);
469
470 // Add crossed-checkmark
471 FPDF_PAGEOBJECT check = FPDFPageObj_CreateNewPath(300, 500);
472 EXPECT_TRUE(FPDFPath_LineTo(check, 400, 400));
473 EXPECT_TRUE(FPDFPath_LineTo(check, 600, 600));
474 EXPECT_TRUE(FPDFPath_MoveTo(check, 400, 600));
475 EXPECT_TRUE(FPDFPath_LineTo(check, 600, 400));
476 EXPECT_TRUE(FPDFPath_SetStrokeColor(check, 128, 128, 128, 180));
477 EXPECT_TRUE(FPDFPath_SetStrokeWidth(check, 8.35f));
478 EXPECT_TRUE(FPDFPath_SetDrawMode(check, 0, 1));
479 FPDFPage_InsertObject(page, check);
Nicolas Pena2eb1a702017-02-09 18:17:33 -0500480 page_bitmap = RenderPage(page);
481 CompareBitmap(page_bitmap, 612, 792, "4b6f3b9d25c4e194821217d5016c3724");
482 FPDFBitmap_Destroy(page_bitmap);
483
484 // Add stroked and filled oval-ish path.
485 FPDF_PAGEOBJECT path = FPDFPageObj_CreateNewPath(250, 100);
486 EXPECT_TRUE(FPDFPath_BezierTo(path, 180, 166, 180, 233, 250, 300));
487 EXPECT_TRUE(FPDFPath_LineTo(path, 255, 305));
488 EXPECT_TRUE(FPDFPath_BezierTo(path, 325, 233, 325, 166, 255, 105));
489 EXPECT_TRUE(FPDFPath_Close(path));
490 EXPECT_TRUE(FPDFPath_SetFillColor(path, 200, 128, 128, 100));
491 EXPECT_TRUE(FPDFPath_SetStrokeColor(path, 128, 200, 128, 150));
492 EXPECT_TRUE(FPDFPath_SetStrokeWidth(path, 10.5f));
493 EXPECT_TRUE(FPDFPath_SetDrawMode(path, FPDF_FILLMODE_ALTERNATE, 1));
494 FPDFPage_InsertObject(page, path);
Nicolas Pena2eb1a702017-02-09 18:17:33 -0500495 page_bitmap = RenderPage(page);
496 CompareBitmap(page_bitmap, 612, 792, "ff3e6a22326754944cc6e56609acd73b");
497 FPDFBitmap_Destroy(page_bitmap);
498 FPDF_ClosePage(page);
Nicolas Pena2eb1a702017-02-09 18:17:33 -0500499}
Nicolas Pena49058402017-02-14 18:26:20 -0500500
501TEST_F(FPDFEditEmbeddertest, AddStandardFontText) {
502 // Start with a blank page
Nicolas Penad03ca422017-03-06 13:54:33 -0500503 FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
Nicolas Pena49058402017-02-14 18:26:20 -0500504
505 // Add some text to the page
Nicolas Penab3161852017-05-02 14:12:50 -0400506 FPDF_PAGEOBJECT text_object1 =
507 FPDFPageObj_NewTextObj(document(), "Arial", 12.0f);
508 EXPECT_TRUE(text_object1);
509 std::unique_ptr<unsigned short, pdfium::FreeDeleter> text1 =
510 GetFPDFWideString(L"I'm at the bottom of the page");
511 EXPECT_TRUE(FPDFText_SetText(text_object1, text1.get()));
512 FPDFPageObj_Transform(text_object1, 1, 0, 0, 1, 20, 20);
513 FPDFPage_InsertObject(page, text_object1);
Nicolas Pena49058402017-02-14 18:26:20 -0500514 FPDF_BITMAP page_bitmap = RenderPage(page);
515#if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
Lei Zhang0d6d1782017-03-24 15:52:00 -0700516 const char md5[] = "a4dddc1a3930fa694bbff9789dab4161";
Nicolas Pena49058402017-02-14 18:26:20 -0500517#else
Lei Zhang3de50052017-03-29 21:02:13 -0700518 const char md5[] = "6e8a9b0682f60fd3ff1bf087b093d30d";
Nicolas Pena5bcd9a32017-03-22 11:04:35 -0400519#endif
Lei Zhang0d6d1782017-03-24 15:52:00 -0700520 CompareBitmap(page_bitmap, 612, 792, md5);
Nicolas Pena49058402017-02-14 18:26:20 -0500521 FPDFBitmap_Destroy(page_bitmap);
522
523 // Try another font
Nicolas Penab3161852017-05-02 14:12:50 -0400524 FPDF_PAGEOBJECT text_object2 =
Nicolas Penad03ca422017-03-06 13:54:33 -0500525 FPDFPageObj_NewTextObj(document(), "TimesNewRomanBold", 15.0f);
Nicolas Penab3161852017-05-02 14:12:50 -0400526 EXPECT_TRUE(text_object2);
527 std::unique_ptr<unsigned short, pdfium::FreeDeleter> text2 =
528 GetFPDFWideString(L"Hi, I'm Bold. Times New Roman Bold.");
529 EXPECT_TRUE(FPDFText_SetText(text_object2, text2.get()));
530 FPDFPageObj_Transform(text_object2, 1, 0, 0, 1, 100, 600);
531 FPDFPage_InsertObject(page, text_object2);
Nicolas Pena49058402017-02-14 18:26:20 -0500532 page_bitmap = RenderPage(page);
533#if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
Lei Zhang0d6d1782017-03-24 15:52:00 -0700534 const char md5_2[] = "a5c4ace4c6f27644094813fe1441a21c";
Lei Zhang3de50052017-03-29 21:02:13 -0700535#elif _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_
536 const char md5_2[] = "56863642d4d8b418cfd810fdb5a5d92f";
Nicolas Pena49058402017-02-14 18:26:20 -0500537#else
Lei Zhang3de50052017-03-29 21:02:13 -0700538 const char md5_2[] = "0c83875429688bda45a55a692d5aa781";
Nicolas Pena5bcd9a32017-03-22 11:04:35 -0400539#endif
Lei Zhang0d6d1782017-03-24 15:52:00 -0700540 CompareBitmap(page_bitmap, 612, 792, md5_2);
Nicolas Pena49058402017-02-14 18:26:20 -0500541 FPDFBitmap_Destroy(page_bitmap);
542
543 // And some randomly transformed text
Nicolas Penab3161852017-05-02 14:12:50 -0400544 FPDF_PAGEOBJECT text_object3 =
Nicolas Penad03ca422017-03-06 13:54:33 -0500545 FPDFPageObj_NewTextObj(document(), "Courier-Bold", 20.0f);
Nicolas Penab3161852017-05-02 14:12:50 -0400546 EXPECT_TRUE(text_object3);
547 std::unique_ptr<unsigned short, pdfium::FreeDeleter> text3 =
548 GetFPDFWideString(L"Can you read me? <:)>");
549 EXPECT_TRUE(FPDFText_SetText(text_object3, text3.get()));
550 FPDFPageObj_Transform(text_object3, 1, 1.5, 2, 0.5, 200, 200);
551 FPDFPage_InsertObject(page, text_object3);
Nicolas Pena49058402017-02-14 18:26:20 -0500552 page_bitmap = RenderPage(page);
553#if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
Lei Zhang0d6d1782017-03-24 15:52:00 -0700554 const char md5_3[] = "40b3ef04f915ff4c4208948001763544";
Lei Zhang3de50052017-03-29 21:02:13 -0700555#elif _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_
Lei Zhangb8e89e32017-05-02 11:53:08 -0700556 const char md5_3[] = "d69d419def35a098d9c10f8317d6709b";
Nicolas Pena49058402017-02-14 18:26:20 -0500557#else
Lei Zhangb8e89e32017-05-02 11:53:08 -0700558 const char md5_3[] = "8b300d3c6dfc12fa9af97e12ed5bd80a";
Nicolas Pena5bcd9a32017-03-22 11:04:35 -0400559#endif
Lei Zhang0d6d1782017-03-24 15:52:00 -0700560 CompareBitmap(page_bitmap, 612, 792, md5_3);
Nicolas Pena49058402017-02-14 18:26:20 -0500561 FPDFBitmap_Destroy(page_bitmap);
562
563 // TODO(npm): Why are there issues with text rotated by 90 degrees?
564 // TODO(npm): FPDF_SaveAsCopy not giving the desired result after this.
565 FPDF_ClosePage(page);
Nicolas Pena49058402017-02-14 18:26:20 -0500566}
Nicolas Penaa4ad01f2017-02-15 16:26:48 -0500567
568TEST_F(FPDFEditEmbeddertest, DoubleGenerating) {
569 // Start with a blank page
Nicolas Penad03ca422017-03-06 13:54:33 -0500570 FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
Nicolas Penaa4ad01f2017-02-15 16:26:48 -0500571
572 // Add a red rectangle with some non-default alpha
573 FPDF_PAGEOBJECT rect = FPDFPageObj_CreateNewRect(10, 10, 100, 100);
574 EXPECT_TRUE(FPDFPath_SetFillColor(rect, 255, 0, 0, 128));
575 EXPECT_TRUE(FPDFPath_SetDrawMode(rect, FPDF_FILLMODE_WINDING, 0));
576 FPDFPage_InsertObject(page, rect);
577 EXPECT_TRUE(FPDFPage_GenerateContent(page));
578
579 // Check the ExtGState
580 CPDF_Page* the_page = CPDFPageFromFPDFPage(page);
581 CPDF_Dictionary* graphics_dict =
582 the_page->m_pResources->GetDictFor("ExtGState");
583 ASSERT_TRUE(graphics_dict);
584 EXPECT_EQ(1, static_cast<int>(graphics_dict->GetCount()));
585
586 // Check the bitmap
587 FPDF_BITMAP page_bitmap = RenderPage(page);
588 CompareBitmap(page_bitmap, 612, 792, "5384da3406d62360ffb5cac4476fff1c");
589 FPDFBitmap_Destroy(page_bitmap);
590
591 // Never mind, my new favorite color is blue, increase alpha
592 EXPECT_TRUE(FPDFPath_SetFillColor(rect, 0, 0, 255, 180));
593 EXPECT_TRUE(FPDFPage_GenerateContent(page));
594 EXPECT_EQ(2, static_cast<int>(graphics_dict->GetCount()));
595
596 // Check that bitmap displays changed content
597 page_bitmap = RenderPage(page);
598 CompareBitmap(page_bitmap, 612, 792, "2e51656f5073b0bee611d9cd086aa09c");
599 FPDFBitmap_Destroy(page_bitmap);
600
601 // And now generate, without changes
602 EXPECT_TRUE(FPDFPage_GenerateContent(page));
603 EXPECT_EQ(2, static_cast<int>(graphics_dict->GetCount()));
604 page_bitmap = RenderPage(page);
605 CompareBitmap(page_bitmap, 612, 792, "2e51656f5073b0bee611d9cd086aa09c");
606 FPDFBitmap_Destroy(page_bitmap);
607
608 // Add some text to the page
Nicolas Penab3161852017-05-02 14:12:50 -0400609 FPDF_PAGEOBJECT text_object =
610 FPDFPageObj_NewTextObj(document(), "Arial", 12.0f);
611 std::unique_ptr<unsigned short, pdfium::FreeDeleter> text =
612 GetFPDFWideString(L"Something something #text# something");
613 EXPECT_TRUE(FPDFText_SetText(text_object, text.get()));
614 FPDFPageObj_Transform(text_object, 1, 0, 0, 1, 300, 300);
615 FPDFPage_InsertObject(page, text_object);
Nicolas Penaa4ad01f2017-02-15 16:26:48 -0500616 EXPECT_TRUE(FPDFPage_GenerateContent(page));
617 CPDF_Dictionary* font_dict = the_page->m_pResources->GetDictFor("Font");
618 ASSERT_TRUE(font_dict);
619 EXPECT_EQ(1, static_cast<int>(font_dict->GetCount()));
620
621 // Generate yet again, check dicts are reasonably sized
622 EXPECT_TRUE(FPDFPage_GenerateContent(page));
623 EXPECT_EQ(2, static_cast<int>(graphics_dict->GetCount()));
624 EXPECT_EQ(1, static_cast<int>(font_dict->GetCount()));
625 FPDF_ClosePage(page);
Nicolas Penaa4ad01f2017-02-15 16:26:48 -0500626}
Nicolas Penabe90aae2017-02-27 10:41:41 -0500627
Nicolas Penad03ca422017-03-06 13:54:33 -0500628TEST_F(FPDFEditEmbeddertest, LoadSimpleType1Font) {
629 CreateNewDocument();
630 // TODO(npm): use other fonts after disallowing loading any font as any type
631 const CPDF_Font* stock_font =
632 CPDF_Font::GetStockFont(cpdf_doc(), "Times-Bold");
Lei Zhangd74da7b2017-05-04 13:30:29 -0700633 const uint8_t* data = stock_font->GetFont()->GetFontData();
634 const uint32_t size = stock_font->GetFont()->GetSize();
Nicolas Penab3161852017-05-02 14:12:50 -0400635 std::unique_ptr<void, FPDFFontDeleter> font(
636 FPDFText_LoadFont(document(), data, size, FPDF_FONT_TYPE1, false));
637 ASSERT_TRUE(font.get());
Nicolas Pena46abb662017-05-17 17:23:22 -0400638 CPDF_Font* typed_font = static_cast<CPDF_Font*>(font.get());
Nicolas Penad03ca422017-03-06 13:54:33 -0500639 EXPECT_TRUE(typed_font->IsType1Font());
Nicolas Penabe90aae2017-02-27 10:41:41 -0500640
Nicolas Penad03ca422017-03-06 13:54:33 -0500641 CPDF_Dictionary* font_dict = typed_font->GetFontDict();
Nicolas Penabe90aae2017-02-27 10:41:41 -0500642 EXPECT_EQ("Font", font_dict->GetStringFor("Type"));
643 EXPECT_EQ("Type1", font_dict->GetStringFor("Subtype"));
644 EXPECT_EQ("Times New Roman Bold", font_dict->GetStringFor("BaseFont"));
645 ASSERT_TRUE(font_dict->KeyExist("FirstChar"));
646 ASSERT_TRUE(font_dict->KeyExist("LastChar"));
647 EXPECT_EQ(32, font_dict->GetIntegerFor("FirstChar"));
Nicolas Penad03ca422017-03-06 13:54:33 -0500648 EXPECT_EQ(255, font_dict->GetIntegerFor("LastChar"));
649
Nicolas Penabe90aae2017-02-27 10:41:41 -0500650 CPDF_Array* widths_array = font_dict->GetArrayFor("Widths");
Nicolas Penad03ca422017-03-06 13:54:33 -0500651 ASSERT_TRUE(widths_array);
652 ASSERT_EQ(224U, widths_array->GetCount());
Nicolas Penabe90aae2017-02-27 10:41:41 -0500653 EXPECT_EQ(250, widths_array->GetNumberAt(0));
Nicolas Penad03ca422017-03-06 13:54:33 -0500654 EXPECT_EQ(569, widths_array->GetNumberAt(11));
655 EXPECT_EQ(500, widths_array->GetNumberAt(223));
656 CheckFontDescriptor(font_dict, FPDF_FONT_TYPE1, true, false, size, data);
657}
Nicolas Penabe90aae2017-02-27 10:41:41 -0500658
Nicolas Penad03ca422017-03-06 13:54:33 -0500659TEST_F(FPDFEditEmbeddertest, LoadSimpleTrueTypeFont) {
660 CreateNewDocument();
661 const CPDF_Font* stock_font = CPDF_Font::GetStockFont(cpdf_doc(), "Courier");
Lei Zhangd74da7b2017-05-04 13:30:29 -0700662 const uint8_t* data = stock_font->GetFont()->GetFontData();
663 const uint32_t size = stock_font->GetFont()->GetSize();
Nicolas Penab3161852017-05-02 14:12:50 -0400664 std::unique_ptr<void, FPDFFontDeleter> font(
665 FPDFText_LoadFont(document(), data, size, FPDF_FONT_TRUETYPE, false));
666 ASSERT_TRUE(font.get());
Nicolas Pena46abb662017-05-17 17:23:22 -0400667 CPDF_Font* typed_font = static_cast<CPDF_Font*>(font.get());
Nicolas Penad03ca422017-03-06 13:54:33 -0500668 EXPECT_TRUE(typed_font->IsTrueTypeFont());
Nicolas Penabe90aae2017-02-27 10:41:41 -0500669
Nicolas Penad03ca422017-03-06 13:54:33 -0500670 CPDF_Dictionary* font_dict = typed_font->GetFontDict();
671 EXPECT_EQ("Font", font_dict->GetStringFor("Type"));
672 EXPECT_EQ("TrueType", font_dict->GetStringFor("Subtype"));
673 EXPECT_EQ("Courier New", font_dict->GetStringFor("BaseFont"));
674 ASSERT_TRUE(font_dict->KeyExist("FirstChar"));
675 ASSERT_TRUE(font_dict->KeyExist("LastChar"));
676 EXPECT_EQ(32, font_dict->GetIntegerFor("FirstChar"));
677 EXPECT_EQ(255, font_dict->GetIntegerFor("LastChar"));
Nicolas Penabe90aae2017-02-27 10:41:41 -0500678
Nicolas Penad03ca422017-03-06 13:54:33 -0500679 CPDF_Array* widths_array = font_dict->GetArrayFor("Widths");
680 ASSERT_TRUE(widths_array);
681 ASSERT_EQ(224U, widths_array->GetCount());
682 EXPECT_EQ(600, widths_array->GetNumberAt(33));
683 EXPECT_EQ(600, widths_array->GetNumberAt(74));
684 EXPECT_EQ(600, widths_array->GetNumberAt(223));
685 CheckFontDescriptor(font_dict, FPDF_FONT_TRUETYPE, false, false, size, data);
686}
687
688TEST_F(FPDFEditEmbeddertest, LoadCIDType0Font) {
689 CreateNewDocument();
690 const CPDF_Font* stock_font =
691 CPDF_Font::GetStockFont(cpdf_doc(), "Times-Roman");
Lei Zhangd74da7b2017-05-04 13:30:29 -0700692 const uint8_t* data = stock_font->GetFont()->GetFontData();
693 const uint32_t size = stock_font->GetFont()->GetSize();
Nicolas Penab3161852017-05-02 14:12:50 -0400694 std::unique_ptr<void, FPDFFontDeleter> font(
695 FPDFText_LoadFont(document(), data, size, FPDF_FONT_TYPE1, 1));
696 ASSERT_TRUE(font.get());
Nicolas Pena46abb662017-05-17 17:23:22 -0400697 CPDF_Font* typed_font = static_cast<CPDF_Font*>(font.get());
Nicolas Penad03ca422017-03-06 13:54:33 -0500698 EXPECT_TRUE(typed_font->IsCIDFont());
699
700 // Check font dictionary entries
701 CPDF_Dictionary* font_dict = typed_font->GetFontDict();
702 EXPECT_EQ("Font", font_dict->GetStringFor("Type"));
703 EXPECT_EQ("Type0", font_dict->GetStringFor("Subtype"));
704 EXPECT_EQ("Times New Roman-Identity-H", font_dict->GetStringFor("BaseFont"));
705 EXPECT_EQ("Identity-H", font_dict->GetStringFor("Encoding"));
706 CPDF_Array* descendant_array = font_dict->GetArrayFor("DescendantFonts");
707 ASSERT_TRUE(descendant_array);
708 EXPECT_EQ(1U, descendant_array->GetCount());
709
710 // Check the CIDFontDict
711 CPDF_Dictionary* cidfont_dict = descendant_array->GetDictAt(0);
712 EXPECT_EQ("Font", cidfont_dict->GetStringFor("Type"));
713 EXPECT_EQ("CIDFontType0", cidfont_dict->GetStringFor("Subtype"));
714 EXPECT_EQ("Times New Roman", cidfont_dict->GetStringFor("BaseFont"));
715 CPDF_Dictionary* cidinfo_dict = cidfont_dict->GetDictFor("CIDSystemInfo");
716 ASSERT_TRUE(cidinfo_dict);
717 EXPECT_EQ("Adobe", cidinfo_dict->GetStringFor("Registry"));
718 EXPECT_EQ("Identity", cidinfo_dict->GetStringFor("Ordering"));
719 EXPECT_EQ(0, cidinfo_dict->GetNumberFor("Supplement"));
720 CheckFontDescriptor(cidfont_dict, FPDF_FONT_TYPE1, false, false, size, data);
721
722 // Check widths
723 CPDF_Array* widths_array = cidfont_dict->GetArrayFor("W");
724 ASSERT_TRUE(widths_array);
Nicolas Penaf45ade32017-05-03 10:23:49 -0400725 EXPECT_GT(widths_array->GetCount(), 1U);
Nicolas Penad03ca422017-03-06 13:54:33 -0500726 CheckCompositeFontWidths(widths_array, typed_font);
727}
728
729TEST_F(FPDFEditEmbeddertest, LoadCIDType2Font) {
730 CreateNewDocument();
731 const CPDF_Font* stock_font =
732 CPDF_Font::GetStockFont(cpdf_doc(), "Helvetica-Oblique");
Lei Zhangd74da7b2017-05-04 13:30:29 -0700733 const uint8_t* data = stock_font->GetFont()->GetFontData();
734 const uint32_t size = stock_font->GetFont()->GetSize();
Nicolas Penad03ca422017-03-06 13:54:33 -0500735
Nicolas Penab3161852017-05-02 14:12:50 -0400736 std::unique_ptr<void, FPDFFontDeleter> font(
737 FPDFText_LoadFont(document(), data, size, FPDF_FONT_TRUETYPE, 1));
738 ASSERT_TRUE(font.get());
Nicolas Pena46abb662017-05-17 17:23:22 -0400739 CPDF_Font* typed_font = static_cast<CPDF_Font*>(font.get());
Nicolas Penad03ca422017-03-06 13:54:33 -0500740 EXPECT_TRUE(typed_font->IsCIDFont());
741
742 // Check font dictionary entries
743 CPDF_Dictionary* font_dict = typed_font->GetFontDict();
744 EXPECT_EQ("Font", font_dict->GetStringFor("Type"));
745 EXPECT_EQ("Type0", font_dict->GetStringFor("Subtype"));
746 EXPECT_EQ("Arial Italic", font_dict->GetStringFor("BaseFont"));
747 EXPECT_EQ("Identity-H", font_dict->GetStringFor("Encoding"));
748 CPDF_Array* descendant_array = font_dict->GetArrayFor("DescendantFonts");
749 ASSERT_TRUE(descendant_array);
750 EXPECT_EQ(1U, descendant_array->GetCount());
751
752 // Check the CIDFontDict
753 CPDF_Dictionary* cidfont_dict = descendant_array->GetDictAt(0);
754 EXPECT_EQ("Font", cidfont_dict->GetStringFor("Type"));
755 EXPECT_EQ("CIDFontType2", cidfont_dict->GetStringFor("Subtype"));
756 EXPECT_EQ("Arial Italic", cidfont_dict->GetStringFor("BaseFont"));
757 CPDF_Dictionary* cidinfo_dict = cidfont_dict->GetDictFor("CIDSystemInfo");
758 ASSERT_TRUE(cidinfo_dict);
759 EXPECT_EQ("Adobe", cidinfo_dict->GetStringFor("Registry"));
760 EXPECT_EQ("Identity", cidinfo_dict->GetStringFor("Ordering"));
761 EXPECT_EQ(0, cidinfo_dict->GetNumberFor("Supplement"));
762 CheckFontDescriptor(cidfont_dict, FPDF_FONT_TRUETYPE, false, true, size,
763 data);
764
765 // Check widths
766 CPDF_Array* widths_array = cidfont_dict->GetArrayFor("W");
767 ASSERT_TRUE(widths_array);
768 CheckCompositeFontWidths(widths_array, typed_font);
Nicolas Penabe90aae2017-02-27 10:41:41 -0500769}
rbpotterce8e51e2017-04-28 12:42:47 -0700770
771TEST_F(FPDFEditEmbeddertest, NormalizeNegativeRotation) {
772 // Load document with a -90 degree rotation
773 EXPECT_TRUE(OpenDocument("bug_713197.pdf"));
774 FPDF_PAGE page = LoadPage(0);
775 EXPECT_NE(nullptr, page);
776
777 EXPECT_EQ(3, FPDFPage_GetRotation(page));
778 UnloadPage(page);
779}
Nicolas Penab3161852017-05-02 14:12:50 -0400780
781TEST_F(FPDFEditEmbeddertest, AddTrueTypeFontText) {
782 // Start with a blank page
783 FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
784 {
785 const CPDF_Font* stock_font = CPDF_Font::GetStockFont(cpdf_doc(), "Arial");
Lei Zhangd74da7b2017-05-04 13:30:29 -0700786 const uint8_t* data = stock_font->GetFont()->GetFontData();
787 const uint32_t size = stock_font->GetFont()->GetSize();
Nicolas Penab3161852017-05-02 14:12:50 -0400788 std::unique_ptr<void, FPDFFontDeleter> font(
789 FPDFText_LoadFont(document(), data, size, FPDF_FONT_TRUETYPE, 0));
790 ASSERT_TRUE(font.get());
791
792 // Add some text to the page
793 FPDF_PAGEOBJECT text_object =
794 FPDFPageObj_CreateTextObj(document(), font.get(), 12.0f);
795 EXPECT_TRUE(text_object);
796 std::unique_ptr<unsigned short, pdfium::FreeDeleter> text =
797 GetFPDFWideString(L"I am testing my loaded font, WEE.");
798 EXPECT_TRUE(FPDFText_SetText(text_object, text.get()));
799 FPDFPageObj_Transform(text_object, 1, 0, 0, 1, 400, 400);
800 FPDFPage_InsertObject(page, text_object);
Nicolas Penab3161852017-05-02 14:12:50 -0400801 FPDF_BITMAP page_bitmap = RenderPage(page);
802#if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
803 const char md5[] = "17d2b6cd574cf66170b09c8927529a94";
804#else
805 const char md5[] = "28e5b10743660dcdfd1618db47b39d32";
806#endif // _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
807 CompareBitmap(page_bitmap, 612, 792, md5);
808 FPDFBitmap_Destroy(page_bitmap);
809
810 // Add some more text, same font
811 FPDF_PAGEOBJECT text_object2 =
812 FPDFPageObj_CreateTextObj(document(), font.get(), 15.0f);
813 std::unique_ptr<unsigned short, pdfium::FreeDeleter> text2 =
814 GetFPDFWideString(L"Bigger font size");
815 EXPECT_TRUE(FPDFText_SetText(text_object2, text2.get()));
816 FPDFPageObj_Transform(text_object2, 1, 0, 0, 1, 200, 200);
817 FPDFPage_InsertObject(page, text_object2);
Nicolas Penab3161852017-05-02 14:12:50 -0400818 }
819 FPDF_BITMAP page_bitmap2 = RenderPage(page);
820#if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
821 const char md5_2[] = "8eded4193ff1f0f77b8b600a825e97ea";
822#else
823 const char md5_2[] = "a068eef4110d607f77c87ea8340fa2a5";
824#endif // _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
825 CompareBitmap(page_bitmap2, 612, 792, md5_2);
826 FPDFBitmap_Destroy(page_bitmap2);
827
Nicolas Pena207b7272017-05-26 17:37:06 -0400828 EXPECT_TRUE(FPDFPage_GenerateContent(page));
Nicolas Penab3161852017-05-02 14:12:50 -0400829 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
830 FPDF_ClosePage(page);
831 std::string new_file = GetString();
832
833 // Render the saved result
834 FPDF_FILEACCESS file_access;
835 memset(&file_access, 0, sizeof(file_access));
836 file_access.m_FileLen = new_file.size();
837 file_access.m_GetBlock = GetBlockFromString;
838 file_access.m_Param = &new_file;
839 FPDF_DOCUMENT new_doc = FPDF_LoadCustomDocument(&file_access, nullptr);
840 ASSERT_NE(nullptr, new_doc);
841 EXPECT_EQ(1, FPDF_GetPageCount(new_doc));
842 FPDF_PAGE new_page = FPDF_LoadPage(new_doc, 0);
843 ASSERT_NE(nullptr, new_page);
844 FPDF_BITMAP new_bitmap = RenderPage(new_page);
845 CompareBitmap(new_bitmap, 612, 792, md5_2);
846 FPDFBitmap_Destroy(new_bitmap);
847 FPDF_ClosePage(new_page);
848 FPDF_CloseDocument(new_doc);
849}
Nicolas Penaf45ade32017-05-03 10:23:49 -0400850
851// TODO(npm): Add tests using Japanese fonts in other OS.
852#if _FXM_PLATFORM_ == _FXM_PLATFORM_LINUX_
853TEST_F(FPDFEditEmbeddertest, AddCIDFontText) {
854 // Start with a blank page
855 FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
856 CFX_Font CIDfont;
857 {
858 // First, get the data from the font
859 CIDfont.LoadSubst("IPAGothic", 1, 0, 400, 0, 932, 0);
860 EXPECT_EQ("IPAGothic", CIDfont.GetFaceName());
861 const uint8_t* data = CIDfont.GetFontData();
862 const uint32_t size = CIDfont.GetSize();
863
864 // Load the data into a FPDF_Font.
865 std::unique_ptr<void, FPDFFontDeleter> font(
866 FPDFText_LoadFont(document(), data, size, FPDF_FONT_TRUETYPE, 1));
867 ASSERT_TRUE(font.get());
868
869 // Add some text to the page
870 FPDF_PAGEOBJECT text_object =
871 FPDFPageObj_CreateTextObj(document(), font.get(), 12.0f);
872 ASSERT_TRUE(text_object);
873 std::wstring wstr = L"ABCDEFGhijklmnop.";
874 std::unique_ptr<unsigned short, pdfium::FreeDeleter> text =
875 GetFPDFWideString(wstr);
876 EXPECT_TRUE(FPDFText_SetText(text_object, text.get()));
877 FPDFPageObj_Transform(text_object, 1, 0, 0, 1, 200, 200);
878 FPDFPage_InsertObject(page, text_object);
879
880 // And add some Japanese characters
881 FPDF_PAGEOBJECT text_object2 =
882 FPDFPageObj_CreateTextObj(document(), font.get(), 18.0f);
883 ASSERT_TRUE(text_object2);
884 std::wstring wstr2 =
885 L"\u3053\u3093\u306B\u3061\u306f\u4e16\u754C\u3002\u3053\u3053\u306B1"
886 L"\u756A";
887 std::unique_ptr<unsigned short, pdfium::FreeDeleter> text2 =
888 GetFPDFWideString(wstr2);
889 EXPECT_TRUE(FPDFText_SetText(text_object2, text2.get()));
890 FPDFPageObj_Transform(text_object2, 1, 0, 0, 1, 100, 500);
891 FPDFPage_InsertObject(page, text_object2);
892 }
893
Nicolas Pena207b7272017-05-26 17:37:06 -0400894 // Check that the text renders properly.
Nicolas Penaf45ade32017-05-03 10:23:49 -0400895 FPDF_BITMAP page_bitmap = RenderPage(page);
896 const char md5[] = "2bc6c1aaa2252e73246a75775ccf38c2";
897 CompareBitmap(page_bitmap, 612, 792, md5);
898 FPDFBitmap_Destroy(page_bitmap);
899
900 // Save the document, close the page.
Nicolas Pena207b7272017-05-26 17:37:06 -0400901 EXPECT_TRUE(FPDFPage_GenerateContent(page));
Nicolas Penaf45ade32017-05-03 10:23:49 -0400902 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
903 FPDF_ClosePage(page);
904 std::string new_file = GetString();
905
906 // Render the saved result
907 FPDF_FILEACCESS file_access;
908 memset(&file_access, 0, sizeof(file_access));
909 file_access.m_FileLen = new_file.size();
910 file_access.m_GetBlock = GetBlockFromString;
911 file_access.m_Param = &new_file;
912 FPDF_DOCUMENT new_doc = FPDF_LoadCustomDocument(&file_access, nullptr);
913 ASSERT_NE(nullptr, new_doc);
914 EXPECT_EQ(1, FPDF_GetPageCount(new_doc));
915 FPDF_PAGE new_page = FPDF_LoadPage(new_doc, 0);
916 ASSERT_NE(nullptr, new_page);
917 FPDF_BITMAP new_bitmap = RenderPage(new_page);
918 CompareBitmap(new_bitmap, 612, 792, md5);
919 FPDFBitmap_Destroy(new_bitmap);
920 FPDF_ClosePage(new_page);
921 FPDF_CloseDocument(new_doc);
922}
923#endif // _FXM_PLATFORM_ == _FXM_PLATFORM_LINUX_