b050e033cde6ae76b0938080a7672e72b2472654
[pdfium.git] / fpdfsdk / src / fpdfview.cpp
1 // Copyright 2014 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 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7 #include "../../core/include/fxcodec/fx_codec.h"
8 #include "../../core/include/fxcrt/fx_safe_types.h"
9 #include "../../public/fpdf_ext.h"
10 #include "../../public/fpdf_progressive.h"
11 #include "../../public/fpdfview.h"
12 #include "../../third_party/base/nonstd_unique_ptr.h"
13 #include "../../third_party/base/numerics/safe_conversions_impl.h"
14 #include "../include/fsdk_define.h"
15 #include "../include/fsdk_mgr.h"
16 #include "../include/fsdk_rendercontext.h"
17 #include "../include/javascript/IJavaScript.h"
18
19 CPDF_CustomAccess::CPDF_CustomAccess(FPDF_FILEACCESS* pFileAccess) {
20   if (pFileAccess)
21     m_FileAccess = *pFileAccess;
22 }
23
24 FX_BOOL CPDF_CustomAccess::ReadBlock(void* buffer,
25                                      FX_FILESIZE offset,
26                                      size_t size) {
27   if (offset < 0) {
28     return FALSE;
29   }
30   FX_SAFE_FILESIZE newPos =
31       pdfium::base::checked_cast<FX_FILESIZE, size_t>(size);
32   newPos += offset;
33   if (!newPos.IsValid() || newPos.ValueOrDie() > m_FileAccess.m_FileLen) {
34     return FALSE;
35   }
36   return m_FileAccess.m_GetBlock(m_FileAccess.m_Param, offset, (uint8_t*)buffer,
37                                  size);
38 }
39
40 // 0 bit: FPDF_POLICY_MACHINETIME_ACCESS
41 static FX_DWORD foxit_sandbox_policy = 0xFFFFFFFF;
42
43 void FSDK_SetSandBoxPolicy(FPDF_DWORD policy, FPDF_BOOL enable) {
44   switch (policy) {
45     case FPDF_POLICY_MACHINETIME_ACCESS: {
46       if (enable)
47         foxit_sandbox_policy |= 0x01;
48       else
49         foxit_sandbox_policy &= 0xFFFFFFFE;
50     } break;
51     default:
52       break;
53   }
54 }
55
56 FPDF_BOOL FSDK_IsSandBoxPolicyEnabled(FPDF_DWORD policy) {
57   switch (policy) {
58     case FPDF_POLICY_MACHINETIME_ACCESS:
59       return (foxit_sandbox_policy & 0x01) ? TRUE : FALSE;
60     default:
61       return FALSE;
62   }
63 }
64
65 CCodec_ModuleMgr* g_pCodecModule = nullptr;
66
67 #if _FX_OS_ == _FX_LINUX_EMBEDDED_
68 class CFontMapper : public IPDF_FontMapper {
69  public:
70   CFontMapper();
71   ~CFontMapper() override;
72
73   // IPDF_FontMapper
74   FT_Face FindSubstFont(
75       CPDF_Document* pDoc,              // [IN] The PDF document
76       const CFX_ByteString& face_name,  // [IN] Original name
77       FX_BOOL bTrueType,                // [IN] TrueType or Type1
78       FX_DWORD flags,   // [IN] PDF font flags (see PDF Reference section 5.7.1)
79       int font_weight,  // [IN] original font weight. 0 for not specified
80       int CharsetCP,    // [IN] code page for charset (see Win32 GetACP())
81       FX_BOOL bVertical,
82       CPDF_SubstFont* pSubstFont  // [OUT] Subst font data
83       ) override;
84
85   FT_Face m_SysFace;
86 };
87
88 CFontMapper* g_pFontMapper = NULL;
89 #endif  // #if _FX_OS_ == _FX_LINUX_EMBEDDED_
90
91 DLLEXPORT void STDCALL FPDF_InitLibrary() {
92   FPDF_InitLibraryWithConfig(nullptr);
93 }
94
95 DLLEXPORT void STDCALL FPDF_InitLibraryWithConfig(
96     const FPDF_LIBRARY_CONFIG* cfg) {
97   g_pCodecModule = new CCodec_ModuleMgr();
98
99   CFX_GEModule::Create(cfg ? cfg->m_pUserFontPaths : nullptr);
100   CFX_GEModule::Get()->SetCodecModule(g_pCodecModule);
101
102   CPDF_ModuleMgr::Create();
103   CPDF_ModuleMgr::Get()->SetCodecModule(g_pCodecModule);
104   CPDF_ModuleMgr::Get()->InitPageModule();
105   CPDF_ModuleMgr::Get()->InitRenderModule();
106   CPDF_ModuleMgr* pModuleMgr = CPDF_ModuleMgr::Get();
107   if (pModuleMgr) {
108     pModuleMgr->LoadEmbeddedGB1CMaps();
109     pModuleMgr->LoadEmbeddedJapan1CMaps();
110     pModuleMgr->LoadEmbeddedCNS1CMaps();
111     pModuleMgr->LoadEmbeddedKorea1CMaps();
112   }
113   if (cfg && cfg->version >= 2)
114     IJS_Runtime::Initialize(cfg->m_v8EmbedderSlot, cfg->m_pIsolate);
115 }
116
117 DLLEXPORT void STDCALL FPDF_DestroyLibrary() {
118 #if _FX_OS_ == _FX_LINUX_EMBEDDED_
119   delete g_pFontMapper;
120   g_pFontMapper = nullptr;
121 #endif
122   CPDF_ModuleMgr::Destroy();
123   CFX_GEModule::Destroy();
124   delete g_pCodecModule;
125   g_pCodecModule = nullptr;
126 }
127
128 #ifndef _WIN32
129 int g_LastError;
130 void SetLastError(int err) {
131   g_LastError = err;
132 }
133
134 int GetLastError() {
135   return g_LastError;
136 }
137 #endif
138
139 void ProcessParseError(FX_DWORD err_code) {
140   // Translate FPDFAPI error code to FPDFVIEW error code
141   switch (err_code) {
142     case PDFPARSE_ERROR_FILE:
143       err_code = FPDF_ERR_FILE;
144       break;
145     case PDFPARSE_ERROR_FORMAT:
146       err_code = FPDF_ERR_FORMAT;
147       break;
148     case PDFPARSE_ERROR_PASSWORD:
149       err_code = FPDF_ERR_PASSWORD;
150       break;
151     case PDFPARSE_ERROR_HANDLER:
152       err_code = FPDF_ERR_SECURITY;
153       break;
154   }
155   SetLastError(err_code);
156 }
157
158 DLLEXPORT void STDCALL FPDF_SetSandBoxPolicy(FPDF_DWORD policy,
159                                              FPDF_BOOL enable) {
160   return FSDK_SetSandBoxPolicy(policy, enable);
161 }
162
163 DLLEXPORT FPDF_DOCUMENT STDCALL FPDF_LoadDocument(FPDF_STRING file_path,
164                                                   FPDF_BYTESTRING password) {
165   // NOTE: the creation of the file needs to be by the embedder on the
166   // other side of this API.
167   IFX_FileRead* pFileAccess = FX_CreateFileRead((const FX_CHAR*)file_path);
168   if (!pFileAccess) {
169     return nullptr;
170   }
171
172   CPDF_Parser* pParser = new CPDF_Parser;
173   pParser->SetPassword(password);
174
175   FX_DWORD err_code = pParser->StartParse(pFileAccess);
176   if (err_code) {
177     delete pParser;
178     ProcessParseError(err_code);
179     return NULL;
180   }
181   return pParser->GetDocument();
182 }
183
184 class CMemFile final : public IFX_FileRead {
185  public:
186   CMemFile(uint8_t* pBuf, FX_FILESIZE size) : m_pBuf(pBuf), m_size(size) {}
187
188   virtual void Release() { delete this; }
189   virtual FX_FILESIZE GetSize() { return m_size; }
190   virtual FX_BOOL ReadBlock(void* buffer, FX_FILESIZE offset, size_t size) {
191     if (offset < 0) {
192       return FALSE;
193     }
194     FX_SAFE_FILESIZE newPos =
195         pdfium::base::checked_cast<FX_FILESIZE, size_t>(size);
196     newPos += offset;
197     if (!newPos.IsValid() || newPos.ValueOrDie() > (FX_DWORD)m_size) {
198       return FALSE;
199     }
200     FXSYS_memcpy(buffer, m_pBuf + offset, size);
201     return TRUE;
202   }
203
204  private:
205   ~CMemFile() {}
206
207   uint8_t* m_pBuf;
208   FX_FILESIZE m_size;
209 };
210 DLLEXPORT FPDF_DOCUMENT STDCALL FPDF_LoadMemDocument(const void* data_buf,
211                                                      int size,
212                                                      FPDF_BYTESTRING password) {
213   CPDF_Parser* pParser = new CPDF_Parser;
214   pParser->SetPassword(password);
215   CMemFile* pMemFile = new CMemFile((uint8_t*)data_buf, size);
216   FX_DWORD err_code = pParser->StartParse(pMemFile);
217   if (err_code) {
218     delete pParser;
219     ProcessParseError(err_code);
220     return NULL;
221   }
222   CPDF_Document* pDoc = NULL;
223   pDoc = pParser ? pParser->GetDocument() : NULL;
224   CheckUnSupportError(pDoc, err_code);
225   return pParser->GetDocument();
226 }
227
228 DLLEXPORT FPDF_DOCUMENT STDCALL
229 FPDF_LoadCustomDocument(FPDF_FILEACCESS* pFileAccess,
230                         FPDF_BYTESTRING password) {
231   CPDF_Parser* pParser = new CPDF_Parser;
232   pParser->SetPassword(password);
233   CPDF_CustomAccess* pFile = new CPDF_CustomAccess(pFileAccess);
234   FX_DWORD err_code = pParser->StartParse(pFile);
235   if (err_code) {
236     delete pParser;
237     ProcessParseError(err_code);
238     return NULL;
239   }
240   CPDF_Document* pDoc = NULL;
241   pDoc = pParser ? pParser->GetDocument() : NULL;
242   CheckUnSupportError(pDoc, err_code);
243   return pParser->GetDocument();
244 }
245
246 DLLEXPORT FPDF_BOOL STDCALL FPDF_GetFileVersion(FPDF_DOCUMENT doc,
247                                                 int* fileVersion) {
248   if (!doc || !fileVersion)
249     return FALSE;
250   *fileVersion = 0;
251   CPDF_Document* pDoc = (CPDF_Document*)doc;
252   CPDF_Parser* pParser = (CPDF_Parser*)pDoc->GetParser();
253   if (!pParser)
254     return FALSE;
255   *fileVersion = pParser->GetFileVersion();
256   return TRUE;
257 }
258
259 // jabdelmalek: changed return type from FX_DWORD to build on Linux (and match
260 // header).
261 DLLEXPORT unsigned long STDCALL FPDF_GetDocPermissions(FPDF_DOCUMENT document) {
262   if (document == NULL)
263     return 0;
264   CPDF_Document* pDoc = (CPDF_Document*)document;
265   CPDF_Parser* pParser = (CPDF_Parser*)pDoc->GetParser();
266   CPDF_Dictionary* pDict = pParser->GetEncryptDict();
267   if (pDict == NULL)
268     return (FX_DWORD)-1;
269
270   return pDict->GetInteger("P");
271 }
272
273 DLLEXPORT int STDCALL FPDF_GetSecurityHandlerRevision(FPDF_DOCUMENT document) {
274   if (document == NULL)
275     return -1;
276   CPDF_Document* pDoc = (CPDF_Document*)document;
277   CPDF_Parser* pParser = (CPDF_Parser*)pDoc->GetParser();
278   CPDF_Dictionary* pDict = pParser->GetEncryptDict();
279   if (pDict == NULL)
280     return -1;
281
282   return pDict->GetInteger("R");
283 }
284
285 DLLEXPORT int STDCALL FPDF_GetPageCount(FPDF_DOCUMENT document) {
286   if (document == NULL)
287     return 0;
288   return ((CPDF_Document*)document)->GetPageCount();
289 }
290
291 DLLEXPORT FPDF_PAGE STDCALL FPDF_LoadPage(FPDF_DOCUMENT document,
292                                           int page_index) {
293   if (document == NULL)
294     return NULL;
295   if (page_index < 0 || page_index >= FPDF_GetPageCount(document))
296     return NULL;
297
298   CPDF_Document* pDoc = (CPDF_Document*)document;
299   if (pDoc == NULL)
300     return NULL;
301   CPDF_Dictionary* pDict = pDoc->GetPage(page_index);
302   if (pDict == NULL)
303     return NULL;
304   CPDF_Page* pPage = new CPDF_Page;
305   pPage->Load(pDoc, pDict);
306   pPage->ParseContent();
307   return pPage;
308 }
309
310 DLLEXPORT double STDCALL FPDF_GetPageWidth(FPDF_PAGE page) {
311   if (!page)
312     return 0.0;
313   return ((CPDF_Page*)page)->GetPageWidth();
314 }
315
316 DLLEXPORT double STDCALL FPDF_GetPageHeight(FPDF_PAGE page) {
317   if (!page)
318     return 0.0;
319   return ((CPDF_Page*)page)->GetPageHeight();
320 }
321
322 void DropContext(void* data) {
323   delete (CRenderContext*)data;
324 }
325
326 #if defined(_DEBUG) || defined(DEBUG)
327 #define DEBUG_TRACE
328 #endif
329
330 #if defined(_WIN32)
331 DLLEXPORT void STDCALL FPDF_RenderPage(HDC dc,
332                                        FPDF_PAGE page,
333                                        int start_x,
334                                        int start_y,
335                                        int size_x,
336                                        int size_y,
337                                        int rotate,
338                                        int flags) {
339   if (page == NULL)
340     return;
341   CPDF_Page* pPage = (CPDF_Page*)page;
342
343   CRenderContext* pContext = new CRenderContext;
344   pPage->SetPrivateData((void*)1, pContext, DropContext);
345
346 #ifndef _WIN32_WCE
347   CFX_DIBitmap* pBitmap = NULL;
348   FX_BOOL bBackgroundAlphaNeeded = FALSE;
349   bBackgroundAlphaNeeded = pPage->BackgroundAlphaNeeded();
350   if (bBackgroundAlphaNeeded) {
351     pBitmap = new CFX_DIBitmap;
352     pBitmap->Create(size_x, size_y, FXDIB_Argb);
353     pBitmap->Clear(0x00ffffff);
354 #ifdef _SKIA_SUPPORT_
355     pContext->m_pDevice = new CFX_SkiaDevice;
356     ((CFX_SkiaDevice*)pContext->m_pDevice)->Attach((CFX_DIBitmap*)pBitmap);
357 #else
358     pContext->m_pDevice = new CFX_FxgeDevice;
359     ((CFX_FxgeDevice*)pContext->m_pDevice)->Attach((CFX_DIBitmap*)pBitmap);
360 #endif
361   } else
362     pContext->m_pDevice = new CFX_WindowsDevice(dc);
363
364   FPDF_RenderPage_Retail(pContext, page, start_x, start_y, size_x, size_y,
365                          rotate, flags, TRUE, NULL);
366
367   if (bBackgroundAlphaNeeded) {
368     if (pBitmap) {
369       CFX_WindowsDevice WinDC(dc);
370
371       if (WinDC.GetDeviceCaps(FXDC_DEVICE_CLASS) == FXDC_PRINTER) {
372         CFX_DIBitmap* pDst = new CFX_DIBitmap;
373         int pitch = pBitmap->GetPitch();
374         pDst->Create(size_x, size_y, FXDIB_Rgb32);
375         FXSYS_memset(pDst->GetBuffer(), -1, pitch * size_y);
376         pDst->CompositeBitmap(0, 0, size_x, size_y, pBitmap, 0, 0,
377                               FXDIB_BLEND_NORMAL, NULL, FALSE, NULL);
378         WinDC.StretchDIBits(pDst, 0, 0, size_x, size_y);
379         delete pDst;
380       } else
381         WinDC.SetDIBits(pBitmap, 0, 0);
382     }
383   }
384 #else
385   // get clip region
386   RECT rect, cliprect;
387   rect.left = start_x;
388   rect.top = start_y;
389   rect.right = start_x + size_x;
390   rect.bottom = start_y + size_y;
391   GetClipBox(dc, &cliprect);
392   IntersectRect(&rect, &rect, &cliprect);
393   int width = rect.right - rect.left;
394   int height = rect.bottom - rect.top;
395
396 #ifdef DEBUG_TRACE
397   {
398     char str[128];
399     memset(str, 0, sizeof(str));
400     FXSYS_snprintf(str, sizeof(str) - 1, "Rendering DIB %d x %d", width,
401                    height);
402     CPDF_ModuleMgr::Get()->ReportError(999, str);
403   }
404 #endif
405
406   // Create a DIB section
407   LPVOID pBuffer;
408   BITMAPINFOHEADER bmih;
409   FXSYS_memset(&bmih, 0, sizeof bmih);
410   bmih.biSize = sizeof bmih;
411   bmih.biBitCount = 24;
412   bmih.biHeight = -height;
413   bmih.biPlanes = 1;
414   bmih.biWidth = width;
415   pContext->m_hBitmap = CreateDIBSection(dc, (BITMAPINFO*)&bmih, DIB_RGB_COLORS,
416                                          &pBuffer, NULL, 0);
417   if (pContext->m_hBitmap == NULL) {
418 #if defined(DEBUG) || defined(_DEBUG)
419     char str[128];
420     memset(str, 0, sizeof(str));
421     FXSYS_snprintf(str, sizeof(str) - 1,
422                    "Error CreateDIBSection: %d x %d, error code = %d", width,
423                    height, GetLastError());
424     CPDF_ModuleMgr::Get()->ReportError(FPDFERR_OUT_OF_MEMORY, str);
425 #else
426     CPDF_ModuleMgr::Get()->ReportError(FPDFERR_OUT_OF_MEMORY, NULL);
427 #endif
428   }
429   FXSYS_memset(pBuffer, 0xff, height * ((width * 3 + 3) / 4 * 4));
430
431 #ifdef DEBUG_TRACE
432   { CPDF_ModuleMgr::Get()->ReportError(999, "DIBSection created"); }
433 #endif
434
435   // Create a device with this external buffer
436   pContext->m_pBitmap = new CFX_DIBitmap;
437   pContext->m_pBitmap->Create(width, height, FXDIB_Rgb, (uint8_t*)pBuffer);
438   pContext->m_pDevice = new CPDF_FxgeDevice;
439   ((CPDF_FxgeDevice*)pContext->m_pDevice)->Attach(pContext->m_pBitmap);
440
441 #ifdef DEBUG_TRACE
442   CPDF_ModuleMgr::Get()->ReportError(999, "Ready for PDF rendering");
443 #endif
444
445   // output to bitmap device
446   FPDF_RenderPage_Retail(pContext, page, start_x - rect.left,
447                          start_y - rect.top, size_x, size_y, rotate, flags);
448
449 #ifdef DEBUG_TRACE
450   CPDF_ModuleMgr::Get()->ReportError(999, "Finished PDF rendering");
451 #endif
452
453   // Now output to real device
454   HDC hMemDC = CreateCompatibleDC(dc);
455   if (hMemDC == NULL) {
456 #if defined(DEBUG) || defined(_DEBUG)
457     char str[128];
458     memset(str, 0, sizeof(str));
459     FXSYS_snprintf(str, sizeof(str) - 1,
460                    "Error CreateCompatibleDC. Error code = %d", GetLastError());
461     CPDF_ModuleMgr::Get()->ReportError(FPDFERR_OUT_OF_MEMORY, str);
462 #else
463     CPDF_ModuleMgr::Get()->ReportError(FPDFERR_OUT_OF_MEMORY, NULL);
464 #endif
465   }
466
467   HGDIOBJ hOldBitmap = SelectObject(hMemDC, pContext->m_hBitmap);
468
469 #ifdef DEBUG_TRACE
470   CPDF_ModuleMgr::Get()->ReportError(999, "Ready for screen rendering");
471 #endif
472
473   BitBlt(dc, rect.left, rect.top, width, height, hMemDC, 0, 0, SRCCOPY);
474   SelectObject(hMemDC, hOldBitmap);
475   DeleteDC(hMemDC);
476
477 #ifdef DEBUG_TRACE
478   CPDF_ModuleMgr::Get()->ReportError(999, "Finished screen rendering");
479 #endif
480
481 #endif
482   if (bBackgroundAlphaNeeded) {
483     delete pBitmap;
484     pBitmap = NULL;
485   }
486   delete pContext;
487   pPage->RemovePrivateData((void*)1);
488 }
489 #endif
490
491 DLLEXPORT void STDCALL FPDF_RenderPageBitmap(FPDF_BITMAP bitmap,
492                                              FPDF_PAGE page,
493                                              int start_x,
494                                              int start_y,
495                                              int size_x,
496                                              int size_y,
497                                              int rotate,
498                                              int flags) {
499   if (bitmap == NULL || page == NULL)
500     return;
501   CPDF_Page* pPage = (CPDF_Page*)page;
502
503   CRenderContext* pContext = new CRenderContext;
504   pPage->SetPrivateData((void*)1, pContext, DropContext);
505 #ifdef _SKIA_SUPPORT_
506   pContext->m_pDevice = new CFX_SkiaDevice;
507
508   if (flags & FPDF_REVERSE_BYTE_ORDER)
509     ((CFX_SkiaDevice*)pContext->m_pDevice)
510         ->Attach((CFX_DIBitmap*)bitmap, 0, TRUE);
511   else
512     ((CFX_SkiaDevice*)pContext->m_pDevice)->Attach((CFX_DIBitmap*)bitmap);
513 #else
514   pContext->m_pDevice = new CFX_FxgeDevice;
515
516   if (flags & FPDF_REVERSE_BYTE_ORDER)
517     ((CFX_FxgeDevice*)pContext->m_pDevice)
518         ->Attach((CFX_DIBitmap*)bitmap, 0, TRUE);
519   else
520     ((CFX_FxgeDevice*)pContext->m_pDevice)->Attach((CFX_DIBitmap*)bitmap);
521 #endif
522
523   FPDF_RenderPage_Retail(pContext, page, start_x, start_y, size_x, size_y,
524                          rotate, flags, TRUE, NULL);
525
526   delete pContext;
527   pPage->RemovePrivateData((void*)1);
528 }
529
530 DLLEXPORT void STDCALL FPDF_ClosePage(FPDF_PAGE page) {
531   if (!page)
532     return;
533   CPDFSDK_PageView* pPageView =
534       (CPDFSDK_PageView*)(((CPDF_Page*)page))->GetPrivateData((void*)page);
535   if (pPageView && pPageView->IsLocked()) {
536     pPageView->TakeOverPage();
537     return;
538   }
539   delete (CPDF_Page*)page;
540 }
541
542 DLLEXPORT void STDCALL FPDF_CloseDocument(FPDF_DOCUMENT document) {
543   if (!document)
544     return;
545   CPDF_Document* pDoc = (CPDF_Document*)document;
546   CPDF_Parser* pParser = (CPDF_Parser*)pDoc->GetParser();
547   if (pParser == NULL) {
548     delete pDoc;
549     return;
550   }
551   delete pParser;
552 }
553
554 DLLEXPORT unsigned long STDCALL FPDF_GetLastError() {
555   return GetLastError();
556 }
557
558 DLLEXPORT void STDCALL FPDF_DeviceToPage(FPDF_PAGE page,
559                                          int start_x,
560                                          int start_y,
561                                          int size_x,
562                                          int size_y,
563                                          int rotate,
564                                          int device_x,
565                                          int device_y,
566                                          double* page_x,
567                                          double* page_y) {
568   if (page == NULL || page_x == NULL || page_y == NULL)
569     return;
570   CPDF_Page* pPage = (CPDF_Page*)page;
571
572   CPDF_Matrix page2device;
573   pPage->GetDisplayMatrix(page2device, start_x, start_y, size_x, size_y,
574                           rotate);
575   CPDF_Matrix device2page;
576   device2page.SetReverse(page2device);
577
578   FX_FLOAT page_x_f, page_y_f;
579   device2page.Transform((FX_FLOAT)(device_x), (FX_FLOAT)(device_y), page_x_f,
580                         page_y_f);
581
582   *page_x = (page_x_f);
583   *page_y = (page_y_f);
584 }
585
586 DLLEXPORT void STDCALL FPDF_PageToDevice(FPDF_PAGE page,
587                                          int start_x,
588                                          int start_y,
589                                          int size_x,
590                                          int size_y,
591                                          int rotate,
592                                          double page_x,
593                                          double page_y,
594                                          int* device_x,
595                                          int* device_y) {
596   if (page == NULL || device_x == NULL || device_y == NULL)
597     return;
598   CPDF_Page* pPage = (CPDF_Page*)page;
599
600   CPDF_Matrix page2device;
601   pPage->GetDisplayMatrix(page2device, start_x, start_y, size_x, size_y,
602                           rotate);
603
604   FX_FLOAT device_x_f, device_y_f;
605   page2device.Transform(((FX_FLOAT)page_x), ((FX_FLOAT)page_y), device_x_f,
606                         device_y_f);
607
608   *device_x = FXSYS_round(device_x_f);
609   *device_y = FXSYS_round(device_y_f);
610 }
611
612 DLLEXPORT FPDF_BITMAP STDCALL FPDFBitmap_Create(int width,
613                                                 int height,
614                                                 int alpha) {
615   nonstd::unique_ptr<CFX_DIBitmap> pBitmap(new CFX_DIBitmap);
616   if (!pBitmap->Create(width, height, alpha ? FXDIB_Argb : FXDIB_Rgb32)) {
617     return NULL;
618   }
619   return pBitmap.release();
620 }
621
622 DLLEXPORT FPDF_BITMAP STDCALL FPDFBitmap_CreateEx(int width,
623                                                   int height,
624                                                   int format,
625                                                   void* first_scan,
626                                                   int stride) {
627   FXDIB_Format fx_format;
628   switch (format) {
629     case FPDFBitmap_Gray:
630       fx_format = FXDIB_8bppRgb;
631       break;
632     case FPDFBitmap_BGR:
633       fx_format = FXDIB_Rgb;
634       break;
635     case FPDFBitmap_BGRx:
636       fx_format = FXDIB_Rgb32;
637       break;
638     case FPDFBitmap_BGRA:
639       fx_format = FXDIB_Argb;
640       break;
641     default:
642       return NULL;
643   }
644   CFX_DIBitmap* pBitmap = new CFX_DIBitmap;
645   pBitmap->Create(width, height, fx_format, (uint8_t*)first_scan, stride);
646   return pBitmap;
647 }
648
649 DLLEXPORT void STDCALL FPDFBitmap_FillRect(FPDF_BITMAP bitmap,
650                                            int left,
651                                            int top,
652                                            int width,
653                                            int height,
654                                            FPDF_DWORD color) {
655   if (bitmap == NULL)
656     return;
657 #ifdef _SKIA_SUPPORT_
658   CFX_SkiaDevice device;
659 #else
660   CFX_FxgeDevice device;
661 #endif
662   device.Attach((CFX_DIBitmap*)bitmap);
663   if (!((CFX_DIBitmap*)bitmap)->HasAlpha())
664     color |= 0xFF000000;
665   FX_RECT rect(left, top, left + width, top + height);
666   device.FillRect(&rect, color);
667 }
668
669 DLLEXPORT void* STDCALL FPDFBitmap_GetBuffer(FPDF_BITMAP bitmap) {
670   if (bitmap == NULL)
671     return NULL;
672   return ((CFX_DIBitmap*)bitmap)->GetBuffer();
673 }
674
675 DLLEXPORT int STDCALL FPDFBitmap_GetWidth(FPDF_BITMAP bitmap) {
676   if (bitmap == NULL)
677     return 0;
678   return ((CFX_DIBitmap*)bitmap)->GetWidth();
679 }
680
681 DLLEXPORT int STDCALL FPDFBitmap_GetHeight(FPDF_BITMAP bitmap) {
682   if (bitmap == NULL)
683     return 0;
684   return ((CFX_DIBitmap*)bitmap)->GetHeight();
685 }
686
687 DLLEXPORT int STDCALL FPDFBitmap_GetStride(FPDF_BITMAP bitmap) {
688   if (bitmap == NULL)
689     return 0;
690   return ((CFX_DIBitmap*)bitmap)->GetPitch();
691 }
692
693 DLLEXPORT void STDCALL FPDFBitmap_Destroy(FPDF_BITMAP bitmap) {
694   delete (CFX_DIBitmap*)bitmap;
695 }
696
697 void FPDF_RenderPage_Retail(CRenderContext* pContext,
698                             FPDF_PAGE page,
699                             int start_x,
700                             int start_y,
701                             int size_x,
702                             int size_y,
703                             int rotate,
704                             int flags,
705                             FX_BOOL bNeedToRestore,
706                             IFSDK_PAUSE_Adapter* pause) {
707   CPDF_Page* pPage = (CPDF_Page*)page;
708   if (pPage == NULL)
709     return;
710
711   if (!pContext->m_pOptions)
712     pContext->m_pOptions = new CPDF_RenderOptions;
713
714   if (flags & FPDF_LCD_TEXT)
715     pContext->m_pOptions->m_Flags |= RENDER_CLEARTYPE;
716   else
717     pContext->m_pOptions->m_Flags &= ~RENDER_CLEARTYPE;
718   if (flags & FPDF_NO_NATIVETEXT)
719     pContext->m_pOptions->m_Flags |= RENDER_NO_NATIVETEXT;
720   if (flags & FPDF_RENDER_LIMITEDIMAGECACHE)
721     pContext->m_pOptions->m_Flags |= RENDER_LIMITEDIMAGECACHE;
722   if (flags & FPDF_RENDER_FORCEHALFTONE)
723     pContext->m_pOptions->m_Flags |= RENDER_FORCE_HALFTONE;
724   if (flags & FPDF_RENDER_NO_SMOOTHTEXT)
725     pContext->m_pOptions->m_Flags |= RENDER_NOTEXTSMOOTH;
726   if (flags & FPDF_RENDER_NO_SMOOTHIMAGE)
727     pContext->m_pOptions->m_Flags |= RENDER_NOIMAGESMOOTH;
728   if (flags & FPDF_RENDER_NO_SMOOTHPATH)
729     pContext->m_pOptions->m_Flags |= RENDER_NOPATHSMOOTH;
730   // Grayscale output
731   if (flags & FPDF_GRAYSCALE) {
732     pContext->m_pOptions->m_ColorMode = RENDER_COLOR_GRAY;
733     pContext->m_pOptions->m_ForeColor = 0;
734     pContext->m_pOptions->m_BackColor = 0xffffff;
735   }
736   const CPDF_OCContext::UsageType usage =
737       (flags & FPDF_PRINTING) ? CPDF_OCContext::Print : CPDF_OCContext::View;
738   pContext->m_pOptions->m_AddFlags = flags >> 8;
739   pContext->m_pOptions->m_pOCContext =
740       new CPDF_OCContext(pPage->m_pDocument, usage);
741
742   CFX_AffineMatrix matrix;
743   pPage->GetDisplayMatrix(matrix, start_x, start_y, size_x, size_y, rotate);
744
745   FX_RECT clip;
746   clip.left = start_x;
747   clip.right = start_x + size_x;
748   clip.top = start_y;
749   clip.bottom = start_y + size_y;
750   pContext->m_pDevice->SaveState();
751   pContext->m_pDevice->SetClip_Rect(&clip);
752
753   pContext->m_pContext = new CPDF_RenderContext;
754   pContext->m_pContext->Create(pPage);
755   pContext->m_pContext->AppendObjectList(pPage, &matrix);
756
757   if (flags & FPDF_ANNOT) {
758     pContext->m_pAnnots = new CPDF_AnnotList(pPage);
759     FX_BOOL bPrinting = pContext->m_pDevice->GetDeviceClass() != FXDC_DISPLAY;
760     pContext->m_pAnnots->DisplayAnnots(pPage, pContext->m_pContext, bPrinting,
761                                        &matrix, TRUE, NULL);
762   }
763
764   pContext->m_pRenderer = new CPDF_ProgressiveRenderer(
765       pContext->m_pContext, pContext->m_pDevice, pContext->m_pOptions);
766   pContext->m_pRenderer->Start(pause);
767   if (bNeedToRestore)
768     pContext->m_pDevice->RestoreState();
769 }
770
771 DLLEXPORT int STDCALL FPDF_GetPageSizeByIndex(FPDF_DOCUMENT document,
772                                               int page_index,
773                                               double* width,
774                                               double* height) {
775   CPDF_Document* pDoc = (CPDF_Document*)document;
776   if (pDoc == NULL)
777     return FALSE;
778
779   CPDF_Dictionary* pDict = pDoc->GetPage(page_index);
780   if (pDict == NULL)
781     return FALSE;
782
783   CPDF_Page page;
784   page.Load(pDoc, pDict);
785   *width = page.GetPageWidth();
786   *height = page.GetPageHeight();
787
788   return TRUE;
789 }
790
791 DLLEXPORT FPDF_BOOL STDCALL
792 FPDF_VIEWERREF_GetPrintScaling(FPDF_DOCUMENT document) {
793   CPDF_Document* pDoc = (CPDF_Document*)document;
794   if (!pDoc)
795     return TRUE;
796   CPDF_ViewerPreferences viewRef(pDoc);
797   return viewRef.PrintScaling();
798 }
799
800 DLLEXPORT int STDCALL FPDF_VIEWERREF_GetNumCopies(FPDF_DOCUMENT document) {
801   CPDF_Document* pDoc = (CPDF_Document*)document;
802   if (!pDoc)
803     return 1;
804   CPDF_ViewerPreferences viewRef(pDoc);
805   return viewRef.NumCopies();
806 }
807
808 DLLEXPORT FPDF_PAGERANGE STDCALL
809 FPDF_VIEWERREF_GetPrintPageRange(FPDF_DOCUMENT document) {
810   CPDF_Document* pDoc = (CPDF_Document*)document;
811   if (!pDoc)
812     return NULL;
813   CPDF_ViewerPreferences viewRef(pDoc);
814   return viewRef.PrintPageRange();
815 }
816
817 DLLEXPORT FPDF_DUPLEXTYPE STDCALL
818 FPDF_VIEWERREF_GetDuplex(FPDF_DOCUMENT document) {
819   CPDF_Document* pDoc = (CPDF_Document*)document;
820   if (!pDoc)
821     return DuplexUndefined;
822   CPDF_ViewerPreferences viewRef(pDoc);
823   CFX_ByteString duplex = viewRef.Duplex();
824   if (FX_BSTRC("Simplex") == duplex)
825     return Simplex;
826   if (FX_BSTRC("DuplexFlipShortEdge") == duplex)
827     return DuplexFlipShortEdge;
828   if (FX_BSTRC("DuplexFlipLongEdge") == duplex)
829     return DuplexFlipLongEdge;
830   return DuplexUndefined;
831 }
832
833 DLLEXPORT FPDF_DWORD STDCALL FPDF_CountNamedDests(FPDF_DOCUMENT document) {
834   if (!document)
835     return 0;
836   CPDF_Document* pDoc = (CPDF_Document*)document;
837
838   CPDF_Dictionary* pRoot = pDoc->GetRoot();
839   if (!pRoot)
840     return 0;
841
842   CPDF_NameTree nameTree(pDoc, FX_BSTRC("Dests"));
843   int count = nameTree.GetCount();
844   CPDF_Dictionary* pDest = pRoot->GetDict(FX_BSTRC("Dests"));
845   if (pDest)
846     count += pDest->GetCount();
847   return count;
848 }
849
850 DLLEXPORT FPDF_DEST STDCALL FPDF_GetNamedDestByName(FPDF_DOCUMENT document,
851                                                     FPDF_BYTESTRING name) {
852   if (!document)
853     return NULL;
854   if (!name || name[0] == 0)
855     return NULL;
856
857   CPDF_Document* pDoc = (CPDF_Document*)document;
858   CPDF_NameTree name_tree(pDoc, FX_BSTRC("Dests"));
859   return name_tree.LookupNamedDest(pDoc, name);
860 }
861
862 DLLEXPORT FPDF_DEST STDCALL FPDF_GetNamedDest(FPDF_DOCUMENT document,
863                                               int index,
864                                               void* buffer,
865                                               long* buflen) {
866   if (!buffer)
867     *buflen = 0;
868   if (!document || index < 0)
869     return NULL;
870   CPDF_Document* pDoc = (CPDF_Document*)document;
871
872   CPDF_Dictionary* pRoot = pDoc->GetRoot();
873   if (!pRoot)
874     return NULL;
875
876   CPDF_Object* pDestObj = NULL;
877   CFX_ByteString bsName;
878   CPDF_NameTree nameTree(pDoc, FX_BSTRC("Dests"));
879   int count = nameTree.GetCount();
880   if (index >= count) {
881     CPDF_Dictionary* pDest = pRoot->GetDict(FX_BSTRC("Dests"));
882     if (!pDest)
883       return NULL;
884     if (index >= count + pDest->GetCount())
885       return NULL;
886     index -= count;
887     FX_POSITION pos = pDest->GetStartPos();
888     int i = 0;
889     while (pos) {
890       pDestObj = pDest->GetNextElement(pos, bsName);
891       if (!pDestObj)
892         continue;
893       if (i == index)
894         break;
895       i++;
896     }
897   } else {
898     pDestObj = nameTree.LookupValue(index, bsName);
899   }
900   if (!pDestObj)
901     return NULL;
902   if (pDestObj->GetType() == PDFOBJ_DICTIONARY) {
903     pDestObj = ((CPDF_Dictionary*)pDestObj)->GetArray(FX_BSTRC("D"));
904     if (!pDestObj)
905       return NULL;
906   }
907   if (pDestObj->GetType() != PDFOBJ_ARRAY)
908     return NULL;
909   CFX_WideString wsName = PDF_DecodeText(bsName);
910   CFX_ByteString utf16Name = wsName.UTF16LE_Encode();
911   unsigned int len = utf16Name.GetLength();
912   if (!buffer) {
913     *buflen = len;
914   } else if (*buflen >= len) {
915     memcpy(buffer, utf16Name.c_str(), len);
916     *buflen = len;
917   } else {
918     *buflen = -1;
919   }
920   return (FPDF_DEST)pDestObj;
921 }