blob: 6045618411a1d363234be5a0f7064e6564a79520 [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
371TEST_F(FPDFEditEmbeddertest, AddStrokedPaths) {
372 // Start with a blank page
Nicolas Penad03ca422017-03-06 13:54:33 -0500373 FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
Nicolas Pena2eb1a702017-02-09 18:17:33 -0500374
375 // Add a large stroked rectangle (fill color should not affect it).
376 FPDF_PAGEOBJECT rect = FPDFPageObj_CreateNewRect(20, 20, 200, 400);
377 EXPECT_TRUE(FPDFPath_SetFillColor(rect, 255, 0, 0, 255));
378 EXPECT_TRUE(FPDFPath_SetStrokeColor(rect, 0, 255, 0, 255));
379 EXPECT_TRUE(FPDFPath_SetStrokeWidth(rect, 15.0f));
380 EXPECT_TRUE(FPDFPath_SetDrawMode(rect, 0, 1));
381 FPDFPage_InsertObject(page, rect);
Nicolas Pena2eb1a702017-02-09 18:17:33 -0500382 FPDF_BITMAP page_bitmap = RenderPage(page);
383 CompareBitmap(page_bitmap, 612, 792, "64bd31f862a89e0a9e505a5af6efd506");
384 FPDFBitmap_Destroy(page_bitmap);
385
386 // Add crossed-checkmark
387 FPDF_PAGEOBJECT check = FPDFPageObj_CreateNewPath(300, 500);
388 EXPECT_TRUE(FPDFPath_LineTo(check, 400, 400));
389 EXPECT_TRUE(FPDFPath_LineTo(check, 600, 600));
390 EXPECT_TRUE(FPDFPath_MoveTo(check, 400, 600));
391 EXPECT_TRUE(FPDFPath_LineTo(check, 600, 400));
392 EXPECT_TRUE(FPDFPath_SetStrokeColor(check, 128, 128, 128, 180));
393 EXPECT_TRUE(FPDFPath_SetStrokeWidth(check, 8.35f));
394 EXPECT_TRUE(FPDFPath_SetDrawMode(check, 0, 1));
395 FPDFPage_InsertObject(page, check);
Nicolas Pena2eb1a702017-02-09 18:17:33 -0500396 page_bitmap = RenderPage(page);
397 CompareBitmap(page_bitmap, 612, 792, "4b6f3b9d25c4e194821217d5016c3724");
398 FPDFBitmap_Destroy(page_bitmap);
399
400 // Add stroked and filled oval-ish path.
401 FPDF_PAGEOBJECT path = FPDFPageObj_CreateNewPath(250, 100);
402 EXPECT_TRUE(FPDFPath_BezierTo(path, 180, 166, 180, 233, 250, 300));
403 EXPECT_TRUE(FPDFPath_LineTo(path, 255, 305));
404 EXPECT_TRUE(FPDFPath_BezierTo(path, 325, 233, 325, 166, 255, 105));
405 EXPECT_TRUE(FPDFPath_Close(path));
406 EXPECT_TRUE(FPDFPath_SetFillColor(path, 200, 128, 128, 100));
407 EXPECT_TRUE(FPDFPath_SetStrokeColor(path, 128, 200, 128, 150));
408 EXPECT_TRUE(FPDFPath_SetStrokeWidth(path, 10.5f));
409 EXPECT_TRUE(FPDFPath_SetDrawMode(path, FPDF_FILLMODE_ALTERNATE, 1));
410 FPDFPage_InsertObject(page, path);
Nicolas Pena2eb1a702017-02-09 18:17:33 -0500411 page_bitmap = RenderPage(page);
412 CompareBitmap(page_bitmap, 612, 792, "ff3e6a22326754944cc6e56609acd73b");
413 FPDFBitmap_Destroy(page_bitmap);
414 FPDF_ClosePage(page);
Nicolas Pena2eb1a702017-02-09 18:17:33 -0500415}
Nicolas Pena49058402017-02-14 18:26:20 -0500416
417TEST_F(FPDFEditEmbeddertest, AddStandardFontText) {
418 // Start with a blank page
Nicolas Penad03ca422017-03-06 13:54:33 -0500419 FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
Nicolas Pena49058402017-02-14 18:26:20 -0500420
421 // Add some text to the page
Nicolas Penab3161852017-05-02 14:12:50 -0400422 FPDF_PAGEOBJECT text_object1 =
423 FPDFPageObj_NewTextObj(document(), "Arial", 12.0f);
424 EXPECT_TRUE(text_object1);
425 std::unique_ptr<unsigned short, pdfium::FreeDeleter> text1 =
426 GetFPDFWideString(L"I'm at the bottom of the page");
427 EXPECT_TRUE(FPDFText_SetText(text_object1, text1.get()));
428 FPDFPageObj_Transform(text_object1, 1, 0, 0, 1, 20, 20);
429 FPDFPage_InsertObject(page, text_object1);
Nicolas Pena49058402017-02-14 18:26:20 -0500430 FPDF_BITMAP page_bitmap = RenderPage(page);
431#if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
Lei Zhang0d6d1782017-03-24 15:52:00 -0700432 const char md5[] = "a4dddc1a3930fa694bbff9789dab4161";
Nicolas Pena49058402017-02-14 18:26:20 -0500433#else
Lei Zhang3de50052017-03-29 21:02:13 -0700434 const char md5[] = "6e8a9b0682f60fd3ff1bf087b093d30d";
Nicolas Pena5bcd9a32017-03-22 11:04:35 -0400435#endif
Lei Zhang0d6d1782017-03-24 15:52:00 -0700436 CompareBitmap(page_bitmap, 612, 792, md5);
Nicolas Pena49058402017-02-14 18:26:20 -0500437 FPDFBitmap_Destroy(page_bitmap);
438
439 // Try another font
Nicolas Penab3161852017-05-02 14:12:50 -0400440 FPDF_PAGEOBJECT text_object2 =
Nicolas Penad03ca422017-03-06 13:54:33 -0500441 FPDFPageObj_NewTextObj(document(), "TimesNewRomanBold", 15.0f);
Nicolas Penab3161852017-05-02 14:12:50 -0400442 EXPECT_TRUE(text_object2);
443 std::unique_ptr<unsigned short, pdfium::FreeDeleter> text2 =
444 GetFPDFWideString(L"Hi, I'm Bold. Times New Roman Bold.");
445 EXPECT_TRUE(FPDFText_SetText(text_object2, text2.get()));
446 FPDFPageObj_Transform(text_object2, 1, 0, 0, 1, 100, 600);
447 FPDFPage_InsertObject(page, text_object2);
Nicolas Pena49058402017-02-14 18:26:20 -0500448 page_bitmap = RenderPage(page);
449#if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
Lei Zhang0d6d1782017-03-24 15:52:00 -0700450 const char md5_2[] = "a5c4ace4c6f27644094813fe1441a21c";
Lei Zhang3de50052017-03-29 21:02:13 -0700451#elif _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_
452 const char md5_2[] = "56863642d4d8b418cfd810fdb5a5d92f";
Nicolas Pena49058402017-02-14 18:26:20 -0500453#else
Lei Zhang3de50052017-03-29 21:02:13 -0700454 const char md5_2[] = "0c83875429688bda45a55a692d5aa781";
Nicolas Pena5bcd9a32017-03-22 11:04:35 -0400455#endif
Lei Zhang0d6d1782017-03-24 15:52:00 -0700456 CompareBitmap(page_bitmap, 612, 792, md5_2);
Nicolas Pena49058402017-02-14 18:26:20 -0500457 FPDFBitmap_Destroy(page_bitmap);
458
459 // And some randomly transformed text
Nicolas Penab3161852017-05-02 14:12:50 -0400460 FPDF_PAGEOBJECT text_object3 =
Nicolas Penad03ca422017-03-06 13:54:33 -0500461 FPDFPageObj_NewTextObj(document(), "Courier-Bold", 20.0f);
Nicolas Penab3161852017-05-02 14:12:50 -0400462 EXPECT_TRUE(text_object3);
463 std::unique_ptr<unsigned short, pdfium::FreeDeleter> text3 =
464 GetFPDFWideString(L"Can you read me? <:)>");
465 EXPECT_TRUE(FPDFText_SetText(text_object3, text3.get()));
466 FPDFPageObj_Transform(text_object3, 1, 1.5, 2, 0.5, 200, 200);
467 FPDFPage_InsertObject(page, text_object3);
Nicolas Pena49058402017-02-14 18:26:20 -0500468 page_bitmap = RenderPage(page);
469#if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
Lei Zhang0d6d1782017-03-24 15:52:00 -0700470 const char md5_3[] = "40b3ef04f915ff4c4208948001763544";
Lei Zhang3de50052017-03-29 21:02:13 -0700471#elif _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_
Lei Zhangb8e89e32017-05-02 11:53:08 -0700472 const char md5_3[] = "d69d419def35a098d9c10f8317d6709b";
Nicolas Pena49058402017-02-14 18:26:20 -0500473#else
Lei Zhangb8e89e32017-05-02 11:53:08 -0700474 const char md5_3[] = "8b300d3c6dfc12fa9af97e12ed5bd80a";
Nicolas Pena5bcd9a32017-03-22 11:04:35 -0400475#endif
Lei Zhang0d6d1782017-03-24 15:52:00 -0700476 CompareBitmap(page_bitmap, 612, 792, md5_3);
Nicolas Pena49058402017-02-14 18:26:20 -0500477 FPDFBitmap_Destroy(page_bitmap);
478
479 // TODO(npm): Why are there issues with text rotated by 90 degrees?
480 // TODO(npm): FPDF_SaveAsCopy not giving the desired result after this.
481 FPDF_ClosePage(page);
Nicolas Pena49058402017-02-14 18:26:20 -0500482}
Nicolas Penaa4ad01f2017-02-15 16:26:48 -0500483
484TEST_F(FPDFEditEmbeddertest, DoubleGenerating) {
485 // Start with a blank page
Nicolas Penad03ca422017-03-06 13:54:33 -0500486 FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
Nicolas Penaa4ad01f2017-02-15 16:26:48 -0500487
488 // Add a red rectangle with some non-default alpha
489 FPDF_PAGEOBJECT rect = FPDFPageObj_CreateNewRect(10, 10, 100, 100);
490 EXPECT_TRUE(FPDFPath_SetFillColor(rect, 255, 0, 0, 128));
491 EXPECT_TRUE(FPDFPath_SetDrawMode(rect, FPDF_FILLMODE_WINDING, 0));
492 FPDFPage_InsertObject(page, rect);
493 EXPECT_TRUE(FPDFPage_GenerateContent(page));
494
495 // Check the ExtGState
496 CPDF_Page* the_page = CPDFPageFromFPDFPage(page);
497 CPDF_Dictionary* graphics_dict =
498 the_page->m_pResources->GetDictFor("ExtGState");
499 ASSERT_TRUE(graphics_dict);
500 EXPECT_EQ(1, static_cast<int>(graphics_dict->GetCount()));
501
502 // Check the bitmap
503 FPDF_BITMAP page_bitmap = RenderPage(page);
504 CompareBitmap(page_bitmap, 612, 792, "5384da3406d62360ffb5cac4476fff1c");
505 FPDFBitmap_Destroy(page_bitmap);
506
507 // Never mind, my new favorite color is blue, increase alpha
508 EXPECT_TRUE(FPDFPath_SetFillColor(rect, 0, 0, 255, 180));
509 EXPECT_TRUE(FPDFPage_GenerateContent(page));
510 EXPECT_EQ(2, static_cast<int>(graphics_dict->GetCount()));
511
512 // Check that bitmap displays changed content
513 page_bitmap = RenderPage(page);
514 CompareBitmap(page_bitmap, 612, 792, "2e51656f5073b0bee611d9cd086aa09c");
515 FPDFBitmap_Destroy(page_bitmap);
516
517 // And now generate, without changes
518 EXPECT_TRUE(FPDFPage_GenerateContent(page));
519 EXPECT_EQ(2, static_cast<int>(graphics_dict->GetCount()));
520 page_bitmap = RenderPage(page);
521 CompareBitmap(page_bitmap, 612, 792, "2e51656f5073b0bee611d9cd086aa09c");
522 FPDFBitmap_Destroy(page_bitmap);
523
524 // Add some text to the page
Nicolas Penab3161852017-05-02 14:12:50 -0400525 FPDF_PAGEOBJECT text_object =
526 FPDFPageObj_NewTextObj(document(), "Arial", 12.0f);
527 std::unique_ptr<unsigned short, pdfium::FreeDeleter> text =
528 GetFPDFWideString(L"Something something #text# something");
529 EXPECT_TRUE(FPDFText_SetText(text_object, text.get()));
530 FPDFPageObj_Transform(text_object, 1, 0, 0, 1, 300, 300);
531 FPDFPage_InsertObject(page, text_object);
Nicolas Penaa4ad01f2017-02-15 16:26:48 -0500532 EXPECT_TRUE(FPDFPage_GenerateContent(page));
533 CPDF_Dictionary* font_dict = the_page->m_pResources->GetDictFor("Font");
534 ASSERT_TRUE(font_dict);
535 EXPECT_EQ(1, static_cast<int>(font_dict->GetCount()));
536
537 // Generate yet again, check dicts are reasonably sized
538 EXPECT_TRUE(FPDFPage_GenerateContent(page));
539 EXPECT_EQ(2, static_cast<int>(graphics_dict->GetCount()));
540 EXPECT_EQ(1, static_cast<int>(font_dict->GetCount()));
541 FPDF_ClosePage(page);
Nicolas Penaa4ad01f2017-02-15 16:26:48 -0500542}
Nicolas Penabe90aae2017-02-27 10:41:41 -0500543
Nicolas Penad03ca422017-03-06 13:54:33 -0500544TEST_F(FPDFEditEmbeddertest, LoadSimpleType1Font) {
545 CreateNewDocument();
546 // TODO(npm): use other fonts after disallowing loading any font as any type
547 const CPDF_Font* stock_font =
548 CPDF_Font::GetStockFont(cpdf_doc(), "Times-Bold");
Lei Zhangd74da7b2017-05-04 13:30:29 -0700549 const uint8_t* data = stock_font->GetFont()->GetFontData();
550 const uint32_t size = stock_font->GetFont()->GetSize();
Nicolas Penab3161852017-05-02 14:12:50 -0400551 std::unique_ptr<void, FPDFFontDeleter> font(
552 FPDFText_LoadFont(document(), data, size, FPDF_FONT_TYPE1, false));
553 ASSERT_TRUE(font.get());
Nicolas Pena46abb662017-05-17 17:23:22 -0400554 CPDF_Font* typed_font = static_cast<CPDF_Font*>(font.get());
Nicolas Penad03ca422017-03-06 13:54:33 -0500555 EXPECT_TRUE(typed_font->IsType1Font());
Nicolas Penabe90aae2017-02-27 10:41:41 -0500556
Nicolas Penad03ca422017-03-06 13:54:33 -0500557 CPDF_Dictionary* font_dict = typed_font->GetFontDict();
Nicolas Penabe90aae2017-02-27 10:41:41 -0500558 EXPECT_EQ("Font", font_dict->GetStringFor("Type"));
559 EXPECT_EQ("Type1", font_dict->GetStringFor("Subtype"));
560 EXPECT_EQ("Times New Roman Bold", font_dict->GetStringFor("BaseFont"));
561 ASSERT_TRUE(font_dict->KeyExist("FirstChar"));
562 ASSERT_TRUE(font_dict->KeyExist("LastChar"));
563 EXPECT_EQ(32, font_dict->GetIntegerFor("FirstChar"));
Nicolas Penad03ca422017-03-06 13:54:33 -0500564 EXPECT_EQ(255, font_dict->GetIntegerFor("LastChar"));
565
Nicolas Penabe90aae2017-02-27 10:41:41 -0500566 CPDF_Array* widths_array = font_dict->GetArrayFor("Widths");
Nicolas Penad03ca422017-03-06 13:54:33 -0500567 ASSERT_TRUE(widths_array);
568 ASSERT_EQ(224U, widths_array->GetCount());
Nicolas Penabe90aae2017-02-27 10:41:41 -0500569 EXPECT_EQ(250, widths_array->GetNumberAt(0));
Nicolas Penad03ca422017-03-06 13:54:33 -0500570 EXPECT_EQ(569, widths_array->GetNumberAt(11));
571 EXPECT_EQ(500, widths_array->GetNumberAt(223));
572 CheckFontDescriptor(font_dict, FPDF_FONT_TYPE1, true, false, size, data);
573}
Nicolas Penabe90aae2017-02-27 10:41:41 -0500574
Nicolas Penad03ca422017-03-06 13:54:33 -0500575TEST_F(FPDFEditEmbeddertest, LoadSimpleTrueTypeFont) {
576 CreateNewDocument();
577 const CPDF_Font* stock_font = CPDF_Font::GetStockFont(cpdf_doc(), "Courier");
Lei Zhangd74da7b2017-05-04 13:30:29 -0700578 const uint8_t* data = stock_font->GetFont()->GetFontData();
579 const uint32_t size = stock_font->GetFont()->GetSize();
Nicolas Penab3161852017-05-02 14:12:50 -0400580 std::unique_ptr<void, FPDFFontDeleter> font(
581 FPDFText_LoadFont(document(), data, size, FPDF_FONT_TRUETYPE, false));
582 ASSERT_TRUE(font.get());
Nicolas Pena46abb662017-05-17 17:23:22 -0400583 CPDF_Font* typed_font = static_cast<CPDF_Font*>(font.get());
Nicolas Penad03ca422017-03-06 13:54:33 -0500584 EXPECT_TRUE(typed_font->IsTrueTypeFont());
Nicolas Penabe90aae2017-02-27 10:41:41 -0500585
Nicolas Penad03ca422017-03-06 13:54:33 -0500586 CPDF_Dictionary* font_dict = typed_font->GetFontDict();
587 EXPECT_EQ("Font", font_dict->GetStringFor("Type"));
588 EXPECT_EQ("TrueType", font_dict->GetStringFor("Subtype"));
589 EXPECT_EQ("Courier New", font_dict->GetStringFor("BaseFont"));
590 ASSERT_TRUE(font_dict->KeyExist("FirstChar"));
591 ASSERT_TRUE(font_dict->KeyExist("LastChar"));
592 EXPECT_EQ(32, font_dict->GetIntegerFor("FirstChar"));
593 EXPECT_EQ(255, font_dict->GetIntegerFor("LastChar"));
Nicolas Penabe90aae2017-02-27 10:41:41 -0500594
Nicolas Penad03ca422017-03-06 13:54:33 -0500595 CPDF_Array* widths_array = font_dict->GetArrayFor("Widths");
596 ASSERT_TRUE(widths_array);
597 ASSERT_EQ(224U, widths_array->GetCount());
598 EXPECT_EQ(600, widths_array->GetNumberAt(33));
599 EXPECT_EQ(600, widths_array->GetNumberAt(74));
600 EXPECT_EQ(600, widths_array->GetNumberAt(223));
601 CheckFontDescriptor(font_dict, FPDF_FONT_TRUETYPE, false, false, size, data);
602}
603
604TEST_F(FPDFEditEmbeddertest, LoadCIDType0Font) {
605 CreateNewDocument();
606 const CPDF_Font* stock_font =
607 CPDF_Font::GetStockFont(cpdf_doc(), "Times-Roman");
Lei Zhangd74da7b2017-05-04 13:30:29 -0700608 const uint8_t* data = stock_font->GetFont()->GetFontData();
609 const uint32_t size = stock_font->GetFont()->GetSize();
Nicolas Penab3161852017-05-02 14:12:50 -0400610 std::unique_ptr<void, FPDFFontDeleter> font(
611 FPDFText_LoadFont(document(), data, size, FPDF_FONT_TYPE1, 1));
612 ASSERT_TRUE(font.get());
Nicolas Pena46abb662017-05-17 17:23:22 -0400613 CPDF_Font* typed_font = static_cast<CPDF_Font*>(font.get());
Nicolas Penad03ca422017-03-06 13:54:33 -0500614 EXPECT_TRUE(typed_font->IsCIDFont());
615
616 // Check font dictionary entries
617 CPDF_Dictionary* font_dict = typed_font->GetFontDict();
618 EXPECT_EQ("Font", font_dict->GetStringFor("Type"));
619 EXPECT_EQ("Type0", font_dict->GetStringFor("Subtype"));
620 EXPECT_EQ("Times New Roman-Identity-H", font_dict->GetStringFor("BaseFont"));
621 EXPECT_EQ("Identity-H", font_dict->GetStringFor("Encoding"));
622 CPDF_Array* descendant_array = font_dict->GetArrayFor("DescendantFonts");
623 ASSERT_TRUE(descendant_array);
624 EXPECT_EQ(1U, descendant_array->GetCount());
625
626 // Check the CIDFontDict
627 CPDF_Dictionary* cidfont_dict = descendant_array->GetDictAt(0);
628 EXPECT_EQ("Font", cidfont_dict->GetStringFor("Type"));
629 EXPECT_EQ("CIDFontType0", cidfont_dict->GetStringFor("Subtype"));
630 EXPECT_EQ("Times New Roman", cidfont_dict->GetStringFor("BaseFont"));
631 CPDF_Dictionary* cidinfo_dict = cidfont_dict->GetDictFor("CIDSystemInfo");
632 ASSERT_TRUE(cidinfo_dict);
633 EXPECT_EQ("Adobe", cidinfo_dict->GetStringFor("Registry"));
634 EXPECT_EQ("Identity", cidinfo_dict->GetStringFor("Ordering"));
635 EXPECT_EQ(0, cidinfo_dict->GetNumberFor("Supplement"));
636 CheckFontDescriptor(cidfont_dict, FPDF_FONT_TYPE1, false, false, size, data);
637
638 // Check widths
639 CPDF_Array* widths_array = cidfont_dict->GetArrayFor("W");
640 ASSERT_TRUE(widths_array);
Nicolas Penaf45ade32017-05-03 10:23:49 -0400641 EXPECT_GT(widths_array->GetCount(), 1U);
Nicolas Penad03ca422017-03-06 13:54:33 -0500642 CheckCompositeFontWidths(widths_array, typed_font);
643}
644
645TEST_F(FPDFEditEmbeddertest, LoadCIDType2Font) {
646 CreateNewDocument();
647 const CPDF_Font* stock_font =
648 CPDF_Font::GetStockFont(cpdf_doc(), "Helvetica-Oblique");
Lei Zhangd74da7b2017-05-04 13:30:29 -0700649 const uint8_t* data = stock_font->GetFont()->GetFontData();
650 const uint32_t size = stock_font->GetFont()->GetSize();
Nicolas Penad03ca422017-03-06 13:54:33 -0500651
Nicolas Penab3161852017-05-02 14:12:50 -0400652 std::unique_ptr<void, FPDFFontDeleter> font(
653 FPDFText_LoadFont(document(), data, size, FPDF_FONT_TRUETYPE, 1));
654 ASSERT_TRUE(font.get());
Nicolas Pena46abb662017-05-17 17:23:22 -0400655 CPDF_Font* typed_font = static_cast<CPDF_Font*>(font.get());
Nicolas Penad03ca422017-03-06 13:54:33 -0500656 EXPECT_TRUE(typed_font->IsCIDFont());
657
658 // Check font dictionary entries
659 CPDF_Dictionary* font_dict = typed_font->GetFontDict();
660 EXPECT_EQ("Font", font_dict->GetStringFor("Type"));
661 EXPECT_EQ("Type0", font_dict->GetStringFor("Subtype"));
662 EXPECT_EQ("Arial Italic", font_dict->GetStringFor("BaseFont"));
663 EXPECT_EQ("Identity-H", font_dict->GetStringFor("Encoding"));
664 CPDF_Array* descendant_array = font_dict->GetArrayFor("DescendantFonts");
665 ASSERT_TRUE(descendant_array);
666 EXPECT_EQ(1U, descendant_array->GetCount());
667
668 // Check the CIDFontDict
669 CPDF_Dictionary* cidfont_dict = descendant_array->GetDictAt(0);
670 EXPECT_EQ("Font", cidfont_dict->GetStringFor("Type"));
671 EXPECT_EQ("CIDFontType2", cidfont_dict->GetStringFor("Subtype"));
672 EXPECT_EQ("Arial Italic", cidfont_dict->GetStringFor("BaseFont"));
673 CPDF_Dictionary* cidinfo_dict = cidfont_dict->GetDictFor("CIDSystemInfo");
674 ASSERT_TRUE(cidinfo_dict);
675 EXPECT_EQ("Adobe", cidinfo_dict->GetStringFor("Registry"));
676 EXPECT_EQ("Identity", cidinfo_dict->GetStringFor("Ordering"));
677 EXPECT_EQ(0, cidinfo_dict->GetNumberFor("Supplement"));
678 CheckFontDescriptor(cidfont_dict, FPDF_FONT_TRUETYPE, false, true, size,
679 data);
680
681 // Check widths
682 CPDF_Array* widths_array = cidfont_dict->GetArrayFor("W");
683 ASSERT_TRUE(widths_array);
684 CheckCompositeFontWidths(widths_array, typed_font);
Nicolas Penabe90aae2017-02-27 10:41:41 -0500685}
rbpotterce8e51e2017-04-28 12:42:47 -0700686
687TEST_F(FPDFEditEmbeddertest, NormalizeNegativeRotation) {
688 // Load document with a -90 degree rotation
689 EXPECT_TRUE(OpenDocument("bug_713197.pdf"));
690 FPDF_PAGE page = LoadPage(0);
691 EXPECT_NE(nullptr, page);
692
693 EXPECT_EQ(3, FPDFPage_GetRotation(page));
694 UnloadPage(page);
695}
Nicolas Penab3161852017-05-02 14:12:50 -0400696
697TEST_F(FPDFEditEmbeddertest, AddTrueTypeFontText) {
698 // Start with a blank page
699 FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
700 {
701 const CPDF_Font* stock_font = CPDF_Font::GetStockFont(cpdf_doc(), "Arial");
Lei Zhangd74da7b2017-05-04 13:30:29 -0700702 const uint8_t* data = stock_font->GetFont()->GetFontData();
703 const uint32_t size = stock_font->GetFont()->GetSize();
Nicolas Penab3161852017-05-02 14:12:50 -0400704 std::unique_ptr<void, FPDFFontDeleter> font(
705 FPDFText_LoadFont(document(), data, size, FPDF_FONT_TRUETYPE, 0));
706 ASSERT_TRUE(font.get());
707
708 // Add some text to the page
709 FPDF_PAGEOBJECT text_object =
710 FPDFPageObj_CreateTextObj(document(), font.get(), 12.0f);
711 EXPECT_TRUE(text_object);
712 std::unique_ptr<unsigned short, pdfium::FreeDeleter> text =
713 GetFPDFWideString(L"I am testing my loaded font, WEE.");
714 EXPECT_TRUE(FPDFText_SetText(text_object, text.get()));
715 FPDFPageObj_Transform(text_object, 1, 0, 0, 1, 400, 400);
716 FPDFPage_InsertObject(page, text_object);
Nicolas Penab3161852017-05-02 14:12:50 -0400717 FPDF_BITMAP page_bitmap = RenderPage(page);
718#if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
719 const char md5[] = "17d2b6cd574cf66170b09c8927529a94";
720#else
721 const char md5[] = "28e5b10743660dcdfd1618db47b39d32";
722#endif // _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
723 CompareBitmap(page_bitmap, 612, 792, md5);
724 FPDFBitmap_Destroy(page_bitmap);
725
726 // Add some more text, same font
727 FPDF_PAGEOBJECT text_object2 =
728 FPDFPageObj_CreateTextObj(document(), font.get(), 15.0f);
729 std::unique_ptr<unsigned short, pdfium::FreeDeleter> text2 =
730 GetFPDFWideString(L"Bigger font size");
731 EXPECT_TRUE(FPDFText_SetText(text_object2, text2.get()));
732 FPDFPageObj_Transform(text_object2, 1, 0, 0, 1, 200, 200);
733 FPDFPage_InsertObject(page, text_object2);
Nicolas Penab3161852017-05-02 14:12:50 -0400734 }
735 FPDF_BITMAP page_bitmap2 = RenderPage(page);
736#if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
737 const char md5_2[] = "8eded4193ff1f0f77b8b600a825e97ea";
738#else
739 const char md5_2[] = "a068eef4110d607f77c87ea8340fa2a5";
740#endif // _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
741 CompareBitmap(page_bitmap2, 612, 792, md5_2);
742 FPDFBitmap_Destroy(page_bitmap2);
743
Nicolas Pena207b7272017-05-26 17:37:06 -0400744 EXPECT_TRUE(FPDFPage_GenerateContent(page));
Nicolas Penab3161852017-05-02 14:12:50 -0400745 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
746 FPDF_ClosePage(page);
747 std::string new_file = GetString();
748
749 // Render the saved result
750 FPDF_FILEACCESS file_access;
751 memset(&file_access, 0, sizeof(file_access));
752 file_access.m_FileLen = new_file.size();
753 file_access.m_GetBlock = GetBlockFromString;
754 file_access.m_Param = &new_file;
755 FPDF_DOCUMENT new_doc = FPDF_LoadCustomDocument(&file_access, nullptr);
756 ASSERT_NE(nullptr, new_doc);
757 EXPECT_EQ(1, FPDF_GetPageCount(new_doc));
758 FPDF_PAGE new_page = FPDF_LoadPage(new_doc, 0);
759 ASSERT_NE(nullptr, new_page);
760 FPDF_BITMAP new_bitmap = RenderPage(new_page);
761 CompareBitmap(new_bitmap, 612, 792, md5_2);
762 FPDFBitmap_Destroy(new_bitmap);
763 FPDF_ClosePage(new_page);
764 FPDF_CloseDocument(new_doc);
765}
Nicolas Penaf45ade32017-05-03 10:23:49 -0400766
767// TODO(npm): Add tests using Japanese fonts in other OS.
768#if _FXM_PLATFORM_ == _FXM_PLATFORM_LINUX_
769TEST_F(FPDFEditEmbeddertest, AddCIDFontText) {
770 // Start with a blank page
771 FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
772 CFX_Font CIDfont;
773 {
774 // First, get the data from the font
775 CIDfont.LoadSubst("IPAGothic", 1, 0, 400, 0, 932, 0);
776 EXPECT_EQ("IPAGothic", CIDfont.GetFaceName());
777 const uint8_t* data = CIDfont.GetFontData();
778 const uint32_t size = CIDfont.GetSize();
779
780 // Load the data into a FPDF_Font.
781 std::unique_ptr<void, FPDFFontDeleter> font(
782 FPDFText_LoadFont(document(), data, size, FPDF_FONT_TRUETYPE, 1));
783 ASSERT_TRUE(font.get());
784
785 // Add some text to the page
786 FPDF_PAGEOBJECT text_object =
787 FPDFPageObj_CreateTextObj(document(), font.get(), 12.0f);
788 ASSERT_TRUE(text_object);
789 std::wstring wstr = L"ABCDEFGhijklmnop.";
790 std::unique_ptr<unsigned short, pdfium::FreeDeleter> text =
791 GetFPDFWideString(wstr);
792 EXPECT_TRUE(FPDFText_SetText(text_object, text.get()));
793 FPDFPageObj_Transform(text_object, 1, 0, 0, 1, 200, 200);
794 FPDFPage_InsertObject(page, text_object);
795
796 // And add some Japanese characters
797 FPDF_PAGEOBJECT text_object2 =
798 FPDFPageObj_CreateTextObj(document(), font.get(), 18.0f);
799 ASSERT_TRUE(text_object2);
800 std::wstring wstr2 =
801 L"\u3053\u3093\u306B\u3061\u306f\u4e16\u754C\u3002\u3053\u3053\u306B1"
802 L"\u756A";
803 std::unique_ptr<unsigned short, pdfium::FreeDeleter> text2 =
804 GetFPDFWideString(wstr2);
805 EXPECT_TRUE(FPDFText_SetText(text_object2, text2.get()));
806 FPDFPageObj_Transform(text_object2, 1, 0, 0, 1, 100, 500);
807 FPDFPage_InsertObject(page, text_object2);
808 }
809
Nicolas Pena207b7272017-05-26 17:37:06 -0400810 // Check that the text renders properly.
Nicolas Penaf45ade32017-05-03 10:23:49 -0400811 FPDF_BITMAP page_bitmap = RenderPage(page);
812 const char md5[] = "2bc6c1aaa2252e73246a75775ccf38c2";
813 CompareBitmap(page_bitmap, 612, 792, md5);
814 FPDFBitmap_Destroy(page_bitmap);
815
816 // Save the document, close the page.
Nicolas Pena207b7272017-05-26 17:37:06 -0400817 EXPECT_TRUE(FPDFPage_GenerateContent(page));
Nicolas Penaf45ade32017-05-03 10:23:49 -0400818 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
819 FPDF_ClosePage(page);
820 std::string new_file = GetString();
821
822 // Render the saved result
823 FPDF_FILEACCESS file_access;
824 memset(&file_access, 0, sizeof(file_access));
825 file_access.m_FileLen = new_file.size();
826 file_access.m_GetBlock = GetBlockFromString;
827 file_access.m_Param = &new_file;
828 FPDF_DOCUMENT new_doc = FPDF_LoadCustomDocument(&file_access, nullptr);
829 ASSERT_NE(nullptr, new_doc);
830 EXPECT_EQ(1, FPDF_GetPageCount(new_doc));
831 FPDF_PAGE new_page = FPDF_LoadPage(new_doc, 0);
832 ASSERT_NE(nullptr, new_page);
833 FPDF_BITMAP new_bitmap = RenderPage(new_page);
834 CompareBitmap(new_bitmap, 612, 792, md5);
835 FPDFBitmap_Destroy(new_bitmap);
836 FPDF_ClosePage(new_page);
837 FPDF_CloseDocument(new_doc);
838}
839#endif // _FXM_PLATFORM_ == _FXM_PLATFORM_LINUX_