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