blob: 4559ee3f192f6db2c3bf0373b4443fe50dca0127 [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();
Nicolas Pena46abb662017-05-17 17:23:22 -040029 cpdf_doc_ = static_cast<CPDF_Document*>(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);
259 EXPECT_TRUE(FPDFPage_GenerateContent(page));
260 FPDF_BITMAP page_bitmap = RenderPage(page);
261 CompareBitmap(page_bitmap, 612, 792, "66d02eaa6181e2c069ce2ea99beda497");
262 FPDFBitmap_Destroy(page_bitmap);
263
264 // Now add to that a green rectangle with some medium alpha
265 FPDF_PAGEOBJECT green_rect = FPDFPageObj_CreateNewRect(100, 100, 40, 40);
266 EXPECT_TRUE(FPDFPath_SetFillColor(green_rect, 0, 255, 0, 128));
Miklos Vajnaed4705b2017-04-05 09:24:50 +0200267
Miklos Vajna1ef04c92017-05-08 18:14:19 +0200268 // Make sure the type of the rectangle is a path.
269 EXPECT_EQ(FPDF_PAGEOBJ_PATH, FPDFPageObj_GetType(green_rect));
270
Miklos Vajnaed4705b2017-04-05 09:24:50 +0200271 // Make sure we get back the same color we set previously.
272 unsigned int R;
273 unsigned int G;
274 unsigned int B;
275 unsigned int A;
276 EXPECT_TRUE(FPDFPath_GetFillColor(green_rect, &R, &G, &B, &A));
277 EXPECT_EQ(0U, R);
278 EXPECT_EQ(255U, G);
279 EXPECT_EQ(0U, B);
280 EXPECT_EQ(128U, A);
281
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500282 EXPECT_TRUE(FPDFPath_SetDrawMode(green_rect, FPDF_FILLMODE_WINDING, 0));
283 FPDFPage_InsertObject(page, green_rect);
284 EXPECT_TRUE(FPDFPage_GenerateContent(page));
285 page_bitmap = RenderPage(page);
286 CompareBitmap(page_bitmap, 612, 792, "7b0b87604594e773add528fae567a558");
287 FPDFBitmap_Destroy(page_bitmap);
288
289 // Add a black triangle.
290 FPDF_PAGEOBJECT black_path = FPDFPageObj_CreateNewPath(400, 100);
291 EXPECT_TRUE(FPDFPath_SetFillColor(black_path, 0, 0, 0, 200));
292 EXPECT_TRUE(FPDFPath_SetDrawMode(black_path, FPDF_FILLMODE_ALTERNATE, 0));
293 EXPECT_TRUE(FPDFPath_LineTo(black_path, 400, 200));
294 EXPECT_TRUE(FPDFPath_LineTo(black_path, 300, 100));
295 EXPECT_TRUE(FPDFPath_Close(black_path));
296 FPDFPage_InsertObject(page, black_path);
297 EXPECT_TRUE(FPDFPage_GenerateContent(page));
298 page_bitmap = RenderPage(page);
299 CompareBitmap(page_bitmap, 612, 792, "eadc8020a14dfcf091da2688733d8806");
300 FPDFBitmap_Destroy(page_bitmap);
301
302 // Now add a more complex blue path.
303 FPDF_PAGEOBJECT blue_path = FPDFPageObj_CreateNewPath(200, 200);
304 EXPECT_TRUE(FPDFPath_SetFillColor(blue_path, 0, 0, 255, 255));
305 EXPECT_TRUE(FPDFPath_SetDrawMode(blue_path, FPDF_FILLMODE_WINDING, 0));
306 EXPECT_TRUE(FPDFPath_LineTo(blue_path, 230, 230));
307 EXPECT_TRUE(FPDFPath_BezierTo(blue_path, 250, 250, 280, 280, 300, 300));
308 EXPECT_TRUE(FPDFPath_LineTo(blue_path, 325, 325));
309 EXPECT_TRUE(FPDFPath_LineTo(blue_path, 350, 325));
310 EXPECT_TRUE(FPDFPath_BezierTo(blue_path, 375, 330, 390, 360, 400, 400));
311 EXPECT_TRUE(FPDFPath_Close(blue_path));
312 FPDFPage_InsertObject(page, blue_path);
313 EXPECT_TRUE(FPDFPage_GenerateContent(page));
314 page_bitmap = RenderPage(page);
315 CompareBitmap(page_bitmap, 612, 792, "9823e1a21bd9b72b6a442ba4f12af946");
316 FPDFBitmap_Destroy(page_bitmap);
317
318 // Now save the result, closing the page and document
Nicolas Penad03ca422017-03-06 13:54:33 -0500319 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500320 FPDF_ClosePage(page);
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500321 std::string new_file = GetString();
322
323 // Render the saved result
324 FPDF_FILEACCESS file_access;
325 memset(&file_access, 0, sizeof(file_access));
326 file_access.m_FileLen = new_file.size();
327 file_access.m_GetBlock = GetBlockFromString;
328 file_access.m_Param = &new_file;
329 FPDF_DOCUMENT new_doc = FPDF_LoadCustomDocument(&file_access, nullptr);
330 ASSERT_NE(nullptr, new_doc);
331 EXPECT_EQ(1, FPDF_GetPageCount(new_doc));
332 FPDF_PAGE new_page = FPDF_LoadPage(new_doc, 0);
333 ASSERT_NE(nullptr, new_page);
334 FPDF_BITMAP new_bitmap = RenderPage(new_page);
335 CompareBitmap(new_bitmap, 612, 792, "9823e1a21bd9b72b6a442ba4f12af946");
336 FPDFBitmap_Destroy(new_bitmap);
337 FPDF_ClosePage(new_page);
338 FPDF_CloseDocument(new_doc);
339}
340
341TEST_F(FPDFEditEmbeddertest, PathOnTopOfText) {
342 // Load document with some text
343 EXPECT_TRUE(OpenDocument("hello_world.pdf"));
344 FPDF_PAGE page = LoadPage(0);
345 EXPECT_NE(nullptr, page);
346
347 // Add an opaque rectangle on top of some of the text.
348 FPDF_PAGEOBJECT red_rect = FPDFPageObj_CreateNewRect(20, 100, 50, 50);
349 EXPECT_TRUE(FPDFPath_SetFillColor(red_rect, 255, 0, 0, 255));
350 EXPECT_TRUE(FPDFPath_SetDrawMode(red_rect, FPDF_FILLMODE_ALTERNATE, 0));
351 FPDFPage_InsertObject(page, red_rect);
352 EXPECT_TRUE(FPDFPage_GenerateContent(page));
353
354 // Add a transparent triangle on top of other part of the text.
355 FPDF_PAGEOBJECT black_path = FPDFPageObj_CreateNewPath(20, 50);
356 EXPECT_TRUE(FPDFPath_SetFillColor(black_path, 0, 0, 0, 100));
357 EXPECT_TRUE(FPDFPath_SetDrawMode(black_path, FPDF_FILLMODE_ALTERNATE, 0));
358 EXPECT_TRUE(FPDFPath_LineTo(black_path, 30, 80));
359 EXPECT_TRUE(FPDFPath_LineTo(black_path, 40, 10));
360 EXPECT_TRUE(FPDFPath_Close(black_path));
361 FPDFPage_InsertObject(page, black_path);
362 EXPECT_TRUE(FPDFPage_GenerateContent(page));
363
364 // Render and check the result. Text is slightly different on Mac.
365 FPDF_BITMAP bitmap = RenderPage(page);
366#if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
Lei Zhang0d6d1782017-03-24 15:52:00 -0700367 const char md5[] = "f9e6fa74230f234286bfcada9f7606d8";
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500368#else
Lei Zhang3de50052017-03-29 21:02:13 -0700369 const char md5[] = "2fdfc5dda29374cfba4349362e38ebdb";
Nicolas Pena5bcd9a32017-03-22 11:04:35 -0400370#endif
Lei Zhang0d6d1782017-03-24 15:52:00 -0700371 CompareBitmap(bitmap, 200, 200, md5);
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500372 FPDFBitmap_Destroy(bitmap);
373 UnloadPage(page);
374}
Nicolas Pena2eb1a702017-02-09 18:17:33 -0500375
376TEST_F(FPDFEditEmbeddertest, AddStrokedPaths) {
377 // Start with a blank page
Nicolas Penad03ca422017-03-06 13:54:33 -0500378 FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
Nicolas Pena2eb1a702017-02-09 18:17:33 -0500379
380 // Add a large stroked rectangle (fill color should not affect it).
381 FPDF_PAGEOBJECT rect = FPDFPageObj_CreateNewRect(20, 20, 200, 400);
382 EXPECT_TRUE(FPDFPath_SetFillColor(rect, 255, 0, 0, 255));
383 EXPECT_TRUE(FPDFPath_SetStrokeColor(rect, 0, 255, 0, 255));
384 EXPECT_TRUE(FPDFPath_SetStrokeWidth(rect, 15.0f));
385 EXPECT_TRUE(FPDFPath_SetDrawMode(rect, 0, 1));
386 FPDFPage_InsertObject(page, rect);
387 EXPECT_TRUE(FPDFPage_GenerateContent(page));
388 FPDF_BITMAP page_bitmap = RenderPage(page);
389 CompareBitmap(page_bitmap, 612, 792, "64bd31f862a89e0a9e505a5af6efd506");
390 FPDFBitmap_Destroy(page_bitmap);
391
392 // Add crossed-checkmark
393 FPDF_PAGEOBJECT check = FPDFPageObj_CreateNewPath(300, 500);
394 EXPECT_TRUE(FPDFPath_LineTo(check, 400, 400));
395 EXPECT_TRUE(FPDFPath_LineTo(check, 600, 600));
396 EXPECT_TRUE(FPDFPath_MoveTo(check, 400, 600));
397 EXPECT_TRUE(FPDFPath_LineTo(check, 600, 400));
398 EXPECT_TRUE(FPDFPath_SetStrokeColor(check, 128, 128, 128, 180));
399 EXPECT_TRUE(FPDFPath_SetStrokeWidth(check, 8.35f));
400 EXPECT_TRUE(FPDFPath_SetDrawMode(check, 0, 1));
401 FPDFPage_InsertObject(page, check);
402 EXPECT_TRUE(FPDFPage_GenerateContent(page));
403 page_bitmap = RenderPage(page);
404 CompareBitmap(page_bitmap, 612, 792, "4b6f3b9d25c4e194821217d5016c3724");
405 FPDFBitmap_Destroy(page_bitmap);
406
407 // Add stroked and filled oval-ish path.
408 FPDF_PAGEOBJECT path = FPDFPageObj_CreateNewPath(250, 100);
409 EXPECT_TRUE(FPDFPath_BezierTo(path, 180, 166, 180, 233, 250, 300));
410 EXPECT_TRUE(FPDFPath_LineTo(path, 255, 305));
411 EXPECT_TRUE(FPDFPath_BezierTo(path, 325, 233, 325, 166, 255, 105));
412 EXPECT_TRUE(FPDFPath_Close(path));
413 EXPECT_TRUE(FPDFPath_SetFillColor(path, 200, 128, 128, 100));
414 EXPECT_TRUE(FPDFPath_SetStrokeColor(path, 128, 200, 128, 150));
415 EXPECT_TRUE(FPDFPath_SetStrokeWidth(path, 10.5f));
416 EXPECT_TRUE(FPDFPath_SetDrawMode(path, FPDF_FILLMODE_ALTERNATE, 1));
417 FPDFPage_InsertObject(page, path);
418 EXPECT_TRUE(FPDFPage_GenerateContent(page));
419 page_bitmap = RenderPage(page);
420 CompareBitmap(page_bitmap, 612, 792, "ff3e6a22326754944cc6e56609acd73b");
421 FPDFBitmap_Destroy(page_bitmap);
422 FPDF_ClosePage(page);
Nicolas Pena2eb1a702017-02-09 18:17:33 -0500423}
Nicolas Pena49058402017-02-14 18:26:20 -0500424
425TEST_F(FPDFEditEmbeddertest, AddStandardFontText) {
426 // Start with a blank page
Nicolas Penad03ca422017-03-06 13:54:33 -0500427 FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
Nicolas Pena49058402017-02-14 18:26:20 -0500428
429 // Add some text to the page
Nicolas Penab3161852017-05-02 14:12:50 -0400430 FPDF_PAGEOBJECT text_object1 =
431 FPDFPageObj_NewTextObj(document(), "Arial", 12.0f);
432 EXPECT_TRUE(text_object1);
433 std::unique_ptr<unsigned short, pdfium::FreeDeleter> text1 =
434 GetFPDFWideString(L"I'm at the bottom of the page");
435 EXPECT_TRUE(FPDFText_SetText(text_object1, text1.get()));
436 FPDFPageObj_Transform(text_object1, 1, 0, 0, 1, 20, 20);
437 FPDFPage_InsertObject(page, text_object1);
Nicolas Pena49058402017-02-14 18:26:20 -0500438 EXPECT_TRUE(FPDFPage_GenerateContent(page));
439 FPDF_BITMAP page_bitmap = RenderPage(page);
440#if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
Lei Zhang0d6d1782017-03-24 15:52:00 -0700441 const char md5[] = "a4dddc1a3930fa694bbff9789dab4161";
Nicolas Pena49058402017-02-14 18:26:20 -0500442#else
Lei Zhang3de50052017-03-29 21:02:13 -0700443 const char md5[] = "6e8a9b0682f60fd3ff1bf087b093d30d";
Nicolas Pena5bcd9a32017-03-22 11:04:35 -0400444#endif
Lei Zhang0d6d1782017-03-24 15:52:00 -0700445 CompareBitmap(page_bitmap, 612, 792, md5);
Nicolas Pena49058402017-02-14 18:26:20 -0500446 FPDFBitmap_Destroy(page_bitmap);
447
448 // Try another font
Nicolas Penab3161852017-05-02 14:12:50 -0400449 FPDF_PAGEOBJECT text_object2 =
Nicolas Penad03ca422017-03-06 13:54:33 -0500450 FPDFPageObj_NewTextObj(document(), "TimesNewRomanBold", 15.0f);
Nicolas Penab3161852017-05-02 14:12:50 -0400451 EXPECT_TRUE(text_object2);
452 std::unique_ptr<unsigned short, pdfium::FreeDeleter> text2 =
453 GetFPDFWideString(L"Hi, I'm Bold. Times New Roman Bold.");
454 EXPECT_TRUE(FPDFText_SetText(text_object2, text2.get()));
455 FPDFPageObj_Transform(text_object2, 1, 0, 0, 1, 100, 600);
456 FPDFPage_InsertObject(page, text_object2);
Nicolas Pena49058402017-02-14 18:26:20 -0500457 EXPECT_TRUE(FPDFPage_GenerateContent(page));
458 page_bitmap = RenderPage(page);
459#if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
Lei Zhang0d6d1782017-03-24 15:52:00 -0700460 const char md5_2[] = "a5c4ace4c6f27644094813fe1441a21c";
Lei Zhang3de50052017-03-29 21:02:13 -0700461#elif _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_
462 const char md5_2[] = "56863642d4d8b418cfd810fdb5a5d92f";
Nicolas Pena49058402017-02-14 18:26:20 -0500463#else
Lei Zhang3de50052017-03-29 21:02:13 -0700464 const char md5_2[] = "0c83875429688bda45a55a692d5aa781";
Nicolas Pena5bcd9a32017-03-22 11:04:35 -0400465#endif
Lei Zhang0d6d1782017-03-24 15:52:00 -0700466 CompareBitmap(page_bitmap, 612, 792, md5_2);
Nicolas Pena49058402017-02-14 18:26:20 -0500467 FPDFBitmap_Destroy(page_bitmap);
468
469 // And some randomly transformed text
Nicolas Penab3161852017-05-02 14:12:50 -0400470 FPDF_PAGEOBJECT text_object3 =
Nicolas Penad03ca422017-03-06 13:54:33 -0500471 FPDFPageObj_NewTextObj(document(), "Courier-Bold", 20.0f);
Nicolas Penab3161852017-05-02 14:12:50 -0400472 EXPECT_TRUE(text_object3);
473 std::unique_ptr<unsigned short, pdfium::FreeDeleter> text3 =
474 GetFPDFWideString(L"Can you read me? <:)>");
475 EXPECT_TRUE(FPDFText_SetText(text_object3, text3.get()));
476 FPDFPageObj_Transform(text_object3, 1, 1.5, 2, 0.5, 200, 200);
477 FPDFPage_InsertObject(page, text_object3);
Nicolas Pena49058402017-02-14 18:26:20 -0500478 EXPECT_TRUE(FPDFPage_GenerateContent(page));
479 page_bitmap = RenderPage(page);
480#if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
Lei Zhang0d6d1782017-03-24 15:52:00 -0700481 const char md5_3[] = "40b3ef04f915ff4c4208948001763544";
Lei Zhang3de50052017-03-29 21:02:13 -0700482#elif _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_
Lei Zhangb8e89e32017-05-02 11:53:08 -0700483 const char md5_3[] = "d69d419def35a098d9c10f8317d6709b";
Nicolas Pena49058402017-02-14 18:26:20 -0500484#else
Lei Zhangb8e89e32017-05-02 11:53:08 -0700485 const char md5_3[] = "8b300d3c6dfc12fa9af97e12ed5bd80a";
Nicolas Pena5bcd9a32017-03-22 11:04:35 -0400486#endif
Lei Zhang0d6d1782017-03-24 15:52:00 -0700487 CompareBitmap(page_bitmap, 612, 792, md5_3);
Nicolas Pena49058402017-02-14 18:26:20 -0500488 FPDFBitmap_Destroy(page_bitmap);
489
490 // TODO(npm): Why are there issues with text rotated by 90 degrees?
491 // TODO(npm): FPDF_SaveAsCopy not giving the desired result after this.
492 FPDF_ClosePage(page);
Nicolas Pena49058402017-02-14 18:26:20 -0500493}
Nicolas Penaa4ad01f2017-02-15 16:26:48 -0500494
495TEST_F(FPDFEditEmbeddertest, DoubleGenerating) {
496 // Start with a blank page
Nicolas Penad03ca422017-03-06 13:54:33 -0500497 FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
Nicolas Penaa4ad01f2017-02-15 16:26:48 -0500498
499 // Add a red rectangle with some non-default alpha
500 FPDF_PAGEOBJECT rect = FPDFPageObj_CreateNewRect(10, 10, 100, 100);
501 EXPECT_TRUE(FPDFPath_SetFillColor(rect, 255, 0, 0, 128));
502 EXPECT_TRUE(FPDFPath_SetDrawMode(rect, FPDF_FILLMODE_WINDING, 0));
503 FPDFPage_InsertObject(page, rect);
504 EXPECT_TRUE(FPDFPage_GenerateContent(page));
505
506 // Check the ExtGState
507 CPDF_Page* the_page = CPDFPageFromFPDFPage(page);
508 CPDF_Dictionary* graphics_dict =
509 the_page->m_pResources->GetDictFor("ExtGState");
510 ASSERT_TRUE(graphics_dict);
511 EXPECT_EQ(1, static_cast<int>(graphics_dict->GetCount()));
512
513 // Check the bitmap
514 FPDF_BITMAP page_bitmap = RenderPage(page);
515 CompareBitmap(page_bitmap, 612, 792, "5384da3406d62360ffb5cac4476fff1c");
516 FPDFBitmap_Destroy(page_bitmap);
517
518 // Never mind, my new favorite color is blue, increase alpha
519 EXPECT_TRUE(FPDFPath_SetFillColor(rect, 0, 0, 255, 180));
520 EXPECT_TRUE(FPDFPage_GenerateContent(page));
521 EXPECT_EQ(2, static_cast<int>(graphics_dict->GetCount()));
522
523 // Check that bitmap displays changed content
524 page_bitmap = RenderPage(page);
525 CompareBitmap(page_bitmap, 612, 792, "2e51656f5073b0bee611d9cd086aa09c");
526 FPDFBitmap_Destroy(page_bitmap);
527
528 // And now generate, without changes
529 EXPECT_TRUE(FPDFPage_GenerateContent(page));
530 EXPECT_EQ(2, static_cast<int>(graphics_dict->GetCount()));
531 page_bitmap = RenderPage(page);
532 CompareBitmap(page_bitmap, 612, 792, "2e51656f5073b0bee611d9cd086aa09c");
533 FPDFBitmap_Destroy(page_bitmap);
534
535 // Add some text to the page
Nicolas Penab3161852017-05-02 14:12:50 -0400536 FPDF_PAGEOBJECT text_object =
537 FPDFPageObj_NewTextObj(document(), "Arial", 12.0f);
538 std::unique_ptr<unsigned short, pdfium::FreeDeleter> text =
539 GetFPDFWideString(L"Something something #text# something");
540 EXPECT_TRUE(FPDFText_SetText(text_object, text.get()));
541 FPDFPageObj_Transform(text_object, 1, 0, 0, 1, 300, 300);
542 FPDFPage_InsertObject(page, text_object);
Nicolas Penaa4ad01f2017-02-15 16:26:48 -0500543 EXPECT_TRUE(FPDFPage_GenerateContent(page));
544 CPDF_Dictionary* font_dict = the_page->m_pResources->GetDictFor("Font");
545 ASSERT_TRUE(font_dict);
546 EXPECT_EQ(1, static_cast<int>(font_dict->GetCount()));
547
548 // Generate yet again, check dicts are reasonably sized
549 EXPECT_TRUE(FPDFPage_GenerateContent(page));
550 EXPECT_EQ(2, static_cast<int>(graphics_dict->GetCount()));
551 EXPECT_EQ(1, static_cast<int>(font_dict->GetCount()));
552 FPDF_ClosePage(page);
Nicolas Penaa4ad01f2017-02-15 16:26:48 -0500553}
Nicolas Penabe90aae2017-02-27 10:41:41 -0500554
Nicolas Penad03ca422017-03-06 13:54:33 -0500555TEST_F(FPDFEditEmbeddertest, LoadSimpleType1Font) {
556 CreateNewDocument();
557 // TODO(npm): use other fonts after disallowing loading any font as any type
558 const CPDF_Font* stock_font =
559 CPDF_Font::GetStockFont(cpdf_doc(), "Times-Bold");
Lei Zhangd74da7b2017-05-04 13:30:29 -0700560 const uint8_t* data = stock_font->GetFont()->GetFontData();
561 const uint32_t size = stock_font->GetFont()->GetSize();
Nicolas Penab3161852017-05-02 14:12:50 -0400562 std::unique_ptr<void, FPDFFontDeleter> font(
563 FPDFText_LoadFont(document(), data, size, FPDF_FONT_TYPE1, false));
564 ASSERT_TRUE(font.get());
Nicolas Pena46abb662017-05-17 17:23:22 -0400565 CPDF_Font* typed_font = static_cast<CPDF_Font*>(font.get());
Nicolas Penad03ca422017-03-06 13:54:33 -0500566 EXPECT_TRUE(typed_font->IsType1Font());
Nicolas Penabe90aae2017-02-27 10:41:41 -0500567
Nicolas Penad03ca422017-03-06 13:54:33 -0500568 CPDF_Dictionary* font_dict = typed_font->GetFontDict();
Nicolas Penabe90aae2017-02-27 10:41:41 -0500569 EXPECT_EQ("Font", font_dict->GetStringFor("Type"));
570 EXPECT_EQ("Type1", font_dict->GetStringFor("Subtype"));
571 EXPECT_EQ("Times New Roman Bold", font_dict->GetStringFor("BaseFont"));
572 ASSERT_TRUE(font_dict->KeyExist("FirstChar"));
573 ASSERT_TRUE(font_dict->KeyExist("LastChar"));
574 EXPECT_EQ(32, font_dict->GetIntegerFor("FirstChar"));
Nicolas Penad03ca422017-03-06 13:54:33 -0500575 EXPECT_EQ(255, font_dict->GetIntegerFor("LastChar"));
576
Nicolas Penabe90aae2017-02-27 10:41:41 -0500577 CPDF_Array* widths_array = font_dict->GetArrayFor("Widths");
Nicolas Penad03ca422017-03-06 13:54:33 -0500578 ASSERT_TRUE(widths_array);
579 ASSERT_EQ(224U, widths_array->GetCount());
Nicolas Penabe90aae2017-02-27 10:41:41 -0500580 EXPECT_EQ(250, widths_array->GetNumberAt(0));
Nicolas Penad03ca422017-03-06 13:54:33 -0500581 EXPECT_EQ(569, widths_array->GetNumberAt(11));
582 EXPECT_EQ(500, widths_array->GetNumberAt(223));
583 CheckFontDescriptor(font_dict, FPDF_FONT_TYPE1, true, false, size, data);
584}
Nicolas Penabe90aae2017-02-27 10:41:41 -0500585
Nicolas Penad03ca422017-03-06 13:54:33 -0500586TEST_F(FPDFEditEmbeddertest, LoadSimpleTrueTypeFont) {
587 CreateNewDocument();
588 const CPDF_Font* stock_font = CPDF_Font::GetStockFont(cpdf_doc(), "Courier");
Lei Zhangd74da7b2017-05-04 13:30:29 -0700589 const uint8_t* data = stock_font->GetFont()->GetFontData();
590 const uint32_t size = stock_font->GetFont()->GetSize();
Nicolas Penab3161852017-05-02 14:12:50 -0400591 std::unique_ptr<void, FPDFFontDeleter> font(
592 FPDFText_LoadFont(document(), data, size, FPDF_FONT_TRUETYPE, false));
593 ASSERT_TRUE(font.get());
Nicolas Pena46abb662017-05-17 17:23:22 -0400594 CPDF_Font* typed_font = static_cast<CPDF_Font*>(font.get());
Nicolas Penad03ca422017-03-06 13:54:33 -0500595 EXPECT_TRUE(typed_font->IsTrueTypeFont());
Nicolas Penabe90aae2017-02-27 10:41:41 -0500596
Nicolas Penad03ca422017-03-06 13:54:33 -0500597 CPDF_Dictionary* font_dict = typed_font->GetFontDict();
598 EXPECT_EQ("Font", font_dict->GetStringFor("Type"));
599 EXPECT_EQ("TrueType", font_dict->GetStringFor("Subtype"));
600 EXPECT_EQ("Courier New", font_dict->GetStringFor("BaseFont"));
601 ASSERT_TRUE(font_dict->KeyExist("FirstChar"));
602 ASSERT_TRUE(font_dict->KeyExist("LastChar"));
603 EXPECT_EQ(32, font_dict->GetIntegerFor("FirstChar"));
604 EXPECT_EQ(255, font_dict->GetIntegerFor("LastChar"));
Nicolas Penabe90aae2017-02-27 10:41:41 -0500605
Nicolas Penad03ca422017-03-06 13:54:33 -0500606 CPDF_Array* widths_array = font_dict->GetArrayFor("Widths");
607 ASSERT_TRUE(widths_array);
608 ASSERT_EQ(224U, widths_array->GetCount());
609 EXPECT_EQ(600, widths_array->GetNumberAt(33));
610 EXPECT_EQ(600, widths_array->GetNumberAt(74));
611 EXPECT_EQ(600, widths_array->GetNumberAt(223));
612 CheckFontDescriptor(font_dict, FPDF_FONT_TRUETYPE, false, false, size, data);
613}
614
615TEST_F(FPDFEditEmbeddertest, LoadCIDType0Font) {
616 CreateNewDocument();
617 const CPDF_Font* stock_font =
618 CPDF_Font::GetStockFont(cpdf_doc(), "Times-Roman");
Lei Zhangd74da7b2017-05-04 13:30:29 -0700619 const uint8_t* data = stock_font->GetFont()->GetFontData();
620 const uint32_t size = stock_font->GetFont()->GetSize();
Nicolas Penab3161852017-05-02 14:12:50 -0400621 std::unique_ptr<void, FPDFFontDeleter> font(
622 FPDFText_LoadFont(document(), data, size, FPDF_FONT_TYPE1, 1));
623 ASSERT_TRUE(font.get());
Nicolas Pena46abb662017-05-17 17:23:22 -0400624 CPDF_Font* typed_font = static_cast<CPDF_Font*>(font.get());
Nicolas Penad03ca422017-03-06 13:54:33 -0500625 EXPECT_TRUE(typed_font->IsCIDFont());
626
627 // Check font dictionary entries
628 CPDF_Dictionary* font_dict = typed_font->GetFontDict();
629 EXPECT_EQ("Font", font_dict->GetStringFor("Type"));
630 EXPECT_EQ("Type0", font_dict->GetStringFor("Subtype"));
631 EXPECT_EQ("Times New Roman-Identity-H", font_dict->GetStringFor("BaseFont"));
632 EXPECT_EQ("Identity-H", font_dict->GetStringFor("Encoding"));
633 CPDF_Array* descendant_array = font_dict->GetArrayFor("DescendantFonts");
634 ASSERT_TRUE(descendant_array);
635 EXPECT_EQ(1U, descendant_array->GetCount());
636
637 // Check the CIDFontDict
638 CPDF_Dictionary* cidfont_dict = descendant_array->GetDictAt(0);
639 EXPECT_EQ("Font", cidfont_dict->GetStringFor("Type"));
640 EXPECT_EQ("CIDFontType0", cidfont_dict->GetStringFor("Subtype"));
641 EXPECT_EQ("Times New Roman", cidfont_dict->GetStringFor("BaseFont"));
642 CPDF_Dictionary* cidinfo_dict = cidfont_dict->GetDictFor("CIDSystemInfo");
643 ASSERT_TRUE(cidinfo_dict);
644 EXPECT_EQ("Adobe", cidinfo_dict->GetStringFor("Registry"));
645 EXPECT_EQ("Identity", cidinfo_dict->GetStringFor("Ordering"));
646 EXPECT_EQ(0, cidinfo_dict->GetNumberFor("Supplement"));
647 CheckFontDescriptor(cidfont_dict, FPDF_FONT_TYPE1, false, false, size, data);
648
649 // Check widths
650 CPDF_Array* widths_array = cidfont_dict->GetArrayFor("W");
651 ASSERT_TRUE(widths_array);
Nicolas Penaf45ade32017-05-03 10:23:49 -0400652 EXPECT_GT(widths_array->GetCount(), 1U);
Nicolas Penad03ca422017-03-06 13:54:33 -0500653 CheckCompositeFontWidths(widths_array, typed_font);
654}
655
656TEST_F(FPDFEditEmbeddertest, LoadCIDType2Font) {
657 CreateNewDocument();
658 const CPDF_Font* stock_font =
659 CPDF_Font::GetStockFont(cpdf_doc(), "Helvetica-Oblique");
Lei Zhangd74da7b2017-05-04 13:30:29 -0700660 const uint8_t* data = stock_font->GetFont()->GetFontData();
661 const uint32_t size = stock_font->GetFont()->GetSize();
Nicolas Penad03ca422017-03-06 13:54:33 -0500662
Nicolas Penab3161852017-05-02 14:12:50 -0400663 std::unique_ptr<void, FPDFFontDeleter> font(
664 FPDFText_LoadFont(document(), data, size, FPDF_FONT_TRUETYPE, 1));
665 ASSERT_TRUE(font.get());
Nicolas Pena46abb662017-05-17 17:23:22 -0400666 CPDF_Font* typed_font = static_cast<CPDF_Font*>(font.get());
Nicolas Penad03ca422017-03-06 13:54:33 -0500667 EXPECT_TRUE(typed_font->IsCIDFont());
668
669 // Check font dictionary entries
670 CPDF_Dictionary* font_dict = typed_font->GetFontDict();
671 EXPECT_EQ("Font", font_dict->GetStringFor("Type"));
672 EXPECT_EQ("Type0", font_dict->GetStringFor("Subtype"));
673 EXPECT_EQ("Arial Italic", font_dict->GetStringFor("BaseFont"));
674 EXPECT_EQ("Identity-H", font_dict->GetStringFor("Encoding"));
675 CPDF_Array* descendant_array = font_dict->GetArrayFor("DescendantFonts");
676 ASSERT_TRUE(descendant_array);
677 EXPECT_EQ(1U, descendant_array->GetCount());
678
679 // Check the CIDFontDict
680 CPDF_Dictionary* cidfont_dict = descendant_array->GetDictAt(0);
681 EXPECT_EQ("Font", cidfont_dict->GetStringFor("Type"));
682 EXPECT_EQ("CIDFontType2", cidfont_dict->GetStringFor("Subtype"));
683 EXPECT_EQ("Arial Italic", cidfont_dict->GetStringFor("BaseFont"));
684 CPDF_Dictionary* cidinfo_dict = cidfont_dict->GetDictFor("CIDSystemInfo");
685 ASSERT_TRUE(cidinfo_dict);
686 EXPECT_EQ("Adobe", cidinfo_dict->GetStringFor("Registry"));
687 EXPECT_EQ("Identity", cidinfo_dict->GetStringFor("Ordering"));
688 EXPECT_EQ(0, cidinfo_dict->GetNumberFor("Supplement"));
689 CheckFontDescriptor(cidfont_dict, FPDF_FONT_TRUETYPE, false, true, size,
690 data);
691
692 // Check widths
693 CPDF_Array* widths_array = cidfont_dict->GetArrayFor("W");
694 ASSERT_TRUE(widths_array);
695 CheckCompositeFontWidths(widths_array, typed_font);
Nicolas Penabe90aae2017-02-27 10:41:41 -0500696}
rbpotterce8e51e2017-04-28 12:42:47 -0700697
698TEST_F(FPDFEditEmbeddertest, NormalizeNegativeRotation) {
699 // Load document with a -90 degree rotation
700 EXPECT_TRUE(OpenDocument("bug_713197.pdf"));
701 FPDF_PAGE page = LoadPage(0);
702 EXPECT_NE(nullptr, page);
703
704 EXPECT_EQ(3, FPDFPage_GetRotation(page));
705 UnloadPage(page);
706}
Nicolas Penab3161852017-05-02 14:12:50 -0400707
708TEST_F(FPDFEditEmbeddertest, AddTrueTypeFontText) {
709 // Start with a blank page
710 FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
711 {
712 const CPDF_Font* stock_font = CPDF_Font::GetStockFont(cpdf_doc(), "Arial");
Lei Zhangd74da7b2017-05-04 13:30:29 -0700713 const uint8_t* data = stock_font->GetFont()->GetFontData();
714 const uint32_t size = stock_font->GetFont()->GetSize();
Nicolas Penab3161852017-05-02 14:12:50 -0400715 std::unique_ptr<void, FPDFFontDeleter> font(
716 FPDFText_LoadFont(document(), data, size, FPDF_FONT_TRUETYPE, 0));
717 ASSERT_TRUE(font.get());
718
719 // Add some text to the page
720 FPDF_PAGEOBJECT text_object =
721 FPDFPageObj_CreateTextObj(document(), font.get(), 12.0f);
722 EXPECT_TRUE(text_object);
723 std::unique_ptr<unsigned short, pdfium::FreeDeleter> text =
724 GetFPDFWideString(L"I am testing my loaded font, WEE.");
725 EXPECT_TRUE(FPDFText_SetText(text_object, text.get()));
726 FPDFPageObj_Transform(text_object, 1, 0, 0, 1, 400, 400);
727 FPDFPage_InsertObject(page, text_object);
728 EXPECT_TRUE(FPDFPage_GenerateContent(page));
729 FPDF_BITMAP page_bitmap = RenderPage(page);
730#if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
731 const char md5[] = "17d2b6cd574cf66170b09c8927529a94";
732#else
733 const char md5[] = "28e5b10743660dcdfd1618db47b39d32";
734#endif // _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
735 CompareBitmap(page_bitmap, 612, 792, md5);
736 FPDFBitmap_Destroy(page_bitmap);
737
738 // Add some more text, same font
739 FPDF_PAGEOBJECT text_object2 =
740 FPDFPageObj_CreateTextObj(document(), font.get(), 15.0f);
741 std::unique_ptr<unsigned short, pdfium::FreeDeleter> text2 =
742 GetFPDFWideString(L"Bigger font size");
743 EXPECT_TRUE(FPDFText_SetText(text_object2, text2.get()));
744 FPDFPageObj_Transform(text_object2, 1, 0, 0, 1, 200, 200);
745 FPDFPage_InsertObject(page, text_object2);
746 EXPECT_TRUE(FPDFPage_GenerateContent(page));
747 }
748 FPDF_BITMAP page_bitmap2 = RenderPage(page);
749#if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
750 const char md5_2[] = "8eded4193ff1f0f77b8b600a825e97ea";
751#else
752 const char md5_2[] = "a068eef4110d607f77c87ea8340fa2a5";
753#endif // _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
754 CompareBitmap(page_bitmap2, 612, 792, md5_2);
755 FPDFBitmap_Destroy(page_bitmap2);
756
757 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
758 FPDF_ClosePage(page);
759 std::string new_file = GetString();
760
761 // Render the saved result
762 FPDF_FILEACCESS file_access;
763 memset(&file_access, 0, sizeof(file_access));
764 file_access.m_FileLen = new_file.size();
765 file_access.m_GetBlock = GetBlockFromString;
766 file_access.m_Param = &new_file;
767 FPDF_DOCUMENT new_doc = FPDF_LoadCustomDocument(&file_access, nullptr);
768 ASSERT_NE(nullptr, new_doc);
769 EXPECT_EQ(1, FPDF_GetPageCount(new_doc));
770 FPDF_PAGE new_page = FPDF_LoadPage(new_doc, 0);
771 ASSERT_NE(nullptr, new_page);
772 FPDF_BITMAP new_bitmap = RenderPage(new_page);
773 CompareBitmap(new_bitmap, 612, 792, md5_2);
774 FPDFBitmap_Destroy(new_bitmap);
775 FPDF_ClosePage(new_page);
776 FPDF_CloseDocument(new_doc);
777}
Nicolas Penaf45ade32017-05-03 10:23:49 -0400778
779// TODO(npm): Add tests using Japanese fonts in other OS.
780#if _FXM_PLATFORM_ == _FXM_PLATFORM_LINUX_
781TEST_F(FPDFEditEmbeddertest, AddCIDFontText) {
782 // Start with a blank page
783 FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
784 CFX_Font CIDfont;
785 {
786 // First, get the data from the font
787 CIDfont.LoadSubst("IPAGothic", 1, 0, 400, 0, 932, 0);
788 EXPECT_EQ("IPAGothic", CIDfont.GetFaceName());
789 const uint8_t* data = CIDfont.GetFontData();
790 const uint32_t size = CIDfont.GetSize();
791
792 // Load the data into a FPDF_Font.
793 std::unique_ptr<void, FPDFFontDeleter> font(
794 FPDFText_LoadFont(document(), data, size, FPDF_FONT_TRUETYPE, 1));
795 ASSERT_TRUE(font.get());
796
797 // Add some text to the page
798 FPDF_PAGEOBJECT text_object =
799 FPDFPageObj_CreateTextObj(document(), font.get(), 12.0f);
800 ASSERT_TRUE(text_object);
801 std::wstring wstr = L"ABCDEFGhijklmnop.";
802 std::unique_ptr<unsigned short, pdfium::FreeDeleter> text =
803 GetFPDFWideString(wstr);
804 EXPECT_TRUE(FPDFText_SetText(text_object, text.get()));
805 FPDFPageObj_Transform(text_object, 1, 0, 0, 1, 200, 200);
806 FPDFPage_InsertObject(page, text_object);
807
808 // And add some Japanese characters
809 FPDF_PAGEOBJECT text_object2 =
810 FPDFPageObj_CreateTextObj(document(), font.get(), 18.0f);
811 ASSERT_TRUE(text_object2);
812 std::wstring wstr2 =
813 L"\u3053\u3093\u306B\u3061\u306f\u4e16\u754C\u3002\u3053\u3053\u306B1"
814 L"\u756A";
815 std::unique_ptr<unsigned short, pdfium::FreeDeleter> text2 =
816 GetFPDFWideString(wstr2);
817 EXPECT_TRUE(FPDFText_SetText(text_object2, text2.get()));
818 FPDFPageObj_Transform(text_object2, 1, 0, 0, 1, 100, 500);
819 FPDFPage_InsertObject(page, text_object2);
820 }
821
822 // Generate contents and check that the text renders properly.
823 EXPECT_TRUE(FPDFPage_GenerateContent(page));
824 FPDF_BITMAP page_bitmap = RenderPage(page);
825 const char md5[] = "2bc6c1aaa2252e73246a75775ccf38c2";
826 CompareBitmap(page_bitmap, 612, 792, md5);
827 FPDFBitmap_Destroy(page_bitmap);
828
829 // Save the document, close the page.
830 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
831 FPDF_ClosePage(page);
832 std::string new_file = GetString();
833
834 // Render the saved result
835 FPDF_FILEACCESS file_access;
836 memset(&file_access, 0, sizeof(file_access));
837 file_access.m_FileLen = new_file.size();
838 file_access.m_GetBlock = GetBlockFromString;
839 file_access.m_Param = &new_file;
840 FPDF_DOCUMENT new_doc = FPDF_LoadCustomDocument(&file_access, nullptr);
841 ASSERT_NE(nullptr, new_doc);
842 EXPECT_EQ(1, FPDF_GetPageCount(new_doc));
843 FPDF_PAGE new_page = FPDF_LoadPage(new_doc, 0);
844 ASSERT_NE(nullptr, new_page);
845 FPDF_BITMAP new_bitmap = RenderPage(new_page);
846 CompareBitmap(new_bitmap, 612, 792, md5);
847 FPDFBitmap_Destroy(new_bitmap);
848 FPDF_ClosePage(new_page);
849 FPDF_CloseDocument(new_doc);
850}
851#endif // _FXM_PLATFORM_ == _FXM_PLATFORM_LINUX_