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 "public/fpdfview.h"
8
9#include <memory>
10
11#include "core/include/fxcodec/fx_codec.h"
12#include "core/include/fxcrt/fx_safe_types.h"
13#include "fpdfsdk/include/fsdk_define.h"
14#include "fpdfsdk/include/fsdk_mgr.h"
15#include "fpdfsdk/include/fsdk_rendercontext.h"
16#include "fpdfsdk/include/javascript/IJavaScript.h"
17#include "public/fpdf_ext.h"
18#include "public/fpdf_progressive.h"
19#include "third_party/base/numerics/safe_conversions_impl.h"
20
21#ifdef PDF_ENABLE_XFA
22#include "core/include/fpdfapi/fpdf_module.h"
23#include "fpdfsdk/include/fpdfxfa/fpdfxfa_app.h"
24#include "fpdfsdk/include/fpdfxfa/fpdfxfa_doc.h"
25#include "fpdfsdk/include/fpdfxfa/fpdfxfa_page.h"
26#include "fpdfsdk/include/fpdfxfa/fpdfxfa_util.h"
27#include "public/fpdf_formfill.h"
28#endif  // PDF_ENABLE_XFA
29
30UnderlyingDocumentType* UnderlyingFromFPDFDocument(FPDF_DOCUMENT doc) {
31  return static_cast<UnderlyingDocumentType*>(doc);
32}
33
34FPDF_DOCUMENT FPDFDocumentFromUnderlying(UnderlyingDocumentType* doc) {
35  return static_cast<FPDF_DOCUMENT>(doc);
36}
37
38UnderlyingPageType* UnderlyingFromFPDFPage(FPDF_PAGE page) {
39  return static_cast<UnderlyingPageType*>(page);
40}
41
42CPDF_Document* CPDFDocumentFromFPDFDocument(FPDF_DOCUMENT doc) {
43#ifdef PDF_ENABLE_XFA
44  return doc ? UnderlyingFromFPDFDocument(doc)->GetPDFDoc() : nullptr;
45#else   // PDF_ENABLE_XFA
46  return UnderlyingFromFPDFDocument(doc);
47#endif  // PDF_ENABLE_XFA
48}
49
50FPDF_DOCUMENT FPDFDocumentFromCPDFDocument(CPDF_Document* doc) {
51#ifdef PDF_ENABLE_XFA
52  return doc ? FPDFDocumentFromUnderlying(
53                   new CPDFXFA_Document(doc, CPDFXFA_App::GetInstance()))
54             : nullptr;
55#else   // PDF_ENABLE_XFA
56  return FPDFDocumentFromUnderlying(doc);
57#endif  // PDF_ENABLE_XFA
58}
59
60CPDF_Page* CPDFPageFromFPDFPage(FPDF_PAGE page) {
61#ifdef PDF_ENABLE_XFA
62  return page ? UnderlyingFromFPDFPage(page)->GetPDFPage() : nullptr;
63#else   // PDF_ENABLE_XFA
64  return UnderlyingFromFPDFPage(page);
65#endif  // PDF_ENABLE_XFA
66}
67
68#ifdef PDF_ENABLE_XFA
69CFPDF_FileStream::CFPDF_FileStream(FPDF_FILEHANDLER* pFS) {
70  m_pFS = pFS;
71  m_nCurPos = 0;
72}
73
74IFX_FileStream* CFPDF_FileStream::Retain() {
75  return this;
76}
77
78void CFPDF_FileStream::Release() {
79  if (m_pFS && m_pFS->Release)
80    m_pFS->Release(m_pFS->clientData);
81  delete this;
82}
83
84FX_FILESIZE CFPDF_FileStream::GetSize() {
85  if (m_pFS && m_pFS->GetSize)
86    return (FX_FILESIZE)m_pFS->GetSize(m_pFS->clientData);
87  return 0;
88}
89
90FX_BOOL CFPDF_FileStream::IsEOF() {
91  return m_nCurPos >= GetSize();
92}
93
94FX_BOOL CFPDF_FileStream::ReadBlock(void* buffer,
95                                    FX_FILESIZE offset,
96                                    size_t size) {
97  if (!buffer || !size || !m_pFS->ReadBlock)
98    return FALSE;
99
100  if (m_pFS->ReadBlock(m_pFS->clientData, (FPDF_DWORD)offset, buffer,
101                       (FPDF_DWORD)size) == 0) {
102    m_nCurPos = offset + size;
103    return TRUE;
104  }
105  return FALSE;
106}
107
108size_t CFPDF_FileStream::ReadBlock(void* buffer, size_t size) {
109  if (!buffer || !size || !m_pFS->ReadBlock)
110    return 0;
111
112  FX_FILESIZE nSize = GetSize();
113  if (m_nCurPos >= nSize)
114    return 0;
115  FX_FILESIZE dwAvail = nSize - m_nCurPos;
116  if (dwAvail < (FX_FILESIZE)size)
117    size = (size_t)dwAvail;
118  if (m_pFS->ReadBlock(m_pFS->clientData, (FPDF_DWORD)m_nCurPos, buffer,
119                       (FPDF_DWORD)size) == 0) {
120    m_nCurPos += size;
121    return size;
122  }
123
124  return 0;
125}
126
127FX_BOOL CFPDF_FileStream::WriteBlock(const void* buffer,
128                                     FX_FILESIZE offset,
129                                     size_t size) {
130  if (!m_pFS || !m_pFS->WriteBlock)
131    return FALSE;
132
133  if (m_pFS->WriteBlock(m_pFS->clientData, (FPDF_DWORD)offset, buffer,
134                        (FPDF_DWORD)size) == 0) {
135    m_nCurPos = offset + size;
136    return TRUE;
137  }
138  return FALSE;
139}
140
141FX_BOOL CFPDF_FileStream::Flush() {
142  if (!m_pFS || !m_pFS->Flush)
143    return TRUE;
144
145  return m_pFS->Flush(m_pFS->clientData) == 0;
146}
147#endif  // PDF_ENABLE_XFA
148
149CPDF_CustomAccess::CPDF_CustomAccess(FPDF_FILEACCESS* pFileAccess) {
150  m_FileAccess = *pFileAccess;
151#ifdef PDF_ENABLE_XFA
152  m_BufferOffset = (FX_DWORD)-1;
153#endif  // PDF_ENABLE_XFA
154}
155
156#ifdef PDF_ENABLE_XFA
157FX_BOOL CPDF_CustomAccess::GetByte(FX_DWORD pos, uint8_t& ch) {
158  if (pos >= m_FileAccess.m_FileLen)
159    return FALSE;
160  if (m_BufferOffset == (FX_DWORD)-1 || pos < m_BufferOffset ||
161      pos >= m_BufferOffset + 512) {
162    // Need to read from file access
163    m_BufferOffset = pos;
164    int size = 512;
165    if (pos + 512 > m_FileAccess.m_FileLen)
166      size = m_FileAccess.m_FileLen - pos;
167    if (!m_FileAccess.m_GetBlock(m_FileAccess.m_Param, m_BufferOffset, m_Buffer,
168                                 size))
169      return FALSE;
170  }
171  ch = m_Buffer[pos - m_BufferOffset];
172  return TRUE;
173}
174
175FX_BOOL CPDF_CustomAccess::GetBlock(FX_DWORD pos,
176                                    uint8_t* pBuf,
177                                    FX_DWORD size) {
178  if (pos + size > m_FileAccess.m_FileLen)
179    return FALSE;
180  return m_FileAccess.m_GetBlock(m_FileAccess.m_Param, pos, pBuf, size);
181}
182#endif  // PDF_ENABLE_XFA
183
184FX_BOOL CPDF_CustomAccess::ReadBlock(void* buffer,
185                                     FX_FILESIZE offset,
186                                     size_t size) {
187  if (offset < 0) {
188    return FALSE;
189  }
190  FX_SAFE_FILESIZE newPos =
191      pdfium::base::checked_cast<FX_FILESIZE, size_t>(size);
192  newPos += offset;
193  if (!newPos.IsValid() || newPos.ValueOrDie() > m_FileAccess.m_FileLen) {
194    return FALSE;
195  }
196  return m_FileAccess.m_GetBlock(m_FileAccess.m_Param, offset, (uint8_t*)buffer,
197                                 size);
198}
199
200// 0 bit: FPDF_POLICY_MACHINETIME_ACCESS
201static FX_DWORD foxit_sandbox_policy = 0xFFFFFFFF;
202
203void FSDK_SetSandBoxPolicy(FPDF_DWORD policy, FPDF_BOOL enable) {
204  switch (policy) {
205    case FPDF_POLICY_MACHINETIME_ACCESS: {
206      if (enable)
207        foxit_sandbox_policy |= 0x01;
208      else
209        foxit_sandbox_policy &= 0xFFFFFFFE;
210    } break;
211    default:
212      break;
213  }
214}
215
216FPDF_BOOL FSDK_IsSandBoxPolicyEnabled(FPDF_DWORD policy) {
217  switch (policy) {
218    case FPDF_POLICY_MACHINETIME_ACCESS:
219      return !!(foxit_sandbox_policy & 0x01);
220    default:
221      return FALSE;
222  }
223}
224
225CCodec_ModuleMgr* g_pCodecModule = nullptr;
226
227DLLEXPORT void STDCALL FPDF_InitLibrary() {
228  FPDF_InitLibraryWithConfig(nullptr);
229}
230
231DLLEXPORT void STDCALL FPDF_InitLibraryWithConfig(
232    const FPDF_LIBRARY_CONFIG* cfg) {
233  g_pCodecModule = new CCodec_ModuleMgr();
234
235  CFX_GEModule::Create(cfg ? cfg->m_pUserFontPaths : nullptr);
236  CFX_GEModule::Get()->SetCodecModule(g_pCodecModule);
237
238  CPDF_ModuleMgr::Create();
239  CPDF_ModuleMgr* pModuleMgr = CPDF_ModuleMgr::Get();
240  pModuleMgr->SetCodecModule(g_pCodecModule);
241  pModuleMgr->InitPageModule();
242  pModuleMgr->InitRenderModule();
243#ifdef PDF_ENABLE_XFA
244  CPDFXFA_App::GetInstance()->Initialize();
245#else   // PDF_ENABLE_XFA
246  pModuleMgr->LoadEmbeddedGB1CMaps();
247  pModuleMgr->LoadEmbeddedJapan1CMaps();
248  pModuleMgr->LoadEmbeddedCNS1CMaps();
249  pModuleMgr->LoadEmbeddedKorea1CMaps();
250#endif  // PDF_ENABLE_XFA
251  if (cfg && cfg->version >= 2)
252    IJS_Runtime::Initialize(cfg->m_v8EmbedderSlot, cfg->m_pIsolate);
253}
254
255DLLEXPORT void STDCALL FPDF_DestroyLibrary() {
256#ifdef PDF_ENABLE_XFA
257  CPDFXFA_App::ReleaseInstance();
258#endif  // PDF_ENABLE_XFA
259  CPDF_ModuleMgr::Destroy();
260  CFX_GEModule::Destroy();
261
262  delete g_pCodecModule;
263  g_pCodecModule = nullptr;
264}
265
266#ifndef _WIN32
267int g_LastError;
268void SetLastError(int err) {
269  g_LastError = err;
270}
271
272int GetLastError() {
273  return g_LastError;
274}
275#endif  // _WIN32
276
277void ProcessParseError(FX_DWORD err_code) {
278  // Translate FPDFAPI error code to FPDFVIEW error code
279  switch (err_code) {
280    case PDFPARSE_ERROR_FILE:
281      err_code = FPDF_ERR_FILE;
282      break;
283    case PDFPARSE_ERROR_FORMAT:
284      err_code = FPDF_ERR_FORMAT;
285      break;
286    case PDFPARSE_ERROR_PASSWORD:
287      err_code = FPDF_ERR_PASSWORD;
288      break;
289    case PDFPARSE_ERROR_HANDLER:
290      err_code = FPDF_ERR_SECURITY;
291      break;
292  }
293  SetLastError(err_code);
294}
295
296DLLEXPORT void STDCALL FPDF_SetSandBoxPolicy(FPDF_DWORD policy,
297                                             FPDF_BOOL enable) {
298  return FSDK_SetSandBoxPolicy(policy, enable);
299}
300
301DLLEXPORT FPDF_DOCUMENT STDCALL FPDF_LoadDocument(FPDF_STRING file_path,
302                                                  FPDF_BYTESTRING password) {
303  // NOTE: the creation of the file needs to be by the embedder on the
304  // other side of this API.
305  IFX_FileRead* pFileAccess = FX_CreateFileRead((const FX_CHAR*)file_path);
306  if (!pFileAccess) {
307    return nullptr;
308  }
309
310  CPDF_Parser* pParser = new CPDF_Parser;
311  pParser->SetPassword(password);
312
313  FX_DWORD err_code = pParser->StartParse(pFileAccess);
314  if (err_code) {
315    delete pParser;
316    ProcessParseError(err_code);
317    return NULL;
318  }
319#ifdef PDF_ENABLE_XFA
320  CPDF_Document* pPDFDoc = pParser->GetDocument();
321  if (!pPDFDoc)
322    return NULL;
323
324  CPDFXFA_App* pProvider = CPDFXFA_App::GetInstance();
325  return new CPDFXFA_Document(pPDFDoc, pProvider);
326#else   // PDF_ENABLE_XFA
327  return pParser->GetDocument();
328#endif  // PDF_ENABLE_XFA
329}
330
331#ifdef PDF_ENABLE_XFA
332DLLEXPORT FPDF_BOOL STDCALL FPDF_HasXFAField(FPDF_DOCUMENT document,
333                                             int* docType) {
334  if (!document)
335    return FALSE;
336
337  CPDF_Document* pdfDoc =
338      (static_cast<CPDFXFA_Document*>(document))->GetPDFDoc();
339  if (!pdfDoc)
340    return FALSE;
341
342  CPDF_Dictionary* pRoot = pdfDoc->GetRoot();
343  if (!pRoot)
344    return FALSE;
345
346  CPDF_Dictionary* pAcroForm = pRoot->GetDict("AcroForm");
347  if (!pAcroForm)
348    return FALSE;
349
350  CPDF_Object* pXFA = pAcroForm->GetElement("XFA");
351  if (!pXFA)
352    return FALSE;
353
354  FX_BOOL bDynamicXFA = pRoot->GetBoolean("NeedsRendering", FALSE);
355
356  if (bDynamicXFA)
357    *docType = DOCTYPE_DYNAMIC_XFA;
358  else
359    *docType = DOCTYPE_STATIC_XFA;
360
361  return TRUE;
362}
363
364DLLEXPORT FPDF_BOOL STDCALL FPDF_LoadXFA(FPDF_DOCUMENT document) {
365  return document && (static_cast<CPDFXFA_Document*>(document))->LoadXFADoc();
366}
367#endif  // PDF_ENABLE_XFA
368
369class CMemFile final : public IFX_FileRead {
370 public:
371  CMemFile(uint8_t* pBuf, FX_FILESIZE size) : m_pBuf(pBuf), m_size(size) {}
372
373  void Release() override { delete this; }
374  FX_FILESIZE GetSize() override { return m_size; }
375  FX_BOOL ReadBlock(void* buffer, FX_FILESIZE offset, size_t size) override {
376    if (offset < 0) {
377      return FALSE;
378    }
379    FX_SAFE_FILESIZE newPos =
380        pdfium::base::checked_cast<FX_FILESIZE, size_t>(size);
381    newPos += offset;
382    if (!newPos.IsValid() || newPos.ValueOrDie() > (FX_DWORD)m_size) {
383      return FALSE;
384    }
385    FXSYS_memcpy(buffer, m_pBuf + offset, size);
386    return TRUE;
387  }
388
389 private:
390  ~CMemFile() override {}
391
392  uint8_t* const m_pBuf;
393  const FX_FILESIZE m_size;
394};
395
396DLLEXPORT FPDF_DOCUMENT STDCALL FPDF_LoadMemDocument(const void* data_buf,
397                                                     int size,
398                                                     FPDF_BYTESTRING password) {
399  CPDF_Parser* pParser = new CPDF_Parser;
400  pParser->SetPassword(password);
401  CMemFile* pMemFile = new CMemFile((uint8_t*)data_buf, size);
402  FX_DWORD err_code = pParser->StartParse(pMemFile);
403  if (err_code) {
404    delete pParser;
405    ProcessParseError(err_code);
406    return NULL;
407  }
408  CPDF_Document* pDoc = NULL;
409  pDoc = pParser ? pParser->GetDocument() : NULL;
410  CheckUnSupportError(pDoc, err_code);
411  return FPDFDocumentFromCPDFDocument(pParser->GetDocument());
412}
413
414DLLEXPORT FPDF_DOCUMENT STDCALL
415FPDF_LoadCustomDocument(FPDF_FILEACCESS* pFileAccess,
416                        FPDF_BYTESTRING password) {
417  CPDF_Parser* pParser = new CPDF_Parser;
418  pParser->SetPassword(password);
419  CPDF_CustomAccess* pFile = new CPDF_CustomAccess(pFileAccess);
420  FX_DWORD err_code = pParser->StartParse(pFile);
421  if (err_code) {
422    delete pParser;
423    ProcessParseError(err_code);
424    return NULL;
425  }
426  CPDF_Document* pDoc = NULL;
427  pDoc = pParser ? pParser->GetDocument() : NULL;
428  CheckUnSupportError(pDoc, err_code);
429  return FPDFDocumentFromCPDFDocument(pParser->GetDocument());
430}
431
432DLLEXPORT FPDF_BOOL STDCALL FPDF_GetFileVersion(FPDF_DOCUMENT doc,
433                                                int* fileVersion) {
434  if (!fileVersion)
435    return FALSE;
436
437  *fileVersion = 0;
438  CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(doc);
439  if (!pDoc)
440    return FALSE;
441
442  CPDF_Parser* pParser = pDoc->GetParser();
443  if (!pParser)
444    return FALSE;
445
446  *fileVersion = pParser->GetFileVersion();
447  return TRUE;
448}
449
450// jabdelmalek: changed return type from FX_DWORD to build on Linux (and match
451// header).
452DLLEXPORT unsigned long STDCALL FPDF_GetDocPermissions(FPDF_DOCUMENT document) {
453  CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
454  if (!pDoc)
455#ifndef PDF_ENABLE_XFA
456    return 0;
457#else   // PDF_ENABLE_XFA
458    return (FX_DWORD)-1;
459#endif  // PDF_ENABLE_XFA
460
461  CPDF_Dictionary* pDict = pDoc->GetParser()->GetEncryptDict();
462  return pDict ? pDict->GetInteger("P") : (FX_DWORD)-1;
463}
464
465DLLEXPORT int STDCALL FPDF_GetSecurityHandlerRevision(FPDF_DOCUMENT document) {
466  CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
467  if (!pDoc)
468    return -1;
469
470  CPDF_Dictionary* pDict = pDoc->GetParser()->GetEncryptDict();
471  return pDict ? pDict->GetInteger("R") : -1;
472}
473
474DLLEXPORT int STDCALL FPDF_GetPageCount(FPDF_DOCUMENT document) {
475  UnderlyingDocumentType* pDoc = UnderlyingFromFPDFDocument(document);
476  return pDoc ? pDoc->GetPageCount() : 0;
477}
478
479DLLEXPORT FPDF_PAGE STDCALL FPDF_LoadPage(FPDF_DOCUMENT document,
480                                          int page_index) {
481  UnderlyingDocumentType* pDoc = UnderlyingFromFPDFDocument(document);
482  if (!pDoc)
483    return nullptr;
484
485  if (page_index < 0 || page_index >= pDoc->GetPageCount())
486    return nullptr;
487
488#ifdef PDF_ENABLE_XFA
489  return pDoc->GetPage(page_index);
490#else   // PDF_ENABLE_XFA
491  CPDF_Dictionary* pDict = pDoc->GetPage(page_index);
492  if (!pDict)
493    return NULL;
494  CPDF_Page* pPage = new CPDF_Page;
495  pPage->Load(pDoc, pDict);
496  pPage->ParseContent();
497  return pPage;
498#endif  // PDF_ENABLE_XFA
499}
500
501DLLEXPORT double STDCALL FPDF_GetPageWidth(FPDF_PAGE page) {
502  UnderlyingPageType* pPage = UnderlyingFromFPDFPage(page);
503  return pPage ? pPage->GetPageWidth() : 0.0;
504}
505
506DLLEXPORT double STDCALL FPDF_GetPageHeight(FPDF_PAGE page) {
507  UnderlyingPageType* pPage = UnderlyingFromFPDFPage(page);
508  return pPage ? pPage->GetPageHeight() : 0.0;
509}
510
511void DropContext(void* data) {
512  delete (CRenderContext*)data;
513}
514
515#if defined(_DEBUG) || defined(DEBUG)
516#define DEBUG_TRACE
517#endif
518
519#if defined(_WIN32)
520DLLEXPORT void STDCALL FPDF_RenderPage(HDC dc,
521                                       FPDF_PAGE page,
522                                       int start_x,
523                                       int start_y,
524                                       int size_x,
525                                       int size_y,
526                                       int rotate,
527                                       int flags) {
528  CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
529  if (!pPage)
530    return;
531
532  CRenderContext* pContext = new CRenderContext;
533  pPage->SetPrivateData((void*)1, pContext, DropContext);
534
535#ifndef _WIN32_WCE
536  CFX_DIBitmap* pBitmap = nullptr;
537  FX_BOOL bBackgroundAlphaNeeded = pPage->BackgroundAlphaNeeded();
538  FX_BOOL bHasImageMask = pPage->HasImageMask();
539  if (bBackgroundAlphaNeeded || bHasImageMask) {
540    pBitmap = new CFX_DIBitmap;
541    pBitmap->Create(size_x, size_y, FXDIB_Argb);
542    pBitmap->Clear(0x00ffffff);
543#ifdef _SKIA_SUPPORT_
544    pContext->m_pDevice = new CFX_SkiaDevice;
545    ((CFX_SkiaDevice*)pContext->m_pDevice)->Attach((CFX_DIBitmap*)pBitmap);
546#else
547    pContext->m_pDevice = new CFX_FxgeDevice;
548    ((CFX_FxgeDevice*)pContext->m_pDevice)->Attach((CFX_DIBitmap*)pBitmap);
549#endif
550  } else {
551    pContext->m_pDevice = new CFX_WindowsDevice(dc);
552  }
553
554  FPDF_RenderPage_Retail(pContext, page, start_x, start_y, size_x, size_y,
555                         rotate, flags, TRUE, NULL);
556
557  if (bBackgroundAlphaNeeded || bHasImageMask) {
558    if (pBitmap) {
559      CFX_WindowsDevice WinDC(dc);
560
561      if (WinDC.GetDeviceCaps(FXDC_DEVICE_CLASS) == FXDC_PRINTER) {
562        CFX_DIBitmap* pDst = new CFX_DIBitmap;
563        int pitch = pBitmap->GetPitch();
564        pDst->Create(size_x, size_y, FXDIB_Rgb32);
565        FXSYS_memset(pDst->GetBuffer(), -1, pitch * size_y);
566        pDst->CompositeBitmap(0, 0, size_x, size_y, pBitmap, 0, 0,
567                              FXDIB_BLEND_NORMAL, NULL, FALSE, NULL);
568        WinDC.StretchDIBits(pDst, 0, 0, size_x, size_y);
569        delete pDst;
570      } else {
571        WinDC.SetDIBits(pBitmap, 0, 0);
572      }
573    }
574  }
575#else
576  // get clip region
577  RECT rect, cliprect;
578  rect.left = start_x;
579  rect.top = start_y;
580  rect.right = start_x + size_x;
581  rect.bottom = start_y + size_y;
582  GetClipBox(dc, &cliprect);
583  IntersectRect(&rect, &rect, &cliprect);
584  int width = rect.right - rect.left;
585  int height = rect.bottom - rect.top;
586
587#ifdef DEBUG_TRACE
588  {
589    char str[128];
590    memset(str, 0, sizeof(str));
591    FXSYS_snprintf(str, sizeof(str) - 1, "Rendering DIB %d x %d", width,
592                   height);
593    CPDF_ModuleMgr::Get()->ReportError(999, str);
594  }
595#endif
596
597  // Create a DIB section
598  LPVOID pBuffer;
599  BITMAPINFOHEADER bmih;
600  FXSYS_memset(&bmih, 0, sizeof bmih);
601  bmih.biSize = sizeof bmih;
602  bmih.biBitCount = 24;
603  bmih.biHeight = -height;
604  bmih.biPlanes = 1;
605  bmih.biWidth = width;
606  pContext->m_hBitmap = CreateDIBSection(dc, (BITMAPINFO*)&bmih, DIB_RGB_COLORS,
607                                         &pBuffer, NULL, 0);
608  if (!pContext->m_hBitmap) {
609#if defined(DEBUG) || defined(_DEBUG)
610    char str[128];
611    memset(str, 0, sizeof(str));
612    FXSYS_snprintf(str, sizeof(str) - 1,
613                   "Error CreateDIBSection: %d x %d, error code = %d", width,
614                   height, GetLastError());
615    CPDF_ModuleMgr::Get()->ReportError(FPDFERR_OUT_OF_MEMORY, str);
616#else
617    CPDF_ModuleMgr::Get()->ReportError(FPDFERR_OUT_OF_MEMORY, NULL);
618#endif
619  }
620  FXSYS_memset(pBuffer, 0xff, height * ((width * 3 + 3) / 4 * 4));
621
622#ifdef DEBUG_TRACE
623  { CPDF_ModuleMgr::Get()->ReportError(999, "DIBSection created"); }
624#endif
625
626  // Create a device with this external buffer
627  pContext->m_pBitmap = new CFX_DIBitmap;
628  pContext->m_pBitmap->Create(width, height, FXDIB_Rgb, (uint8_t*)pBuffer);
629  pContext->m_pDevice = new CPDF_FxgeDevice;
630  ((CPDF_FxgeDevice*)pContext->m_pDevice)->Attach(pContext->m_pBitmap);
631
632#ifdef DEBUG_TRACE
633  CPDF_ModuleMgr::Get()->ReportError(999, "Ready for PDF rendering");
634#endif
635
636  // output to bitmap device
637  FPDF_RenderPage_Retail(pContext, page, start_x - rect.left,
638                         start_y - rect.top, size_x, size_y, rotate, flags);
639
640#ifdef DEBUG_TRACE
641  CPDF_ModuleMgr::Get()->ReportError(999, "Finished PDF rendering");
642#endif
643
644  // Now output to real device
645  HDC hMemDC = CreateCompatibleDC(dc);
646  if (!hMemDC) {
647#if defined(DEBUG) || defined(_DEBUG)
648    char str[128];
649    memset(str, 0, sizeof(str));
650    FXSYS_snprintf(str, sizeof(str) - 1,
651                   "Error CreateCompatibleDC. Error code = %d", GetLastError());
652    CPDF_ModuleMgr::Get()->ReportError(FPDFERR_OUT_OF_MEMORY, str);
653#else
654    CPDF_ModuleMgr::Get()->ReportError(FPDFERR_OUT_OF_MEMORY, NULL);
655#endif
656  }
657
658  HGDIOBJ hOldBitmap = SelectObject(hMemDC, pContext->m_hBitmap);
659
660#ifdef DEBUG_TRACE
661  CPDF_ModuleMgr::Get()->ReportError(999, "Ready for screen rendering");
662#endif
663
664  BitBlt(dc, rect.left, rect.top, width, height, hMemDC, 0, 0, SRCCOPY);
665  SelectObject(hMemDC, hOldBitmap);
666  DeleteDC(hMemDC);
667
668#ifdef DEBUG_TRACE
669  CPDF_ModuleMgr::Get()->ReportError(999, "Finished screen rendering");
670#endif
671
672#endif
673  if (bBackgroundAlphaNeeded || bHasImageMask)
674    delete pBitmap;
675
676  delete pContext;
677  pPage->RemovePrivateData((void*)1);
678}
679#endif
680
681DLLEXPORT void STDCALL FPDF_RenderPageBitmap(FPDF_BITMAP bitmap,
682                                             FPDF_PAGE page,
683                                             int start_x,
684                                             int start_y,
685                                             int size_x,
686                                             int size_y,
687                                             int rotate,
688                                             int flags) {
689  if (!bitmap)
690    return;
691  CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
692  if (!pPage)
693    return;
694  CRenderContext* pContext = new CRenderContext;
695  pPage->SetPrivateData((void*)1, pContext, DropContext);
696#ifdef _SKIA_SUPPORT_
697  pContext->m_pDevice = new CFX_SkiaDevice;
698
699  if (flags & FPDF_REVERSE_BYTE_ORDER)
700    ((CFX_SkiaDevice*)pContext->m_pDevice)
701        ->Attach((CFX_DIBitmap*)bitmap, 0, TRUE);
702  else
703    ((CFX_SkiaDevice*)pContext->m_pDevice)->Attach((CFX_DIBitmap*)bitmap);
704#else
705  pContext->m_pDevice = new CFX_FxgeDevice;
706
707  if (flags & FPDF_REVERSE_BYTE_ORDER)
708    ((CFX_FxgeDevice*)pContext->m_pDevice)
709        ->Attach((CFX_DIBitmap*)bitmap, 0, TRUE);
710  else
711    ((CFX_FxgeDevice*)pContext->m_pDevice)->Attach((CFX_DIBitmap*)bitmap);
712#endif
713
714  FPDF_RenderPage_Retail(pContext, page, start_x, start_y, size_x, size_y,
715                         rotate, flags, TRUE, NULL);
716
717  delete pContext;
718  pPage->RemovePrivateData((void*)1);
719}
720
721DLLEXPORT void STDCALL FPDF_ClosePage(FPDF_PAGE page) {
722  if (!page)
723    return;
724#ifdef PDF_ENABLE_XFA
725  CPDFXFA_Page* pPage = (CPDFXFA_Page*)page;
726  pPage->Release();
727#else   // PDF_ENABLE_XFA
728  CPDFSDK_PageView* pPageView =
729      (CPDFSDK_PageView*)(((CPDF_Page*)page))->GetPrivateData((void*)page);
730  if (pPageView && pPageView->IsLocked()) {
731    pPageView->TakeOverPage();
732    return;
733  }
734  delete (CPDF_Page*)page;
735#endif  // PDF_ENABLE_XFA
736}
737
738DLLEXPORT void STDCALL FPDF_CloseDocument(FPDF_DOCUMENT document) {
739#ifdef PDF_ENABLE_XFA
740  delete UnderlyingFromFPDFDocument(document);
741#else   // PDF_ENABLE_XFA
742  CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
743  if (!pDoc)
744    return;
745  CPDF_Parser* pParser = pDoc->GetParser();
746  if (!pParser) {
747    delete pDoc;
748    return;
749  }
750  delete pParser;
751#endif  // PDF_ENABLE_XFA
752}
753
754DLLEXPORT unsigned long STDCALL FPDF_GetLastError() {
755  return GetLastError();
756}
757
758DLLEXPORT void STDCALL FPDF_DeviceToPage(FPDF_PAGE page,
759                                         int start_x,
760                                         int start_y,
761                                         int size_x,
762                                         int size_y,
763                                         int rotate,
764                                         int device_x,
765                                         int device_y,
766                                         double* page_x,
767                                         double* page_y) {
768  if (!page || !page_x || !page_y)
769    return;
770  UnderlyingPageType* pPage = UnderlyingFromFPDFPage(page);
771#ifdef PDF_ENABLE_XFA
772  pPage->DeviceToPage(start_x, start_y, size_x, size_y, rotate, device_x,
773                      device_y, page_x, page_y);
774#else   // PDF_ENABLE_XFA
775  CFX_Matrix page2device;
776  pPage->GetDisplayMatrix(page2device, start_x, start_y, size_x, size_y,
777                          rotate);
778  CFX_Matrix device2page;
779  device2page.SetReverse(page2device);
780  FX_FLOAT page_x_f, page_y_f;
781  device2page.Transform((FX_FLOAT)(device_x), (FX_FLOAT)(device_y), page_x_f,
782                        page_y_f);
783  *page_x = (page_x_f);
784  *page_y = (page_y_f);
785#endif  // PDF_ENABLE_XFA
786}
787
788DLLEXPORT void STDCALL FPDF_PageToDevice(FPDF_PAGE page,
789                                         int start_x,
790                                         int start_y,
791                                         int size_x,
792                                         int size_y,
793                                         int rotate,
794                                         double page_x,
795                                         double page_y,
796                                         int* device_x,
797                                         int* device_y) {
798  if (!device_x || !device_y)
799    return;
800  UnderlyingPageType* pPage = UnderlyingFromFPDFPage(page);
801  if (!pPage)
802    return;
803#ifdef PDF_ENABLE_XFA
804  pPage->PageToDevice(start_x, start_y, size_x, size_y, rotate, page_x, page_y,
805                      device_x, device_y);
806#else   // PDF_ENABLE_XFA
807  CFX_Matrix page2device;
808  pPage->GetDisplayMatrix(page2device, start_x, start_y, size_x, size_y,
809                          rotate);
810  FX_FLOAT device_x_f, device_y_f;
811  page2device.Transform(((FX_FLOAT)page_x), ((FX_FLOAT)page_y), device_x_f,
812                        device_y_f);
813  *device_x = FXSYS_round(device_x_f);
814  *device_y = FXSYS_round(device_y_f);
815#endif  // PDF_ENABLE_XFA
816}
817
818DLLEXPORT FPDF_BITMAP STDCALL FPDFBitmap_Create(int width,
819                                                int height,
820                                                int alpha) {
821  std::unique_ptr<CFX_DIBitmap> pBitmap(new CFX_DIBitmap);
822  if (!pBitmap->Create(width, height, alpha ? FXDIB_Argb : FXDIB_Rgb32)) {
823    return NULL;
824  }
825  return pBitmap.release();
826}
827
828DLLEXPORT FPDF_BITMAP STDCALL FPDFBitmap_CreateEx(int width,
829                                                  int height,
830                                                  int format,
831                                                  void* first_scan,
832                                                  int stride) {
833  FXDIB_Format fx_format;
834  switch (format) {
835    case FPDFBitmap_Gray:
836      fx_format = FXDIB_8bppRgb;
837      break;
838    case FPDFBitmap_BGR:
839      fx_format = FXDIB_Rgb;
840      break;
841    case FPDFBitmap_BGRx:
842      fx_format = FXDIB_Rgb32;
843      break;
844    case FPDFBitmap_BGRA:
845      fx_format = FXDIB_Argb;
846      break;
847    default:
848      return NULL;
849  }
850  CFX_DIBitmap* pBitmap = new CFX_DIBitmap;
851  pBitmap->Create(width, height, fx_format, (uint8_t*)first_scan, stride);
852  return pBitmap;
853}
854
855DLLEXPORT void STDCALL FPDFBitmap_FillRect(FPDF_BITMAP bitmap,
856                                           int left,
857                                           int top,
858                                           int width,
859                                           int height,
860                                           FPDF_DWORD color) {
861  if (!bitmap)
862    return;
863#ifdef _SKIA_SUPPORT_
864  CFX_SkiaDevice device;
865#else
866  CFX_FxgeDevice device;
867#endif
868  device.Attach((CFX_DIBitmap*)bitmap);
869  if (!((CFX_DIBitmap*)bitmap)->HasAlpha())
870    color |= 0xFF000000;
871  FX_RECT rect(left, top, left + width, top + height);
872  device.FillRect(&rect, color);
873}
874
875DLLEXPORT void* STDCALL FPDFBitmap_GetBuffer(FPDF_BITMAP bitmap) {
876  return bitmap ? ((CFX_DIBitmap*)bitmap)->GetBuffer() : nullptr;
877}
878
879DLLEXPORT int STDCALL FPDFBitmap_GetWidth(FPDF_BITMAP bitmap) {
880  return bitmap ? ((CFX_DIBitmap*)bitmap)->GetWidth() : 0;
881}
882
883DLLEXPORT int STDCALL FPDFBitmap_GetHeight(FPDF_BITMAP bitmap) {
884  return bitmap ? ((CFX_DIBitmap*)bitmap)->GetHeight() : 0;
885}
886
887DLLEXPORT int STDCALL FPDFBitmap_GetStride(FPDF_BITMAP bitmap) {
888  return bitmap ? ((CFX_DIBitmap*)bitmap)->GetPitch() : 0;
889}
890
891DLLEXPORT void STDCALL FPDFBitmap_Destroy(FPDF_BITMAP bitmap) {
892  delete (CFX_DIBitmap*)bitmap;
893}
894
895void FPDF_RenderPage_Retail(CRenderContext* pContext,
896                            FPDF_PAGE page,
897                            int start_x,
898                            int start_y,
899                            int size_x,
900                            int size_y,
901                            int rotate,
902                            int flags,
903                            FX_BOOL bNeedToRestore,
904                            IFSDK_PAUSE_Adapter* pause) {
905  CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
906  if (!pPage)
907    return;
908
909  if (!pContext->m_pOptions)
910    pContext->m_pOptions = new CPDF_RenderOptions;
911
912  if (flags & FPDF_LCD_TEXT)
913    pContext->m_pOptions->m_Flags |= RENDER_CLEARTYPE;
914  else
915    pContext->m_pOptions->m_Flags &= ~RENDER_CLEARTYPE;
916  if (flags & FPDF_NO_NATIVETEXT)
917    pContext->m_pOptions->m_Flags |= RENDER_NO_NATIVETEXT;
918  if (flags & FPDF_RENDER_LIMITEDIMAGECACHE)
919    pContext->m_pOptions->m_Flags |= RENDER_LIMITEDIMAGECACHE;
920  if (flags & FPDF_RENDER_FORCEHALFTONE)
921    pContext->m_pOptions->m_Flags |= RENDER_FORCE_HALFTONE;
922#ifndef PDF_ENABLE_XFA
923  if (flags & FPDF_RENDER_NO_SMOOTHTEXT)
924    pContext->m_pOptions->m_Flags |= RENDER_NOTEXTSMOOTH;
925  if (flags & FPDF_RENDER_NO_SMOOTHIMAGE)
926    pContext->m_pOptions->m_Flags |= RENDER_NOIMAGESMOOTH;
927  if (flags & FPDF_RENDER_NO_SMOOTHPATH)
928    pContext->m_pOptions->m_Flags |= RENDER_NOPATHSMOOTH;
929#endif  // PDF_ENABLE_XFA
930  // Grayscale output
931  if (flags & FPDF_GRAYSCALE) {
932    pContext->m_pOptions->m_ColorMode = RENDER_COLOR_GRAY;
933    pContext->m_pOptions->m_ForeColor = 0;
934    pContext->m_pOptions->m_BackColor = 0xffffff;
935  }
936  const CPDF_OCContext::UsageType usage =
937      (flags & FPDF_PRINTING) ? CPDF_OCContext::Print : CPDF_OCContext::View;
938  pContext->m_pOptions->m_AddFlags = flags >> 8;
939  pContext->m_pOptions->m_pOCContext =
940      new CPDF_OCContext(pPage->m_pDocument, usage);
941
942  CFX_Matrix matrix;
943  pPage->GetDisplayMatrix(matrix, start_x, start_y, size_x, size_y, rotate);
944
945  FX_RECT clip;
946  clip.left = start_x;
947  clip.right = start_x + size_x;
948  clip.top = start_y;
949  clip.bottom = start_y + size_y;
950  pContext->m_pDevice->SaveState();
951  pContext->m_pDevice->SetClip_Rect(&clip);
952
953  pContext->m_pContext = new CPDF_RenderContext(pPage);
954  pContext->m_pContext->AppendObjectList(pPage, &matrix);
955
956  if (flags & FPDF_ANNOT) {
957    pContext->m_pAnnots = new CPDF_AnnotList(pPage);
958    FX_BOOL bPrinting = pContext->m_pDevice->GetDeviceClass() != FXDC_DISPLAY;
959    pContext->m_pAnnots->DisplayAnnots(pPage, pContext->m_pContext, bPrinting,
960                                       &matrix, TRUE, NULL);
961  }
962
963  pContext->m_pRenderer = new CPDF_ProgressiveRenderer(
964      pContext->m_pContext, pContext->m_pDevice, pContext->m_pOptions);
965  pContext->m_pRenderer->Start(pause);
966  if (bNeedToRestore)
967    pContext->m_pDevice->RestoreState();
968}
969
970DLLEXPORT int STDCALL FPDF_GetPageSizeByIndex(FPDF_DOCUMENT document,
971                                              int page_index,
972                                              double* width,
973                                              double* height) {
974  UnderlyingDocumentType* pDoc = UnderlyingFromFPDFDocument(document);
975  if (!pDoc)
976    return FALSE;
977
978#ifdef PDF_ENABLE_XFA
979  int count = pDoc->GetPageCount();
980  if (page_index < 0 || page_index >= count)
981    return FALSE;
982  CPDFXFA_Page* pPage = pDoc->GetPage(page_index);
983  if (!pPage)
984    return FALSE;
985  *width = pPage->GetPageWidth();
986  *height = pPage->GetPageHeight();
987#else   // PDF_ENABLE_XFA
988  CPDF_Dictionary* pDict = pDoc->GetPage(page_index);
989  if (!pDict)
990    return FALSE;
991  CPDF_Page page;
992  page.Load(pDoc, pDict);
993  *width = page.GetPageWidth();
994  *height = page.GetPageHeight();
995#endif  // PDF_ENABLE_XFA
996
997  return TRUE;
998}
999
1000DLLEXPORT FPDF_BOOL STDCALL
1001FPDF_VIEWERREF_GetPrintScaling(FPDF_DOCUMENT document) {
1002  CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
1003  if (!pDoc)
1004    return TRUE;
1005  CPDF_ViewerPreferences viewRef(pDoc);
1006  return viewRef.PrintScaling();
1007}
1008
1009DLLEXPORT int STDCALL FPDF_VIEWERREF_GetNumCopies(FPDF_DOCUMENT document) {
1010  CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
1011  if (!pDoc)
1012    return 1;
1013  CPDF_ViewerPreferences viewRef(pDoc);
1014  return viewRef.NumCopies();
1015}
1016
1017DLLEXPORT FPDF_PAGERANGE STDCALL
1018FPDF_VIEWERREF_GetPrintPageRange(FPDF_DOCUMENT document) {
1019  CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
1020  if (!pDoc)
1021    return NULL;
1022  CPDF_ViewerPreferences viewRef(pDoc);
1023  return viewRef.PrintPageRange();
1024}
1025
1026DLLEXPORT FPDF_DUPLEXTYPE STDCALL
1027FPDF_VIEWERREF_GetDuplex(FPDF_DOCUMENT document) {
1028  CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
1029  if (!pDoc)
1030    return DuplexUndefined;
1031  CPDF_ViewerPreferences viewRef(pDoc);
1032  CFX_ByteString duplex = viewRef.Duplex();
1033  if ("Simplex" == duplex)
1034    return Simplex;
1035  if ("DuplexFlipShortEdge" == duplex)
1036    return DuplexFlipShortEdge;
1037  if ("DuplexFlipLongEdge" == duplex)
1038    return DuplexFlipLongEdge;
1039  return DuplexUndefined;
1040}
1041
1042DLLEXPORT FPDF_DWORD STDCALL FPDF_CountNamedDests(FPDF_DOCUMENT document) {
1043  CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
1044  if (!pDoc)
1045    return 0;
1046
1047  CPDF_Dictionary* pRoot = pDoc->GetRoot();
1048  if (!pRoot)
1049    return 0;
1050
1051  CPDF_NameTree nameTree(pDoc, "Dests");
1052  pdfium::base::CheckedNumeric<FPDF_DWORD> count = nameTree.GetCount();
1053  CPDF_Dictionary* pDest = pRoot->GetDict("Dests");
1054  if (pDest)
1055    count += pDest->GetCount();
1056
1057  if (!count.IsValid())
1058    return 0;
1059
1060  return count.ValueOrDie();
1061}
1062
1063DLLEXPORT FPDF_DEST STDCALL FPDF_GetNamedDestByName(FPDF_DOCUMENT document,
1064                                                    FPDF_BYTESTRING name) {
1065  if (!name || name[0] == 0)
1066    return nullptr;
1067
1068  CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
1069  if (!pDoc)
1070    return nullptr;
1071
1072  CPDF_NameTree name_tree(pDoc, "Dests");
1073  return name_tree.LookupNamedDest(pDoc, name);
1074}
1075
1076#ifdef PDF_ENABLE_XFA
1077FPDF_RESULT FPDF_BStr_Init(FPDF_BSTR* str) {
1078  if (!str)
1079    return -1;
1080
1081  FXSYS_memset(str, 0, sizeof(FPDF_BSTR));
1082  return 0;
1083}
1084
1085FPDF_RESULT FPDF_BStr_Set(FPDF_BSTR* str, FPDF_LPCSTR bstr, int length) {
1086  if (!str)
1087    return -1;
1088  if (!bstr || !length)
1089    return -1;
1090  if (length == -1)
1091    length = FXSYS_strlen(bstr);
1092
1093  if (length == 0) {
1094    if (str->str) {
1095      FX_Free(str->str);
1096      str->str = NULL;
1097    }
1098    str->len = 0;
1099    return 0;
1100  }
1101
1102  if (str->str && str->len < length)
1103    str->str = FX_Realloc(char, str->str, length + 1);
1104  else if (!str->str)
1105    str->str = FX_Alloc(char, length + 1);
1106
1107  str->str[length] = 0;
1108  if (str->str == NULL)
1109    return -1;
1110
1111  FXSYS_memcpy(str->str, bstr, length);
1112  str->len = length;
1113
1114  return 0;
1115}
1116
1117FPDF_RESULT FPDF_BStr_Clear(FPDF_BSTR* str) {
1118  if (!str)
1119    return -1;
1120
1121  if (str->str) {
1122    FX_Free(str->str);
1123    str->str = NULL;
1124  }
1125  str->len = 0;
1126  return 0;
1127}
1128#endif  // PDF_ENABLE_XFA
1129
1130DLLEXPORT FPDF_DEST STDCALL FPDF_GetNamedDest(FPDF_DOCUMENT document,
1131                                              int index,
1132                                              void* buffer,
1133                                              long* buflen) {
1134  if (!buffer)
1135    *buflen = 0;
1136
1137  if (index < 0)
1138    return nullptr;
1139
1140  CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
1141  if (!pDoc)
1142    return nullptr;
1143
1144  CPDF_Dictionary* pRoot = pDoc->GetRoot();
1145  if (!pRoot)
1146    return nullptr;
1147
1148  CPDF_Object* pDestObj = nullptr;
1149  CFX_ByteString bsName;
1150  CPDF_NameTree nameTree(pDoc, "Dests");
1151  int count = nameTree.GetCount();
1152  if (index >= count) {
1153    CPDF_Dictionary* pDest = pRoot->GetDict("Dests");
1154    if (!pDest)
1155      return nullptr;
1156
1157    pdfium::base::CheckedNumeric<int> checked_count = count;
1158    checked_count += pDest->GetCount();
1159    if (!checked_count.IsValid() || index >= checked_count.ValueOrDie())
1160      return nullptr;
1161
1162    index -= count;
1163    int i = 0;
1164    for (const auto& it : *pDest) {
1165      bsName = it.first;
1166      pDestObj = it.second;
1167      if (!pDestObj)
1168        continue;
1169      if (i == index)
1170        break;
1171      i++;
1172    }
1173  } else {
1174    pDestObj = nameTree.LookupValue(index, bsName);
1175  }
1176  if (!pDestObj)
1177    return nullptr;
1178  if (CPDF_Dictionary* pDict = pDestObj->AsDictionary()) {
1179    pDestObj = pDict->GetArray("D");
1180    if (!pDestObj)
1181      return nullptr;
1182  }
1183  if (!pDestObj->IsArray())
1184    return nullptr;
1185
1186  CFX_WideString wsName = PDF_DecodeText(bsName);
1187  CFX_ByteString utf16Name = wsName.UTF16LE_Encode();
1188  unsigned int len = utf16Name.GetLength();
1189  if (!buffer) {
1190    *buflen = len;
1191  } else if (*buflen >= len) {
1192    memcpy(buffer, utf16Name.c_str(), len);
1193    *buflen = len;
1194  } else {
1195    *buflen = -1;
1196  }
1197  return (FPDF_DEST)pDestObj;
1198}
1199