• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // 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 
5 #include <memory>
6 #include <string>
7 
8 #include "core/fpdfapi/font/cpdf_font.h"
9 #include "core/fpdfapi/page/cpdf_page.h"
10 #include "core/fpdfapi/parser/cpdf_array.h"
11 #include "core/fpdfapi/parser/cpdf_dictionary.h"
12 #include "core/fpdfapi/parser/cpdf_stream.h"
13 #include "core/fxcrt/fx_system.h"
14 #include "fpdfsdk/fsdk_define.h"
15 #include "public/fpdf_edit.h"
16 #include "public/fpdfview.h"
17 #include "testing/embedder_test.h"
18 #include "testing/gmock/include/gmock/gmock-matchers.h"
19 #include "testing/gtest/include/gtest/gtest.h"
20 #include "testing/test_support.h"
21 
22 class FPDFEditEmbeddertest : public EmbedderTest, public TestSaver {};
23 
24 namespace {
25 
26 const char kExpectedPDF[] =
27     "%PDF-1.7\r\n"
28     "%\xA1\xB3\xC5\xD7\r\n"
29     "1 0 obj\r\n"
30     "<</Pages 2 0 R /Type/Catalog>>\r\n"
31     "endobj\r\n"
32     "2 0 obj\r\n"
33     "<</Count 1/Kids\\[ 4 0 R \\]/Type/Pages>>\r\n"
34     "endobj\r\n"
35     "3 0 obj\r\n"
36     "<</CreationDate\\(D:.*\\)/Creator\\(PDFium\\)>>\r\n"
37     "endobj\r\n"
38     "4 0 obj\r\n"
39     "<</Contents 5 0 R /MediaBox\\[ 0 0 640 480\\]"
40     "/Parent 2 0 R /Resources<<>>/Rotate 0/Type/Page"
41     ">>\r\n"
42     "endobj\r\n"
43     "5 0 obj\r\n"
44     "<</Filter/FlateDecode/Length 8>>stream\r\n"
45     // Character '_' is matching '\0' (see comment below).
46     "x\x9C\x3____\x1\r\n"
47     "endstream\r\n"
48     "endobj\r\n"
49     "xref\r\n"
50     "0 6\r\n"
51     "0000000000 65535 f\r\n"
52     "0000000017 00000 n\r\n"
53     "0000000066 00000 n\r\n"
54     "0000000122 00000 n\r\n"
55     "0000000192 00000 n\r\n"
56     "0000000301 00000 n\r\n"
57     "trailer\r\n"
58     "<<\r\n"
59     "/Root 1 0 R\r\n"
60     "/Info 3 0 R\r\n"
61     "/Size 6/ID\\[<.*><.*>\\]>>\r\n"
62     "startxref\r\n"
63     "379\r\n"
64     "%%EOF\r\n";
65 
GetBlockFromString(void * param,unsigned long pos,unsigned char * buf,unsigned long size)66 int GetBlockFromString(void* param,
67                        unsigned long pos,
68                        unsigned char* buf,
69                        unsigned long size) {
70   std::string* new_file = static_cast<std::string*>(param);
71   if (!new_file || pos + size < pos)
72     return 0;
73 
74   unsigned long file_size = new_file->size();
75   if (pos + size > file_size)
76     return 0;
77 
78   memcpy(buf, new_file->data() + pos, size);
79   return 1;
80 }
81 
82 }  // namespace
83 
TEST_F(FPDFEditEmbeddertest,EmptyCreation)84 TEST_F(FPDFEditEmbeddertest, EmptyCreation) {
85   EXPECT_TRUE(CreateEmptyDocument());
86   FPDF_PAGE page = FPDFPage_New(document(), 0, 640.0, 480.0);
87   EXPECT_NE(nullptr, page);
88   EXPECT_TRUE(FPDFPage_GenerateContent(page));
89   EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
90 
91   // The MatchesRegexp doesn't support embedded NUL ('\0') characters. They are
92   // replaced by '_' for the purpose of the test.
93   std::string result = GetString();
94   std::replace(result.begin(), result.end(), '\0', '_');
95   EXPECT_THAT(result, testing::MatchesRegex(
96                           std::string(kExpectedPDF, sizeof(kExpectedPDF))));
97   FPDF_ClosePage(page);
98 }
99 
100 // Regression test for https://crbug.com/667012
TEST_F(FPDFEditEmbeddertest,RasterizePDF)101 TEST_F(FPDFEditEmbeddertest, RasterizePDF) {
102   const char kAllBlackMd5sum[] = "5708fc5c4a8bd0abde99c8e8f0390615";
103 
104   // Get the bitmap for the original document/
105   FPDF_BITMAP orig_bitmap;
106   {
107     EXPECT_TRUE(OpenDocument("black.pdf"));
108     FPDF_PAGE orig_page = LoadPage(0);
109     EXPECT_NE(nullptr, orig_page);
110     orig_bitmap = RenderPage(orig_page);
111     CompareBitmap(orig_bitmap, 612, 792, kAllBlackMd5sum);
112     UnloadPage(orig_page);
113   }
114 
115   // Create a new document from |orig_bitmap| and save it.
116   {
117     FPDF_DOCUMENT temp_doc = FPDF_CreateNewDocument();
118     FPDF_PAGE temp_page = FPDFPage_New(temp_doc, 0, 612, 792);
119 
120     // Add the bitmap to an image object and add the image object to the output
121     // page.
122     FPDF_PAGEOBJECT temp_img = FPDFPageObj_NewImgeObj(temp_doc);
123     EXPECT_TRUE(FPDFImageObj_SetBitmap(&temp_page, 1, temp_img, orig_bitmap));
124     EXPECT_TRUE(FPDFImageObj_SetMatrix(temp_img, 612, 0, 0, 792, 0, 0));
125     FPDFPage_InsertObject(temp_page, temp_img);
126     EXPECT_TRUE(FPDFPage_GenerateContent(temp_page));
127     EXPECT_TRUE(FPDF_SaveAsCopy(temp_doc, this, 0));
128     FPDF_ClosePage(temp_page);
129     FPDF_CloseDocument(temp_doc);
130   }
131   FPDFBitmap_Destroy(orig_bitmap);
132 
133   // Get the generated content. Make sure it is at least as big as the original
134   // PDF.
135   std::string new_file = GetString();
136   EXPECT_GT(new_file.size(), 923U);
137 
138   // Read |new_file| in, and verify its rendered bitmap.
139   {
140     FPDF_FILEACCESS file_access;
141     memset(&file_access, 0, sizeof(file_access));
142     file_access.m_FileLen = new_file.size();
143     file_access.m_GetBlock = GetBlockFromString;
144     file_access.m_Param = &new_file;
145 
146     FPDF_DOCUMENT new_doc = FPDF_LoadCustomDocument(&file_access, nullptr);
147     EXPECT_EQ(1, FPDF_GetPageCount(document_));
148     FPDF_PAGE new_page = FPDF_LoadPage(new_doc, 0);
149     EXPECT_NE(nullptr, new_page);
150     FPDF_BITMAP new_bitmap = RenderPage(new_page);
151     CompareBitmap(new_bitmap, 612, 792, kAllBlackMd5sum);
152     FPDF_ClosePage(new_page);
153     FPDF_CloseDocument(new_doc);
154     FPDFBitmap_Destroy(new_bitmap);
155   }
156 }
157 
TEST_F(FPDFEditEmbeddertest,AddPaths)158 TEST_F(FPDFEditEmbeddertest, AddPaths) {
159   // Start with a blank page
160   FPDF_DOCUMENT doc = FPDF_CreateNewDocument();
161   FPDF_PAGE page = FPDFPage_New(doc, 0, 612, 792);
162 
163   // We will first add a red rectangle
164   FPDF_PAGEOBJECT red_rect = FPDFPageObj_CreateNewRect(10, 10, 20, 20);
165   ASSERT_NE(nullptr, red_rect);
166   // Expect false when trying to set colors out of range
167   EXPECT_FALSE(FPDFPath_SetStrokeColor(red_rect, 100, 100, 100, 300));
168   EXPECT_FALSE(FPDFPath_SetFillColor(red_rect, 200, 256, 200, 0));
169 
170   // Fill rectangle with red and insert to the page
171   EXPECT_TRUE(FPDFPath_SetFillColor(red_rect, 255, 0, 0, 255));
172   EXPECT_TRUE(FPDFPath_SetDrawMode(red_rect, FPDF_FILLMODE_ALTERNATE, 0));
173   FPDFPage_InsertObject(page, red_rect);
174   EXPECT_TRUE(FPDFPage_GenerateContent(page));
175   FPDF_BITMAP page_bitmap = RenderPage(page);
176   CompareBitmap(page_bitmap, 612, 792, "66d02eaa6181e2c069ce2ea99beda497");
177   FPDFBitmap_Destroy(page_bitmap);
178 
179   // Now add to that a green rectangle with some medium alpha
180   FPDF_PAGEOBJECT green_rect = FPDFPageObj_CreateNewRect(100, 100, 40, 40);
181   EXPECT_TRUE(FPDFPath_SetFillColor(green_rect, 0, 255, 0, 128));
182   EXPECT_TRUE(FPDFPath_SetDrawMode(green_rect, FPDF_FILLMODE_WINDING, 0));
183   FPDFPage_InsertObject(page, green_rect);
184   EXPECT_TRUE(FPDFPage_GenerateContent(page));
185   page_bitmap = RenderPage(page);
186   CompareBitmap(page_bitmap, 612, 792, "7b0b87604594e773add528fae567a558");
187   FPDFBitmap_Destroy(page_bitmap);
188 
189   // Add a black triangle.
190   FPDF_PAGEOBJECT black_path = FPDFPageObj_CreateNewPath(400, 100);
191   EXPECT_TRUE(FPDFPath_SetFillColor(black_path, 0, 0, 0, 200));
192   EXPECT_TRUE(FPDFPath_SetDrawMode(black_path, FPDF_FILLMODE_ALTERNATE, 0));
193   EXPECT_TRUE(FPDFPath_LineTo(black_path, 400, 200));
194   EXPECT_TRUE(FPDFPath_LineTo(black_path, 300, 100));
195   EXPECT_TRUE(FPDFPath_Close(black_path));
196   FPDFPage_InsertObject(page, black_path);
197   EXPECT_TRUE(FPDFPage_GenerateContent(page));
198   page_bitmap = RenderPage(page);
199   CompareBitmap(page_bitmap, 612, 792, "eadc8020a14dfcf091da2688733d8806");
200   FPDFBitmap_Destroy(page_bitmap);
201 
202   // Now add a more complex blue path.
203   FPDF_PAGEOBJECT blue_path = FPDFPageObj_CreateNewPath(200, 200);
204   EXPECT_TRUE(FPDFPath_SetFillColor(blue_path, 0, 0, 255, 255));
205   EXPECT_TRUE(FPDFPath_SetDrawMode(blue_path, FPDF_FILLMODE_WINDING, 0));
206   EXPECT_TRUE(FPDFPath_LineTo(blue_path, 230, 230));
207   EXPECT_TRUE(FPDFPath_BezierTo(blue_path, 250, 250, 280, 280, 300, 300));
208   EXPECT_TRUE(FPDFPath_LineTo(blue_path, 325, 325));
209   EXPECT_TRUE(FPDFPath_LineTo(blue_path, 350, 325));
210   EXPECT_TRUE(FPDFPath_BezierTo(blue_path, 375, 330, 390, 360, 400, 400));
211   EXPECT_TRUE(FPDFPath_Close(blue_path));
212   FPDFPage_InsertObject(page, blue_path);
213   EXPECT_TRUE(FPDFPage_GenerateContent(page));
214   page_bitmap = RenderPage(page);
215   CompareBitmap(page_bitmap, 612, 792, "9823e1a21bd9b72b6a442ba4f12af946");
216   FPDFBitmap_Destroy(page_bitmap);
217 
218   // Now save the result, closing the page and document
219   EXPECT_TRUE(FPDF_SaveAsCopy(doc, this, 0));
220   FPDF_ClosePage(page);
221   FPDF_CloseDocument(doc);
222   std::string new_file = GetString();
223 
224   // Render the saved result
225   FPDF_FILEACCESS file_access;
226   memset(&file_access, 0, sizeof(file_access));
227   file_access.m_FileLen = new_file.size();
228   file_access.m_GetBlock = GetBlockFromString;
229   file_access.m_Param = &new_file;
230   FPDF_DOCUMENT new_doc = FPDF_LoadCustomDocument(&file_access, nullptr);
231   ASSERT_NE(nullptr, new_doc);
232   EXPECT_EQ(1, FPDF_GetPageCount(new_doc));
233   FPDF_PAGE new_page = FPDF_LoadPage(new_doc, 0);
234   ASSERT_NE(nullptr, new_page);
235   FPDF_BITMAP new_bitmap = RenderPage(new_page);
236   CompareBitmap(new_bitmap, 612, 792, "9823e1a21bd9b72b6a442ba4f12af946");
237   FPDFBitmap_Destroy(new_bitmap);
238   FPDF_ClosePage(new_page);
239   FPDF_CloseDocument(new_doc);
240 }
241 
TEST_F(FPDFEditEmbeddertest,PathOnTopOfText)242 TEST_F(FPDFEditEmbeddertest, PathOnTopOfText) {
243   // Load document with some text
244   EXPECT_TRUE(OpenDocument("hello_world.pdf"));
245   FPDF_PAGE page = LoadPage(0);
246   EXPECT_NE(nullptr, page);
247 
248   // Add an opaque rectangle on top of some of the text.
249   FPDF_PAGEOBJECT red_rect = FPDFPageObj_CreateNewRect(20, 100, 50, 50);
250   EXPECT_TRUE(FPDFPath_SetFillColor(red_rect, 255, 0, 0, 255));
251   EXPECT_TRUE(FPDFPath_SetDrawMode(red_rect, FPDF_FILLMODE_ALTERNATE, 0));
252   FPDFPage_InsertObject(page, red_rect);
253   EXPECT_TRUE(FPDFPage_GenerateContent(page));
254 
255   // Add a transparent triangle on top of other part of the text.
256   FPDF_PAGEOBJECT black_path = FPDFPageObj_CreateNewPath(20, 50);
257   EXPECT_TRUE(FPDFPath_SetFillColor(black_path, 0, 0, 0, 100));
258   EXPECT_TRUE(FPDFPath_SetDrawMode(black_path, FPDF_FILLMODE_ALTERNATE, 0));
259   EXPECT_TRUE(FPDFPath_LineTo(black_path, 30, 80));
260   EXPECT_TRUE(FPDFPath_LineTo(black_path, 40, 10));
261   EXPECT_TRUE(FPDFPath_Close(black_path));
262   FPDFPage_InsertObject(page, black_path);
263   EXPECT_TRUE(FPDFPage_GenerateContent(page));
264 
265   // Render and check the result. Text is slightly different on Mac.
266   FPDF_BITMAP bitmap = RenderPage(page);
267 #if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
268   const char md5[] = "2f7c0deee10a9490538e195af64beb67";
269 #else
270   const char md5[] = "17c942c76ff229200f2c98073bb60d85";
271 #endif
272   CompareBitmap(bitmap, 200, 200, md5);
273   FPDFBitmap_Destroy(bitmap);
274   UnloadPage(page);
275 }
276 
TEST_F(FPDFEditEmbeddertest,AddStrokedPaths)277 TEST_F(FPDFEditEmbeddertest, AddStrokedPaths) {
278   // Start with a blank page
279   FPDF_DOCUMENT doc = FPDF_CreateNewDocument();
280   FPDF_PAGE page = FPDFPage_New(doc, 0, 612, 792);
281 
282   // Add a large stroked rectangle (fill color should not affect it).
283   FPDF_PAGEOBJECT rect = FPDFPageObj_CreateNewRect(20, 20, 200, 400);
284   EXPECT_TRUE(FPDFPath_SetFillColor(rect, 255, 0, 0, 255));
285   EXPECT_TRUE(FPDFPath_SetStrokeColor(rect, 0, 255, 0, 255));
286   EXPECT_TRUE(FPDFPath_SetStrokeWidth(rect, 15.0f));
287   EXPECT_TRUE(FPDFPath_SetDrawMode(rect, 0, 1));
288   FPDFPage_InsertObject(page, rect);
289   EXPECT_TRUE(FPDFPage_GenerateContent(page));
290   FPDF_BITMAP page_bitmap = RenderPage(page);
291   CompareBitmap(page_bitmap, 612, 792, "64bd31f862a89e0a9e505a5af6efd506");
292   FPDFBitmap_Destroy(page_bitmap);
293 
294   // Add crossed-checkmark
295   FPDF_PAGEOBJECT check = FPDFPageObj_CreateNewPath(300, 500);
296   EXPECT_TRUE(FPDFPath_LineTo(check, 400, 400));
297   EXPECT_TRUE(FPDFPath_LineTo(check, 600, 600));
298   EXPECT_TRUE(FPDFPath_MoveTo(check, 400, 600));
299   EXPECT_TRUE(FPDFPath_LineTo(check, 600, 400));
300   EXPECT_TRUE(FPDFPath_SetStrokeColor(check, 128, 128, 128, 180));
301   EXPECT_TRUE(FPDFPath_SetStrokeWidth(check, 8.35f));
302   EXPECT_TRUE(FPDFPath_SetDrawMode(check, 0, 1));
303   FPDFPage_InsertObject(page, check);
304   EXPECT_TRUE(FPDFPage_GenerateContent(page));
305   page_bitmap = RenderPage(page);
306   CompareBitmap(page_bitmap, 612, 792, "4b6f3b9d25c4e194821217d5016c3724");
307   FPDFBitmap_Destroy(page_bitmap);
308 
309   // Add stroked and filled oval-ish path.
310   FPDF_PAGEOBJECT path = FPDFPageObj_CreateNewPath(250, 100);
311   EXPECT_TRUE(FPDFPath_BezierTo(path, 180, 166, 180, 233, 250, 300));
312   EXPECT_TRUE(FPDFPath_LineTo(path, 255, 305));
313   EXPECT_TRUE(FPDFPath_BezierTo(path, 325, 233, 325, 166, 255, 105));
314   EXPECT_TRUE(FPDFPath_Close(path));
315   EXPECT_TRUE(FPDFPath_SetFillColor(path, 200, 128, 128, 100));
316   EXPECT_TRUE(FPDFPath_SetStrokeColor(path, 128, 200, 128, 150));
317   EXPECT_TRUE(FPDFPath_SetStrokeWidth(path, 10.5f));
318   EXPECT_TRUE(FPDFPath_SetDrawMode(path, FPDF_FILLMODE_ALTERNATE, 1));
319   FPDFPage_InsertObject(page, path);
320   EXPECT_TRUE(FPDFPage_GenerateContent(page));
321   page_bitmap = RenderPage(page);
322   CompareBitmap(page_bitmap, 612, 792, "ff3e6a22326754944cc6e56609acd73b");
323   FPDFBitmap_Destroy(page_bitmap);
324   FPDF_ClosePage(page);
325   FPDF_CloseDocument(doc);
326 }
327 
TEST_F(FPDFEditEmbeddertest,AddStandardFontText)328 TEST_F(FPDFEditEmbeddertest, AddStandardFontText) {
329   // Start with a blank page
330   FPDF_DOCUMENT doc = FPDF_CreateNewDocument();
331   FPDF_PAGE page = FPDFPage_New(doc, 0, 612, 792);
332 
333   // Add some text to the page
334   FPDF_PAGEOBJECT text1 = FPDFPageObj_NewTextObj(doc, "Arial", 12.0f);
335   EXPECT_TRUE(text1);
336   EXPECT_TRUE(FPDFText_SetText(text1, "I'm at the bottom of the page"));
337   FPDFPageObj_Transform(text1, 1, 0, 0, 1, 20, 20);
338   FPDFPage_InsertObject(page, text1);
339   EXPECT_TRUE(FPDFPage_GenerateContent(page));
340   FPDF_BITMAP page_bitmap = RenderPage(page);
341 #if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
342   const char md5[] = "e19c90395d73cb9f37a6c3b0e8b18a9e";
343 #else
344   const char md5[] = "7c3a36ba7cec01688a16a14bfed9ecfc";
345 #endif
346   CompareBitmap(page_bitmap, 612, 792, md5);
347   FPDFBitmap_Destroy(page_bitmap);
348 
349   // Try another font
350   FPDF_PAGEOBJECT text2 =
351       FPDFPageObj_NewTextObj(doc, "TimesNewRomanBold", 15.0f);
352   EXPECT_TRUE(text2);
353   EXPECT_TRUE(FPDFText_SetText(text2, "Hi, I'm Bold. Times New Roman Bold."));
354   FPDFPageObj_Transform(text2, 1, 0, 0, 1, 100, 600);
355   FPDFPage_InsertObject(page, text2);
356   EXPECT_TRUE(FPDFPage_GenerateContent(page));
357   page_bitmap = RenderPage(page);
358 #if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
359   const char md5_2[] = "8e1c43dca6be68d364dbc283f5521041";
360 #else
361   const char md5_2[] = "e0e0873e3a2634a6394a431a51ce90ff";
362 #endif
363   CompareBitmap(page_bitmap, 612, 792, md5_2);
364   FPDFBitmap_Destroy(page_bitmap);
365 
366   // And some randomly transformed text
367   FPDF_PAGEOBJECT text3 = FPDFPageObj_NewTextObj(doc, "Courier-Bold", 20.0f);
368   EXPECT_TRUE(text3);
369   EXPECT_TRUE(FPDFText_SetText(text3, "Can you read me? <:)>"));
370   FPDFPageObj_Transform(text3, 1, 1.5, 2, 0.5, 200, 200);
371   FPDFPage_InsertObject(page, text3);
372   EXPECT_TRUE(FPDFPage_GenerateContent(page));
373   page_bitmap = RenderPage(page);
374 #if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
375   const char md5_3[] = "c6e5df448428793c7e4b0c820bd8c85e";
376 #else
377   const char md5_3[] = "903ee10b6a9f0be51ecad0a1a0eeb171";
378 #endif
379   CompareBitmap(page_bitmap, 612, 792, md5_3);
380   FPDFBitmap_Destroy(page_bitmap);
381 
382   // TODO(npm): Why are there issues with text rotated by 90 degrees?
383   // TODO(npm): FPDF_SaveAsCopy not giving the desired result after this.
384   FPDF_ClosePage(page);
385   FPDF_CloseDocument(doc);
386 }
387 
TEST_F(FPDFEditEmbeddertest,DoubleGenerating)388 TEST_F(FPDFEditEmbeddertest, DoubleGenerating) {
389   // Start with a blank page
390   FPDF_DOCUMENT doc = FPDF_CreateNewDocument();
391   FPDF_PAGE page = FPDFPage_New(doc, 0, 612, 792);
392 
393   // Add a red rectangle with some non-default alpha
394   FPDF_PAGEOBJECT rect = FPDFPageObj_CreateNewRect(10, 10, 100, 100);
395   EXPECT_TRUE(FPDFPath_SetFillColor(rect, 255, 0, 0, 128));
396   EXPECT_TRUE(FPDFPath_SetDrawMode(rect, FPDF_FILLMODE_WINDING, 0));
397   FPDFPage_InsertObject(page, rect);
398   EXPECT_TRUE(FPDFPage_GenerateContent(page));
399 
400   // Check the ExtGState
401   CPDF_Page* the_page = CPDFPageFromFPDFPage(page);
402   CPDF_Dictionary* graphics_dict =
403       the_page->m_pResources->GetDictFor("ExtGState");
404   ASSERT_TRUE(graphics_dict);
405   EXPECT_EQ(1, static_cast<int>(graphics_dict->GetCount()));
406 
407   // Check the bitmap
408   FPDF_BITMAP page_bitmap = RenderPage(page);
409   CompareBitmap(page_bitmap, 612, 792, "5384da3406d62360ffb5cac4476fff1c");
410   FPDFBitmap_Destroy(page_bitmap);
411 
412   // Never mind, my new favorite color is blue, increase alpha
413   EXPECT_TRUE(FPDFPath_SetFillColor(rect, 0, 0, 255, 180));
414   EXPECT_TRUE(FPDFPage_GenerateContent(page));
415   EXPECT_EQ(2, static_cast<int>(graphics_dict->GetCount()));
416 
417   // Check that bitmap displays changed content
418   page_bitmap = RenderPage(page);
419   CompareBitmap(page_bitmap, 612, 792, "2e51656f5073b0bee611d9cd086aa09c");
420   FPDFBitmap_Destroy(page_bitmap);
421 
422   // And now generate, without changes
423   EXPECT_TRUE(FPDFPage_GenerateContent(page));
424   EXPECT_EQ(2, static_cast<int>(graphics_dict->GetCount()));
425   page_bitmap = RenderPage(page);
426   CompareBitmap(page_bitmap, 612, 792, "2e51656f5073b0bee611d9cd086aa09c");
427   FPDFBitmap_Destroy(page_bitmap);
428 
429   // Add some text to the page
430   FPDF_PAGEOBJECT text = FPDFPageObj_NewTextObj(doc, "Arial", 12.0f);
431   EXPECT_TRUE(FPDFText_SetText(text, "Something something #text# something"));
432   FPDFPageObj_Transform(text, 1, 0, 0, 1, 300, 300);
433   FPDFPage_InsertObject(page, text);
434   EXPECT_TRUE(FPDFPage_GenerateContent(page));
435   CPDF_Dictionary* font_dict = the_page->m_pResources->GetDictFor("Font");
436   ASSERT_TRUE(font_dict);
437   EXPECT_EQ(1, static_cast<int>(font_dict->GetCount()));
438 
439   // Generate yet again, check dicts are reasonably sized
440   EXPECT_TRUE(FPDFPage_GenerateContent(page));
441   EXPECT_EQ(2, static_cast<int>(graphics_dict->GetCount()));
442   EXPECT_EQ(1, static_cast<int>(font_dict->GetCount()));
443   FPDF_ClosePage(page);
444   FPDF_CloseDocument(doc);
445 }
446 
TEST_F(FPDFEditEmbeddertest,Type1Font)447 TEST_F(FPDFEditEmbeddertest, Type1Font) {
448   // Create a new document
449   FPDF_DOCUMENT doc = FPDF_CreateNewDocument();
450   CPDF_Document* document = reinterpret_cast<CPDF_Document*>(doc);
451 
452   // Get Times New Roman Bold as a Type 1 font
453   CPDF_Font* times_bold = CPDF_Font::GetStockFont(document, "Times-Bold");
454   uint8_t* data = times_bold->m_Font.GetFontData();
455   uint32_t size = times_bold->m_Font.GetSize();
456   FPDF_FONT font = FPDFText_LoadType1Font(doc, data, size);
457   ASSERT_TRUE(font);
458   CPDF_Font* type1_font = reinterpret_cast<CPDF_Font*>(font);
459   EXPECT_TRUE(type1_font->IsType1Font());
460 
461   // Check that the font dictionary has the required keys according to the spec
462   CPDF_Dictionary* font_dict = type1_font->GetFontDict();
463   EXPECT_EQ("Font", font_dict->GetStringFor("Type"));
464   EXPECT_EQ("Type1", font_dict->GetStringFor("Subtype"));
465   EXPECT_EQ("Times New Roman Bold", font_dict->GetStringFor("BaseFont"));
466   ASSERT_TRUE(font_dict->KeyExist("FirstChar"));
467   ASSERT_TRUE(font_dict->KeyExist("LastChar"));
468   EXPECT_EQ(32, font_dict->GetIntegerFor("FirstChar"));
469   EXPECT_EQ(65532, font_dict->GetIntegerFor("LastChar"));
470   ASSERT_TRUE(font_dict->KeyExist("Widths"));
471   CPDF_Array* widths_array = font_dict->GetArrayFor("Widths");
472   EXPECT_EQ(65501U, widths_array->GetCount());
473   EXPECT_EQ(250, widths_array->GetNumberAt(0));
474   EXPECT_EQ(0, widths_array->GetNumberAt(8172));
475   EXPECT_EQ(1000, widths_array->GetNumberAt(65500));
476   ASSERT_TRUE(font_dict->KeyExist("FontDescriptor"));
477   CPDF_Dictionary* font_desc = font_dict->GetDictFor("FontDescriptor");
478   EXPECT_EQ("FontDescriptor", font_desc->GetStringFor("Type"));
479   EXPECT_EQ(font_dict->GetStringFor("BaseFont"),
480             font_desc->GetStringFor("FontName"));
481 
482   // Check that the font descriptor has the required keys according to the spec
483   ASSERT_TRUE(font_desc->KeyExist("Flags"));
484   int font_flags = font_desc->GetIntegerFor("Flags");
485   EXPECT_TRUE(font_flags & FXFONT_BOLD);
486   EXPECT_TRUE(font_flags & FXFONT_NONSYMBOLIC);
487   ASSERT_TRUE(font_desc->KeyExist("FontBBox"));
488   EXPECT_EQ(4U, font_desc->GetArrayFor("FontBBox")->GetCount());
489   EXPECT_TRUE(font_desc->KeyExist("ItalicAngle"));
490   EXPECT_TRUE(font_desc->KeyExist("Ascent"));
491   EXPECT_TRUE(font_desc->KeyExist("Descent"));
492   EXPECT_TRUE(font_desc->KeyExist("CapHeight"));
493   EXPECT_TRUE(font_desc->KeyExist("StemV"));
494   ASSERT_TRUE(font_desc->KeyExist("FontFile"));
495 
496   // Check that the font stream is the one that was provided
497   CPDF_Stream* font_stream = font_desc->GetStreamFor("FontFile");
498   ASSERT_EQ(size, font_stream->GetRawSize());
499   uint8_t* stream_data = font_stream->GetRawData();
500   for (size_t i = 0; i < size; i++)
501     EXPECT_EQ(data[i], stream_data[i]);
502 
503   // Close document
504   FPDF_CloseDocument(doc);
505 }
506