blob: 383e207f5439eac11f8fb3e9e5cfff7542a3eb73 [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();
29 cpdf_doc_ = reinterpret_cast<CPDF_Document*>(document_);
30 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
268 // Make sure we get back the same color we set previously.
269 unsigned int R;
270 unsigned int G;
271 unsigned int B;
272 unsigned int A;
273 EXPECT_TRUE(FPDFPath_GetFillColor(green_rect, &R, &G, &B, &A));
274 EXPECT_EQ(0U, R);
275 EXPECT_EQ(255U, G);
276 EXPECT_EQ(0U, B);
277 EXPECT_EQ(128U, A);
278
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500279 EXPECT_TRUE(FPDFPath_SetDrawMode(green_rect, FPDF_FILLMODE_WINDING, 0));
280 FPDFPage_InsertObject(page, green_rect);
281 EXPECT_TRUE(FPDFPage_GenerateContent(page));
282 page_bitmap = RenderPage(page);
283 CompareBitmap(page_bitmap, 612, 792, "7b0b87604594e773add528fae567a558");
284 FPDFBitmap_Destroy(page_bitmap);
285
286 // Add a black triangle.
287 FPDF_PAGEOBJECT black_path = FPDFPageObj_CreateNewPath(400, 100);
288 EXPECT_TRUE(FPDFPath_SetFillColor(black_path, 0, 0, 0, 200));
289 EXPECT_TRUE(FPDFPath_SetDrawMode(black_path, FPDF_FILLMODE_ALTERNATE, 0));
290 EXPECT_TRUE(FPDFPath_LineTo(black_path, 400, 200));
291 EXPECT_TRUE(FPDFPath_LineTo(black_path, 300, 100));
292 EXPECT_TRUE(FPDFPath_Close(black_path));
293 FPDFPage_InsertObject(page, black_path);
294 EXPECT_TRUE(FPDFPage_GenerateContent(page));
295 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);
310 EXPECT_TRUE(FPDFPage_GenerateContent(page));
311 page_bitmap = RenderPage(page);
312 CompareBitmap(page_bitmap, 612, 792, "9823e1a21bd9b72b6a442ba4f12af946");
313 FPDFBitmap_Destroy(page_bitmap);
314
315 // Now save the result, closing the page and document
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);
349 EXPECT_TRUE(FPDFPage_GenerateContent(page));
350
351 // Add a transparent triangle on top of other part of the text.
352 FPDF_PAGEOBJECT black_path = FPDFPageObj_CreateNewPath(20, 50);
353 EXPECT_TRUE(FPDFPath_SetFillColor(black_path, 0, 0, 0, 100));
354 EXPECT_TRUE(FPDFPath_SetDrawMode(black_path, FPDF_FILLMODE_ALTERNATE, 0));
355 EXPECT_TRUE(FPDFPath_LineTo(black_path, 30, 80));
356 EXPECT_TRUE(FPDFPath_LineTo(black_path, 40, 10));
357 EXPECT_TRUE(FPDFPath_Close(black_path));
358 FPDFPage_InsertObject(page, black_path);
359 EXPECT_TRUE(FPDFPage_GenerateContent(page));
360
361 // Render and check the result. Text is slightly different on Mac.
362 FPDF_BITMAP bitmap = RenderPage(page);
363#if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
Lei Zhang0d6d1782017-03-24 15:52:00 -0700364 const char md5[] = "f9e6fa74230f234286bfcada9f7606d8";
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500365#else
Lei Zhang3de50052017-03-29 21:02:13 -0700366 const char md5[] = "2fdfc5dda29374cfba4349362e38ebdb";
Nicolas Pena5bcd9a32017-03-22 11:04:35 -0400367#endif
Lei Zhang0d6d1782017-03-24 15:52:00 -0700368 CompareBitmap(bitmap, 200, 200, md5);
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500369 FPDFBitmap_Destroy(bitmap);
370 UnloadPage(page);
371}
Nicolas Pena2eb1a702017-02-09 18:17:33 -0500372
373TEST_F(FPDFEditEmbeddertest, AddStrokedPaths) {
374 // Start with a blank page
Nicolas Penad03ca422017-03-06 13:54:33 -0500375 FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
Nicolas Pena2eb1a702017-02-09 18:17:33 -0500376
377 // Add a large stroked rectangle (fill color should not affect it).
378 FPDF_PAGEOBJECT rect = FPDFPageObj_CreateNewRect(20, 20, 200, 400);
379 EXPECT_TRUE(FPDFPath_SetFillColor(rect, 255, 0, 0, 255));
380 EXPECT_TRUE(FPDFPath_SetStrokeColor(rect, 0, 255, 0, 255));
381 EXPECT_TRUE(FPDFPath_SetStrokeWidth(rect, 15.0f));
382 EXPECT_TRUE(FPDFPath_SetDrawMode(rect, 0, 1));
383 FPDFPage_InsertObject(page, rect);
384 EXPECT_TRUE(FPDFPage_GenerateContent(page));
385 FPDF_BITMAP page_bitmap = RenderPage(page);
386 CompareBitmap(page_bitmap, 612, 792, "64bd31f862a89e0a9e505a5af6efd506");
387 FPDFBitmap_Destroy(page_bitmap);
388
389 // Add crossed-checkmark
390 FPDF_PAGEOBJECT check = FPDFPageObj_CreateNewPath(300, 500);
391 EXPECT_TRUE(FPDFPath_LineTo(check, 400, 400));
392 EXPECT_TRUE(FPDFPath_LineTo(check, 600, 600));
393 EXPECT_TRUE(FPDFPath_MoveTo(check, 400, 600));
394 EXPECT_TRUE(FPDFPath_LineTo(check, 600, 400));
395 EXPECT_TRUE(FPDFPath_SetStrokeColor(check, 128, 128, 128, 180));
396 EXPECT_TRUE(FPDFPath_SetStrokeWidth(check, 8.35f));
397 EXPECT_TRUE(FPDFPath_SetDrawMode(check, 0, 1));
398 FPDFPage_InsertObject(page, check);
399 EXPECT_TRUE(FPDFPage_GenerateContent(page));
400 page_bitmap = RenderPage(page);
401 CompareBitmap(page_bitmap, 612, 792, "4b6f3b9d25c4e194821217d5016c3724");
402 FPDFBitmap_Destroy(page_bitmap);
403
404 // Add stroked and filled oval-ish path.
405 FPDF_PAGEOBJECT path = FPDFPageObj_CreateNewPath(250, 100);
406 EXPECT_TRUE(FPDFPath_BezierTo(path, 180, 166, 180, 233, 250, 300));
407 EXPECT_TRUE(FPDFPath_LineTo(path, 255, 305));
408 EXPECT_TRUE(FPDFPath_BezierTo(path, 325, 233, 325, 166, 255, 105));
409 EXPECT_TRUE(FPDFPath_Close(path));
410 EXPECT_TRUE(FPDFPath_SetFillColor(path, 200, 128, 128, 100));
411 EXPECT_TRUE(FPDFPath_SetStrokeColor(path, 128, 200, 128, 150));
412 EXPECT_TRUE(FPDFPath_SetStrokeWidth(path, 10.5f));
413 EXPECT_TRUE(FPDFPath_SetDrawMode(path, FPDF_FILLMODE_ALTERNATE, 1));
414 FPDFPage_InsertObject(page, path);
415 EXPECT_TRUE(FPDFPage_GenerateContent(page));
416 page_bitmap = RenderPage(page);
417 CompareBitmap(page_bitmap, 612, 792, "ff3e6a22326754944cc6e56609acd73b");
418 FPDFBitmap_Destroy(page_bitmap);
419 FPDF_ClosePage(page);
Nicolas Pena2eb1a702017-02-09 18:17:33 -0500420}
Nicolas Pena49058402017-02-14 18:26:20 -0500421
422TEST_F(FPDFEditEmbeddertest, AddStandardFontText) {
423 // Start with a blank page
Nicolas Penad03ca422017-03-06 13:54:33 -0500424 FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
Nicolas Pena49058402017-02-14 18:26:20 -0500425
426 // Add some text to the page
Nicolas Penab3161852017-05-02 14:12:50 -0400427 FPDF_PAGEOBJECT text_object1 =
428 FPDFPageObj_NewTextObj(document(), "Arial", 12.0f);
429 EXPECT_TRUE(text_object1);
430 std::unique_ptr<unsigned short, pdfium::FreeDeleter> text1 =
431 GetFPDFWideString(L"I'm at the bottom of the page");
432 EXPECT_TRUE(FPDFText_SetText(text_object1, text1.get()));
433 FPDFPageObj_Transform(text_object1, 1, 0, 0, 1, 20, 20);
434 FPDFPage_InsertObject(page, text_object1);
Nicolas Pena49058402017-02-14 18:26:20 -0500435 EXPECT_TRUE(FPDFPage_GenerateContent(page));
436 FPDF_BITMAP page_bitmap = RenderPage(page);
437#if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
Lei Zhang0d6d1782017-03-24 15:52:00 -0700438 const char md5[] = "a4dddc1a3930fa694bbff9789dab4161";
Nicolas Pena49058402017-02-14 18:26:20 -0500439#else
Lei Zhang3de50052017-03-29 21:02:13 -0700440 const char md5[] = "6e8a9b0682f60fd3ff1bf087b093d30d";
Nicolas Pena5bcd9a32017-03-22 11:04:35 -0400441#endif
Lei Zhang0d6d1782017-03-24 15:52:00 -0700442 CompareBitmap(page_bitmap, 612, 792, md5);
Nicolas Pena49058402017-02-14 18:26:20 -0500443 FPDFBitmap_Destroy(page_bitmap);
444
445 // Try another font
Nicolas Penab3161852017-05-02 14:12:50 -0400446 FPDF_PAGEOBJECT text_object2 =
Nicolas Penad03ca422017-03-06 13:54:33 -0500447 FPDFPageObj_NewTextObj(document(), "TimesNewRomanBold", 15.0f);
Nicolas Penab3161852017-05-02 14:12:50 -0400448 EXPECT_TRUE(text_object2);
449 std::unique_ptr<unsigned short, pdfium::FreeDeleter> text2 =
450 GetFPDFWideString(L"Hi, I'm Bold. Times New Roman Bold.");
451 EXPECT_TRUE(FPDFText_SetText(text_object2, text2.get()));
452 FPDFPageObj_Transform(text_object2, 1, 0, 0, 1, 100, 600);
453 FPDFPage_InsertObject(page, text_object2);
Nicolas Pena49058402017-02-14 18:26:20 -0500454 EXPECT_TRUE(FPDFPage_GenerateContent(page));
455 page_bitmap = RenderPage(page);
456#if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
Lei Zhang0d6d1782017-03-24 15:52:00 -0700457 const char md5_2[] = "a5c4ace4c6f27644094813fe1441a21c";
Lei Zhang3de50052017-03-29 21:02:13 -0700458#elif _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_
459 const char md5_2[] = "56863642d4d8b418cfd810fdb5a5d92f";
Nicolas Pena49058402017-02-14 18:26:20 -0500460#else
Lei Zhang3de50052017-03-29 21:02:13 -0700461 const char md5_2[] = "0c83875429688bda45a55a692d5aa781";
Nicolas Pena5bcd9a32017-03-22 11:04:35 -0400462#endif
Lei Zhang0d6d1782017-03-24 15:52:00 -0700463 CompareBitmap(page_bitmap, 612, 792, md5_2);
Nicolas Pena49058402017-02-14 18:26:20 -0500464 FPDFBitmap_Destroy(page_bitmap);
465
466 // And some randomly transformed text
Nicolas Penab3161852017-05-02 14:12:50 -0400467 FPDF_PAGEOBJECT text_object3 =
Nicolas Penad03ca422017-03-06 13:54:33 -0500468 FPDFPageObj_NewTextObj(document(), "Courier-Bold", 20.0f);
Nicolas Penab3161852017-05-02 14:12:50 -0400469 EXPECT_TRUE(text_object3);
470 std::unique_ptr<unsigned short, pdfium::FreeDeleter> text3 =
471 GetFPDFWideString(L"Can you read me? <:)>");
472 EXPECT_TRUE(FPDFText_SetText(text_object3, text3.get()));
473 FPDFPageObj_Transform(text_object3, 1, 1.5, 2, 0.5, 200, 200);
474 FPDFPage_InsertObject(page, text_object3);
Nicolas Pena49058402017-02-14 18:26:20 -0500475 EXPECT_TRUE(FPDFPage_GenerateContent(page));
476 page_bitmap = RenderPage(page);
477#if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
Lei Zhang0d6d1782017-03-24 15:52:00 -0700478 const char md5_3[] = "40b3ef04f915ff4c4208948001763544";
Lei Zhang3de50052017-03-29 21:02:13 -0700479#elif _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_
Lei Zhangb8e89e32017-05-02 11:53:08 -0700480 const char md5_3[] = "d69d419def35a098d9c10f8317d6709b";
Nicolas Pena49058402017-02-14 18:26:20 -0500481#else
Lei Zhangb8e89e32017-05-02 11:53:08 -0700482 const char md5_3[] = "8b300d3c6dfc12fa9af97e12ed5bd80a";
Nicolas Pena5bcd9a32017-03-22 11:04:35 -0400483#endif
Lei Zhang0d6d1782017-03-24 15:52:00 -0700484 CompareBitmap(page_bitmap, 612, 792, md5_3);
Nicolas Pena49058402017-02-14 18:26:20 -0500485 FPDFBitmap_Destroy(page_bitmap);
486
487 // TODO(npm): Why are there issues with text rotated by 90 degrees?
488 // TODO(npm): FPDF_SaveAsCopy not giving the desired result after this.
489 FPDF_ClosePage(page);
Nicolas Pena49058402017-02-14 18:26:20 -0500490}
Nicolas Penaa4ad01f2017-02-15 16:26:48 -0500491
492TEST_F(FPDFEditEmbeddertest, DoubleGenerating) {
493 // Start with a blank page
Nicolas Penad03ca422017-03-06 13:54:33 -0500494 FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
Nicolas Penaa4ad01f2017-02-15 16:26:48 -0500495
496 // Add a red rectangle with some non-default alpha
497 FPDF_PAGEOBJECT rect = FPDFPageObj_CreateNewRect(10, 10, 100, 100);
498 EXPECT_TRUE(FPDFPath_SetFillColor(rect, 255, 0, 0, 128));
499 EXPECT_TRUE(FPDFPath_SetDrawMode(rect, FPDF_FILLMODE_WINDING, 0));
500 FPDFPage_InsertObject(page, rect);
501 EXPECT_TRUE(FPDFPage_GenerateContent(page));
502
503 // Check the ExtGState
504 CPDF_Page* the_page = CPDFPageFromFPDFPage(page);
505 CPDF_Dictionary* graphics_dict =
506 the_page->m_pResources->GetDictFor("ExtGState");
507 ASSERT_TRUE(graphics_dict);
508 EXPECT_EQ(1, static_cast<int>(graphics_dict->GetCount()));
509
510 // Check the bitmap
511 FPDF_BITMAP page_bitmap = RenderPage(page);
512 CompareBitmap(page_bitmap, 612, 792, "5384da3406d62360ffb5cac4476fff1c");
513 FPDFBitmap_Destroy(page_bitmap);
514
515 // Never mind, my new favorite color is blue, increase alpha
516 EXPECT_TRUE(FPDFPath_SetFillColor(rect, 0, 0, 255, 180));
517 EXPECT_TRUE(FPDFPage_GenerateContent(page));
518 EXPECT_EQ(2, static_cast<int>(graphics_dict->GetCount()));
519
520 // Check that bitmap displays changed content
521 page_bitmap = RenderPage(page);
522 CompareBitmap(page_bitmap, 612, 792, "2e51656f5073b0bee611d9cd086aa09c");
523 FPDFBitmap_Destroy(page_bitmap);
524
525 // And now generate, without changes
526 EXPECT_TRUE(FPDFPage_GenerateContent(page));
527 EXPECT_EQ(2, static_cast<int>(graphics_dict->GetCount()));
528 page_bitmap = RenderPage(page);
529 CompareBitmap(page_bitmap, 612, 792, "2e51656f5073b0bee611d9cd086aa09c");
530 FPDFBitmap_Destroy(page_bitmap);
531
532 // Add some text to the page
Nicolas Penab3161852017-05-02 14:12:50 -0400533 FPDF_PAGEOBJECT text_object =
534 FPDFPageObj_NewTextObj(document(), "Arial", 12.0f);
535 std::unique_ptr<unsigned short, pdfium::FreeDeleter> text =
536 GetFPDFWideString(L"Something something #text# something");
537 EXPECT_TRUE(FPDFText_SetText(text_object, text.get()));
538 FPDFPageObj_Transform(text_object, 1, 0, 0, 1, 300, 300);
539 FPDFPage_InsertObject(page, text_object);
Nicolas Penaa4ad01f2017-02-15 16:26:48 -0500540 EXPECT_TRUE(FPDFPage_GenerateContent(page));
541 CPDF_Dictionary* font_dict = the_page->m_pResources->GetDictFor("Font");
542 ASSERT_TRUE(font_dict);
543 EXPECT_EQ(1, static_cast<int>(font_dict->GetCount()));
544
545 // Generate yet again, check dicts are reasonably sized
546 EXPECT_TRUE(FPDFPage_GenerateContent(page));
547 EXPECT_EQ(2, static_cast<int>(graphics_dict->GetCount()));
548 EXPECT_EQ(1, static_cast<int>(font_dict->GetCount()));
549 FPDF_ClosePage(page);
Nicolas Penaa4ad01f2017-02-15 16:26:48 -0500550}
Nicolas Penabe90aae2017-02-27 10:41:41 -0500551
Nicolas Penad03ca422017-03-06 13:54:33 -0500552TEST_F(FPDFEditEmbeddertest, LoadSimpleType1Font) {
553 CreateNewDocument();
554 // TODO(npm): use other fonts after disallowing loading any font as any type
555 const CPDF_Font* stock_font =
556 CPDF_Font::GetStockFont(cpdf_doc(), "Times-Bold");
557 const uint8_t* data = stock_font->m_Font.GetFontData();
558 const uint32_t size = stock_font->m_Font.GetSize();
Nicolas Penab3161852017-05-02 14:12:50 -0400559 std::unique_ptr<void, FPDFFontDeleter> font(
560 FPDFText_LoadFont(document(), data, size, FPDF_FONT_TYPE1, false));
561 ASSERT_TRUE(font.get());
562 CPDF_Font* typed_font = reinterpret_cast<CPDF_Font*>(font.get());
Nicolas Penad03ca422017-03-06 13:54:33 -0500563 EXPECT_TRUE(typed_font->IsType1Font());
Nicolas Penabe90aae2017-02-27 10:41:41 -0500564
Nicolas Penad03ca422017-03-06 13:54:33 -0500565 CPDF_Dictionary* font_dict = typed_font->GetFontDict();
Nicolas Penabe90aae2017-02-27 10:41:41 -0500566 EXPECT_EQ("Font", font_dict->GetStringFor("Type"));
567 EXPECT_EQ("Type1", font_dict->GetStringFor("Subtype"));
568 EXPECT_EQ("Times New Roman Bold", font_dict->GetStringFor("BaseFont"));
569 ASSERT_TRUE(font_dict->KeyExist("FirstChar"));
570 ASSERT_TRUE(font_dict->KeyExist("LastChar"));
571 EXPECT_EQ(32, font_dict->GetIntegerFor("FirstChar"));
Nicolas Penad03ca422017-03-06 13:54:33 -0500572 EXPECT_EQ(255, font_dict->GetIntegerFor("LastChar"));
573
Nicolas Penabe90aae2017-02-27 10:41:41 -0500574 CPDF_Array* widths_array = font_dict->GetArrayFor("Widths");
Nicolas Penad03ca422017-03-06 13:54:33 -0500575 ASSERT_TRUE(widths_array);
576 ASSERT_EQ(224U, widths_array->GetCount());
Nicolas Penabe90aae2017-02-27 10:41:41 -0500577 EXPECT_EQ(250, widths_array->GetNumberAt(0));
Nicolas Penad03ca422017-03-06 13:54:33 -0500578 EXPECT_EQ(569, widths_array->GetNumberAt(11));
579 EXPECT_EQ(500, widths_array->GetNumberAt(223));
580 CheckFontDescriptor(font_dict, FPDF_FONT_TYPE1, true, false, size, data);
581}
Nicolas Penabe90aae2017-02-27 10:41:41 -0500582
Nicolas Penad03ca422017-03-06 13:54:33 -0500583TEST_F(FPDFEditEmbeddertest, LoadSimpleTrueTypeFont) {
584 CreateNewDocument();
585 const CPDF_Font* stock_font = CPDF_Font::GetStockFont(cpdf_doc(), "Courier");
586 const uint8_t* data = stock_font->m_Font.GetFontData();
587 const uint32_t size = stock_font->m_Font.GetSize();
Nicolas Penab3161852017-05-02 14:12:50 -0400588 std::unique_ptr<void, FPDFFontDeleter> font(
589 FPDFText_LoadFont(document(), data, size, FPDF_FONT_TRUETYPE, false));
590 ASSERT_TRUE(font.get());
591 CPDF_Font* typed_font = reinterpret_cast<CPDF_Font*>(font.get());
Nicolas Penad03ca422017-03-06 13:54:33 -0500592 EXPECT_TRUE(typed_font->IsTrueTypeFont());
Nicolas Penabe90aae2017-02-27 10:41:41 -0500593
Nicolas Penad03ca422017-03-06 13:54:33 -0500594 CPDF_Dictionary* font_dict = typed_font->GetFontDict();
595 EXPECT_EQ("Font", font_dict->GetStringFor("Type"));
596 EXPECT_EQ("TrueType", font_dict->GetStringFor("Subtype"));
597 EXPECT_EQ("Courier New", font_dict->GetStringFor("BaseFont"));
598 ASSERT_TRUE(font_dict->KeyExist("FirstChar"));
599 ASSERT_TRUE(font_dict->KeyExist("LastChar"));
600 EXPECT_EQ(32, font_dict->GetIntegerFor("FirstChar"));
601 EXPECT_EQ(255, font_dict->GetIntegerFor("LastChar"));
Nicolas Penabe90aae2017-02-27 10:41:41 -0500602
Nicolas Penad03ca422017-03-06 13:54:33 -0500603 CPDF_Array* widths_array = font_dict->GetArrayFor("Widths");
604 ASSERT_TRUE(widths_array);
605 ASSERT_EQ(224U, widths_array->GetCount());
606 EXPECT_EQ(600, widths_array->GetNumberAt(33));
607 EXPECT_EQ(600, widths_array->GetNumberAt(74));
608 EXPECT_EQ(600, widths_array->GetNumberAt(223));
609 CheckFontDescriptor(font_dict, FPDF_FONT_TRUETYPE, false, false, size, data);
610}
611
612TEST_F(FPDFEditEmbeddertest, LoadCIDType0Font) {
613 CreateNewDocument();
614 const CPDF_Font* stock_font =
615 CPDF_Font::GetStockFont(cpdf_doc(), "Times-Roman");
616 const uint8_t* data = stock_font->m_Font.GetFontData();
617 const uint32_t size = stock_font->m_Font.GetSize();
Nicolas Penab3161852017-05-02 14:12:50 -0400618 std::unique_ptr<void, FPDFFontDeleter> font(
619 FPDFText_LoadFont(document(), data, size, FPDF_FONT_TYPE1, 1));
620 ASSERT_TRUE(font.get());
621 CPDF_Font* typed_font = reinterpret_cast<CPDF_Font*>(font.get());
Nicolas Penad03ca422017-03-06 13:54:33 -0500622 EXPECT_TRUE(typed_font->IsCIDFont());
623
624 // Check font dictionary entries
625 CPDF_Dictionary* font_dict = typed_font->GetFontDict();
626 EXPECT_EQ("Font", font_dict->GetStringFor("Type"));
627 EXPECT_EQ("Type0", font_dict->GetStringFor("Subtype"));
628 EXPECT_EQ("Times New Roman-Identity-H", font_dict->GetStringFor("BaseFont"));
629 EXPECT_EQ("Identity-H", font_dict->GetStringFor("Encoding"));
630 CPDF_Array* descendant_array = font_dict->GetArrayFor("DescendantFonts");
631 ASSERT_TRUE(descendant_array);
632 EXPECT_EQ(1U, descendant_array->GetCount());
633
634 // Check the CIDFontDict
635 CPDF_Dictionary* cidfont_dict = descendant_array->GetDictAt(0);
636 EXPECT_EQ("Font", cidfont_dict->GetStringFor("Type"));
637 EXPECT_EQ("CIDFontType0", cidfont_dict->GetStringFor("Subtype"));
638 EXPECT_EQ("Times New Roman", cidfont_dict->GetStringFor("BaseFont"));
639 CPDF_Dictionary* cidinfo_dict = cidfont_dict->GetDictFor("CIDSystemInfo");
640 ASSERT_TRUE(cidinfo_dict);
641 EXPECT_EQ("Adobe", cidinfo_dict->GetStringFor("Registry"));
642 EXPECT_EQ("Identity", cidinfo_dict->GetStringFor("Ordering"));
643 EXPECT_EQ(0, cidinfo_dict->GetNumberFor("Supplement"));
644 CheckFontDescriptor(cidfont_dict, FPDF_FONT_TYPE1, false, false, size, data);
645
646 // Check widths
647 CPDF_Array* widths_array = cidfont_dict->GetArrayFor("W");
648 ASSERT_TRUE(widths_array);
Nicolas Penaf45ade32017-05-03 10:23:49 -0400649 EXPECT_GT(widths_array->GetCount(), 1U);
Nicolas Penad03ca422017-03-06 13:54:33 -0500650 CheckCompositeFontWidths(widths_array, typed_font);
651}
652
653TEST_F(FPDFEditEmbeddertest, LoadCIDType2Font) {
654 CreateNewDocument();
655 const CPDF_Font* stock_font =
656 CPDF_Font::GetStockFont(cpdf_doc(), "Helvetica-Oblique");
657 const uint8_t* data = stock_font->m_Font.GetFontData();
658 const uint32_t size = stock_font->m_Font.GetSize();
659
Nicolas Penab3161852017-05-02 14:12:50 -0400660 std::unique_ptr<void, FPDFFontDeleter> font(
661 FPDFText_LoadFont(document(), data, size, FPDF_FONT_TRUETYPE, 1));
662 ASSERT_TRUE(font.get());
663 CPDF_Font* typed_font = reinterpret_cast<CPDF_Font*>(font.get());
Nicolas Penad03ca422017-03-06 13:54:33 -0500664 EXPECT_TRUE(typed_font->IsCIDFont());
665
666 // Check font dictionary entries
667 CPDF_Dictionary* font_dict = typed_font->GetFontDict();
668 EXPECT_EQ("Font", font_dict->GetStringFor("Type"));
669 EXPECT_EQ("Type0", font_dict->GetStringFor("Subtype"));
670 EXPECT_EQ("Arial Italic", font_dict->GetStringFor("BaseFont"));
671 EXPECT_EQ("Identity-H", font_dict->GetStringFor("Encoding"));
672 CPDF_Array* descendant_array = font_dict->GetArrayFor("DescendantFonts");
673 ASSERT_TRUE(descendant_array);
674 EXPECT_EQ(1U, descendant_array->GetCount());
675
676 // Check the CIDFontDict
677 CPDF_Dictionary* cidfont_dict = descendant_array->GetDictAt(0);
678 EXPECT_EQ("Font", cidfont_dict->GetStringFor("Type"));
679 EXPECT_EQ("CIDFontType2", cidfont_dict->GetStringFor("Subtype"));
680 EXPECT_EQ("Arial Italic", cidfont_dict->GetStringFor("BaseFont"));
681 CPDF_Dictionary* cidinfo_dict = cidfont_dict->GetDictFor("CIDSystemInfo");
682 ASSERT_TRUE(cidinfo_dict);
683 EXPECT_EQ("Adobe", cidinfo_dict->GetStringFor("Registry"));
684 EXPECT_EQ("Identity", cidinfo_dict->GetStringFor("Ordering"));
685 EXPECT_EQ(0, cidinfo_dict->GetNumberFor("Supplement"));
686 CheckFontDescriptor(cidfont_dict, FPDF_FONT_TRUETYPE, false, true, size,
687 data);
688
689 // Check widths
690 CPDF_Array* widths_array = cidfont_dict->GetArrayFor("W");
691 ASSERT_TRUE(widths_array);
692 CheckCompositeFontWidths(widths_array, typed_font);
Nicolas Penabe90aae2017-02-27 10:41:41 -0500693}
rbpotterce8e51e2017-04-28 12:42:47 -0700694
695TEST_F(FPDFEditEmbeddertest, NormalizeNegativeRotation) {
696 // Load document with a -90 degree rotation
697 EXPECT_TRUE(OpenDocument("bug_713197.pdf"));
698 FPDF_PAGE page = LoadPage(0);
699 EXPECT_NE(nullptr, page);
700
701 EXPECT_EQ(3, FPDFPage_GetRotation(page));
702 UnloadPage(page);
703}
Nicolas Penab3161852017-05-02 14:12:50 -0400704
705TEST_F(FPDFEditEmbeddertest, AddTrueTypeFontText) {
706 // Start with a blank page
707 FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
708 {
709 const CPDF_Font* stock_font = CPDF_Font::GetStockFont(cpdf_doc(), "Arial");
710 const uint8_t* data = stock_font->m_Font.GetFontData();
711 const uint32_t size = stock_font->m_Font.GetSize();
712 std::unique_ptr<void, FPDFFontDeleter> font(
713 FPDFText_LoadFont(document(), data, size, FPDF_FONT_TRUETYPE, 0));
714 ASSERT_TRUE(font.get());
715
716 // Add some text to the page
717 FPDF_PAGEOBJECT text_object =
718 FPDFPageObj_CreateTextObj(document(), font.get(), 12.0f);
719 EXPECT_TRUE(text_object);
720 std::unique_ptr<unsigned short, pdfium::FreeDeleter> text =
721 GetFPDFWideString(L"I am testing my loaded font, WEE.");
722 EXPECT_TRUE(FPDFText_SetText(text_object, text.get()));
723 FPDFPageObj_Transform(text_object, 1, 0, 0, 1, 400, 400);
724 FPDFPage_InsertObject(page, text_object);
725 EXPECT_TRUE(FPDFPage_GenerateContent(page));
726 FPDF_BITMAP page_bitmap = RenderPage(page);
727#if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
728 const char md5[] = "17d2b6cd574cf66170b09c8927529a94";
729#else
730 const char md5[] = "28e5b10743660dcdfd1618db47b39d32";
731#endif // _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
732 CompareBitmap(page_bitmap, 612, 792, md5);
733 FPDFBitmap_Destroy(page_bitmap);
734
735 // Add some more text, same font
736 FPDF_PAGEOBJECT text_object2 =
737 FPDFPageObj_CreateTextObj(document(), font.get(), 15.0f);
738 std::unique_ptr<unsigned short, pdfium::FreeDeleter> text2 =
739 GetFPDFWideString(L"Bigger font size");
740 EXPECT_TRUE(FPDFText_SetText(text_object2, text2.get()));
741 FPDFPageObj_Transform(text_object2, 1, 0, 0, 1, 200, 200);
742 FPDFPage_InsertObject(page, text_object2);
743 EXPECT_TRUE(FPDFPage_GenerateContent(page));
744 }
745 FPDF_BITMAP page_bitmap2 = RenderPage(page);
746#if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
747 const char md5_2[] = "8eded4193ff1f0f77b8b600a825e97ea";
748#else
749 const char md5_2[] = "a068eef4110d607f77c87ea8340fa2a5";
750#endif // _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
751 CompareBitmap(page_bitmap2, 612, 792, md5_2);
752 FPDFBitmap_Destroy(page_bitmap2);
753
754 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
755 FPDF_ClosePage(page);
756 std::string new_file = GetString();
757
758 // Render the saved result
759 FPDF_FILEACCESS file_access;
760 memset(&file_access, 0, sizeof(file_access));
761 file_access.m_FileLen = new_file.size();
762 file_access.m_GetBlock = GetBlockFromString;
763 file_access.m_Param = &new_file;
764 FPDF_DOCUMENT new_doc = FPDF_LoadCustomDocument(&file_access, nullptr);
765 ASSERT_NE(nullptr, new_doc);
766 EXPECT_EQ(1, FPDF_GetPageCount(new_doc));
767 FPDF_PAGE new_page = FPDF_LoadPage(new_doc, 0);
768 ASSERT_NE(nullptr, new_page);
769 FPDF_BITMAP new_bitmap = RenderPage(new_page);
770 CompareBitmap(new_bitmap, 612, 792, md5_2);
771 FPDFBitmap_Destroy(new_bitmap);
772 FPDF_ClosePage(new_page);
773 FPDF_CloseDocument(new_doc);
774}
Nicolas Penaf45ade32017-05-03 10:23:49 -0400775
776// TODO(npm): Add tests using Japanese fonts in other OS.
777#if _FXM_PLATFORM_ == _FXM_PLATFORM_LINUX_
778TEST_F(FPDFEditEmbeddertest, AddCIDFontText) {
779 // Start with a blank page
780 FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
781 CFX_Font CIDfont;
782 {
783 // First, get the data from the font
784 CIDfont.LoadSubst("IPAGothic", 1, 0, 400, 0, 932, 0);
785 EXPECT_EQ("IPAGothic", CIDfont.GetFaceName());
786 const uint8_t* data = CIDfont.GetFontData();
787 const uint32_t size = CIDfont.GetSize();
788
789 // Load the data into a FPDF_Font.
790 std::unique_ptr<void, FPDFFontDeleter> font(
791 FPDFText_LoadFont(document(), data, size, FPDF_FONT_TRUETYPE, 1));
792 ASSERT_TRUE(font.get());
793
794 // Add some text to the page
795 FPDF_PAGEOBJECT text_object =
796 FPDFPageObj_CreateTextObj(document(), font.get(), 12.0f);
797 ASSERT_TRUE(text_object);
798 std::wstring wstr = L"ABCDEFGhijklmnop.";
799 std::unique_ptr<unsigned short, pdfium::FreeDeleter> text =
800 GetFPDFWideString(wstr);
801 EXPECT_TRUE(FPDFText_SetText(text_object, text.get()));
802 FPDFPageObj_Transform(text_object, 1, 0, 0, 1, 200, 200);
803 FPDFPage_InsertObject(page, text_object);
804
805 // And add some Japanese characters
806 FPDF_PAGEOBJECT text_object2 =
807 FPDFPageObj_CreateTextObj(document(), font.get(), 18.0f);
808 ASSERT_TRUE(text_object2);
809 std::wstring wstr2 =
810 L"\u3053\u3093\u306B\u3061\u306f\u4e16\u754C\u3002\u3053\u3053\u306B1"
811 L"\u756A";
812 std::unique_ptr<unsigned short, pdfium::FreeDeleter> text2 =
813 GetFPDFWideString(wstr2);
814 EXPECT_TRUE(FPDFText_SetText(text_object2, text2.get()));
815 FPDFPageObj_Transform(text_object2, 1, 0, 0, 1, 100, 500);
816 FPDFPage_InsertObject(page, text_object2);
817 }
818
819 // Generate contents and check that the text renders properly.
820 EXPECT_TRUE(FPDFPage_GenerateContent(page));
821 FPDF_BITMAP page_bitmap = RenderPage(page);
822 const char md5[] = "2bc6c1aaa2252e73246a75775ccf38c2";
823 CompareBitmap(page_bitmap, 612, 792, md5);
824 FPDFBitmap_Destroy(page_bitmap);
825
826 // Save the document, close the page.
827 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
828 FPDF_ClosePage(page);
829 std::string new_file = GetString();
830
831 // Render the saved result
832 FPDF_FILEACCESS file_access;
833 memset(&file_access, 0, sizeof(file_access));
834 file_access.m_FileLen = new_file.size();
835 file_access.m_GetBlock = GetBlockFromString;
836 file_access.m_Param = &new_file;
837 FPDF_DOCUMENT new_doc = FPDF_LoadCustomDocument(&file_access, nullptr);
838 ASSERT_NE(nullptr, new_doc);
839 EXPECT_EQ(1, FPDF_GetPageCount(new_doc));
840 FPDF_PAGE new_page = FPDF_LoadPage(new_doc, 0);
841 ASSERT_NE(nullptr, new_page);
842 FPDF_BITMAP new_bitmap = RenderPage(new_page);
843 CompareBitmap(new_bitmap, 612, 792, md5);
844 FPDFBitmap_Destroy(new_bitmap);
845 FPDF_ClosePage(new_page);
846 FPDF_CloseDocument(new_doc);
847}
848#endif // _FXM_PLATFORM_ == _FXM_PLATFORM_LINUX_