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 #include <utility>
11 #include <vector>
12 
13 #include "build/build_config.h"
14 #include "core/fpdfapi/page/cpdf_docpagedata.h"
15 #include "core/fpdfapi/page/cpdf_occontext.h"
16 #include "core/fpdfapi/page/cpdf_page.h"
17 #include "core/fpdfapi/page/cpdf_pagemodule.h"
18 #include "core/fpdfapi/parser/cpdf_array.h"
19 #include "core/fpdfapi/parser/cpdf_dictionary.h"
20 #include "core/fpdfapi/parser/cpdf_document.h"
21 #include "core/fpdfapi/parser/cpdf_name.h"
22 #include "core/fpdfapi/parser/cpdf_parser.h"
23 #include "core/fpdfapi/parser/fpdf_parser_decode.h"
24 #include "core/fpdfapi/render/cpdf_docrenderdata.h"
25 #include "core/fpdfapi/render/cpdf_pagerendercache.h"
26 #include "core/fpdfapi/render/cpdf_pagerendercontext.h"
27 #include "core/fpdfapi/render/cpdf_rendercontext.h"
28 #include "core/fpdfapi/render/cpdf_renderoptions.h"
29 #include "core/fpdfdoc/cpdf_nametree.h"
30 #include "core/fpdfdoc/cpdf_viewerpreferences.h"
31 #include "core/fxcrt/cfx_readonlymemorystream.h"
32 #include "core/fxcrt/fx_stream.h"
33 #include "core/fxcrt/fx_system.h"
34 #include "core/fxcrt/unowned_ptr.h"
35 #include "core/fxge/cfx_defaultrenderdevice.h"
36 #include "core/fxge/cfx_gemodule.h"
37 #include "core/fxge/cfx_renderdevice.h"
38 #include "fpdfsdk/cpdfsdk_customaccess.h"
39 #include "fpdfsdk/cpdfsdk_formfillenvironment.h"
40 #include "fpdfsdk/cpdfsdk_helpers.h"
41 #include "fpdfsdk/cpdfsdk_pageview.h"
42 #include "fpdfsdk/cpdfsdk_renderpage.h"
43 #include "fxjs/ijs_runtime.h"
44 #include "public/fpdf_formfill.h"
45 #include "third_party/base/ptr_util.h"
46 #include "third_party/base/span.h"
47 
48 #ifdef PDF_ENABLE_XFA
49 #include "fpdfsdk/fpdfxfa/cpdfxfa_context.h"
50 #include "fpdfsdk/fpdfxfa/cpdfxfa_page.h"
51 #include "fxbarcode/BC_Library.h"
52 #endif  // PDF_ENABLE_XFA
53 
54 #if defined(OS_WIN)
55 #include "core/fpdfapi/render/cpdf_progressiverenderer.h"
56 #include "core/fpdfapi/render/cpdf_windowsrenderdevice.h"
57 #include "public/fpdf_edit.h"
58 
59 // These checks are here because core/ and public/ cannot depend on each other.
60 static_assert(WindowsPrintMode::kModeEmf == FPDF_PRINTMODE_EMF,
61               "WindowsPrintMode::kModeEmf value mismatch");
62 static_assert(WindowsPrintMode::kModeTextOnly == FPDF_PRINTMODE_TEXTONLY,
63               "WindowsPrintMode::kModeTextOnly value mismatch");
64 static_assert(WindowsPrintMode::kModePostScript2 == FPDF_PRINTMODE_POSTSCRIPT2,
65               "WindowsPrintMode::kModePostScript2 value mismatch");
66 static_assert(WindowsPrintMode::kModePostScript3 == FPDF_PRINTMODE_POSTSCRIPT3,
67               "WindowsPrintMode::kModePostScript3 value mismatch");
68 static_assert(WindowsPrintMode::kModePostScript2PassThrough ==
69                   FPDF_PRINTMODE_POSTSCRIPT2_PASSTHROUGH,
70               "WindowsPrintMode::kModePostScript2PassThrough value mismatch");
71 static_assert(WindowsPrintMode::kModePostScript3PassThrough ==
72                   FPDF_PRINTMODE_POSTSCRIPT3_PASSTHROUGH,
73               "WindowsPrintMode::kModePostScript3PassThrough value mismatch");
74 #endif  // defined(OS_WIN)
75 
76 namespace {
77 
78 bool g_bLibraryInitialized = false;
79 
LoadDocumentImpl(const RetainPtr<IFX_SeekableReadStream> & pFileAccess,FPDF_BYTESTRING password)80 FPDF_DOCUMENT LoadDocumentImpl(
81     const RetainPtr<IFX_SeekableReadStream>& pFileAccess,
82     FPDF_BYTESTRING password) {
83   if (!pFileAccess) {
84     ProcessParseError(CPDF_Parser::FILE_ERROR);
85     return nullptr;
86   }
87 
88   auto pDocument = pdfium::MakeUnique<CPDF_Document>(
89       pdfium::MakeUnique<CPDF_DocRenderData>(),
90       pdfium::MakeUnique<CPDF_DocPageData>());
91 
92   CPDF_Parser::Error error = pDocument->LoadDoc(pFileAccess, password);
93   if (error != CPDF_Parser::SUCCESS) {
94     ProcessParseError(error);
95     return nullptr;
96   }
97 
98   ReportUnsupportedFeatures(pDocument.get());
99   return FPDFDocumentFromCPDFDocument(pDocument.release());
100 }
101 
102 }  // namespace
103 
FPDF_InitLibrary()104 FPDF_EXPORT void FPDF_CALLCONV FPDF_InitLibrary() {
105   FPDF_InitLibraryWithConfig(nullptr);
106 }
107 
108 FPDF_EXPORT void FPDF_CALLCONV
FPDF_InitLibraryWithConfig(const FPDF_LIBRARY_CONFIG * config)109 FPDF_InitLibraryWithConfig(const FPDF_LIBRARY_CONFIG* config) {
110   if (g_bLibraryInitialized)
111     return;
112 
113   FXMEM_InitializePartitionAlloc();
114   CFX_GEModule::Create(config ? config->m_pUserFontPaths : nullptr);
115   CPDF_PageModule::Create();
116 
117 #ifdef PDF_ENABLE_XFA
118   BC_Library_Init();
119 #endif  // PDF_ENABLE_XFA
120   if (config && config->version >= 2)
121     IJS_Runtime::Initialize(config->m_v8EmbedderSlot, config->m_pIsolate);
122 
123   g_bLibraryInitialized = true;
124 }
125 
FPDF_DestroyLibrary()126 FPDF_EXPORT void FPDF_CALLCONV FPDF_DestroyLibrary() {
127   if (!g_bLibraryInitialized)
128     return;
129 
130 #ifdef PDF_ENABLE_XFA
131   BC_Library_Destroy();
132 #endif  // PDF_ENABLE_XFA
133 
134   CPDF_PageModule::Destroy();
135   CFX_GEModule::Destroy();
136   IJS_Runtime::Destroy();
137 
138   g_bLibraryInitialized = false;
139 }
140 
FPDF_SetSandBoxPolicy(FPDF_DWORD policy,FPDF_BOOL enable)141 FPDF_EXPORT void FPDF_CALLCONV FPDF_SetSandBoxPolicy(FPDF_DWORD policy,
142                                                      FPDF_BOOL enable) {
143   return SetPDFSandboxPolicy(policy, enable);
144 }
145 
146 #if defined(OS_WIN)
147 #if defined(PDFIUM_PRINT_TEXT_WITH_GDI)
148 FPDF_EXPORT void FPDF_CALLCONV
FPDF_SetTypefaceAccessibleFunc(PDFiumEnsureTypefaceCharactersAccessible func)149 FPDF_SetTypefaceAccessibleFunc(PDFiumEnsureTypefaceCharactersAccessible func) {
150   g_pdfium_typeface_accessible_func = func;
151 }
152 
FPDF_SetPrintTextWithGDI(FPDF_BOOL use_gdi)153 FPDF_EXPORT void FPDF_CALLCONV FPDF_SetPrintTextWithGDI(FPDF_BOOL use_gdi) {
154   g_pdfium_print_text_with_gdi = !!use_gdi;
155 }
156 #endif  // PDFIUM_PRINT_TEXT_WITH_GDI
157 
FPDF_SetPrintMode(int mode)158 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_SetPrintMode(int mode) {
159   if (mode < FPDF_PRINTMODE_EMF ||
160       mode > FPDF_PRINTMODE_POSTSCRIPT3_PASSTHROUGH) {
161     return FALSE;
162   }
163   g_pdfium_print_mode = static_cast<WindowsPrintMode>(mode);
164   return TRUE;
165 }
166 #endif  // defined(OS_WIN)
167 
168 FPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV
FPDF_LoadDocument(FPDF_STRING file_path,FPDF_BYTESTRING password)169 FPDF_LoadDocument(FPDF_STRING file_path, FPDF_BYTESTRING password) {
170   // NOTE: the creation of the file needs to be by the embedder on the
171   // other side of this API.
172   return LoadDocumentImpl(IFX_SeekableReadStream::CreateFromFilename(file_path),
173                           password);
174 }
175 
FPDF_GetFormType(FPDF_DOCUMENT document)176 FPDF_EXPORT int FPDF_CALLCONV FPDF_GetFormType(FPDF_DOCUMENT document) {
177   const CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
178   if (!pDoc)
179     return FORMTYPE_NONE;
180 
181   const CPDF_Dictionary* pRoot = pDoc->GetRoot();
182   if (!pRoot)
183     return FORMTYPE_NONE;
184 
185   const CPDF_Dictionary* pAcroForm = pRoot->GetDictFor("AcroForm");
186   if (!pAcroForm)
187     return FORMTYPE_NONE;
188 
189   const CPDF_Object* pXFA = pAcroForm->GetObjectFor("XFA");
190   if (!pXFA)
191     return FORMTYPE_ACRO_FORM;
192 
193   bool bNeedsRendering = pRoot->GetBooleanFor("NeedsRendering", false);
194   return bNeedsRendering ? FORMTYPE_XFA_FULL : FORMTYPE_XFA_FOREGROUND;
195 }
196 
FPDF_LoadXFA(FPDF_DOCUMENT document)197 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_LoadXFA(FPDF_DOCUMENT document) {
198 #ifdef PDF_ENABLE_XFA
199   auto* pDoc = CPDFDocumentFromFPDFDocument(document);
200   if (!pDoc)
201     return false;
202 
203   auto* pContext = static_cast<CPDFXFA_Context*>(pDoc->GetExtension());
204   if (pContext)
205     return pContext->LoadXFADoc();
206 #endif  // PDF_ENABLE_XFA
207   return false;
208 }
209 
210 FPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV
FPDF_LoadMemDocument(const void * data_buf,int size,FPDF_BYTESTRING password)211 FPDF_LoadMemDocument(const void* data_buf, int size, FPDF_BYTESTRING password) {
212   return LoadDocumentImpl(
213       pdfium::MakeRetain<CFX_ReadOnlyMemoryStream>(
214           pdfium::make_span(static_cast<const uint8_t*>(data_buf), size)),
215       password);
216 }
217 
218 FPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV
FPDF_LoadCustomDocument(FPDF_FILEACCESS * pFileAccess,FPDF_BYTESTRING password)219 FPDF_LoadCustomDocument(FPDF_FILEACCESS* pFileAccess,
220                         FPDF_BYTESTRING password) {
221   if (!pFileAccess)
222     return nullptr;
223   return LoadDocumentImpl(pdfium::MakeRetain<CPDFSDK_CustomAccess>(pFileAccess),
224                           password);
225 }
226 
FPDF_GetFileVersion(FPDF_DOCUMENT doc,int * fileVersion)227 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_GetFileVersion(FPDF_DOCUMENT doc,
228                                                         int* fileVersion) {
229   if (!fileVersion)
230     return false;
231 
232   *fileVersion = 0;
233   CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(doc);
234   if (!pDoc)
235     return false;
236 
237   const CPDF_Parser* pParser = pDoc->GetParser();
238   if (!pParser)
239     return false;
240 
241   *fileVersion = pParser->GetFileVersion();
242   return true;
243 }
244 
245 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDF_DocumentHasValidCrossReferenceTable(FPDF_DOCUMENT document)246 FPDF_DocumentHasValidCrossReferenceTable(FPDF_DOCUMENT document) {
247   CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
248   return pDoc && pDoc->has_valid_cross_reference_table();
249 }
250 
251 FPDF_EXPORT unsigned long FPDF_CALLCONV
FPDF_GetDocPermissions(FPDF_DOCUMENT document)252 FPDF_GetDocPermissions(FPDF_DOCUMENT document) {
253   CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
254   return pDoc ? pDoc->GetUserPermissions() : 0;
255 }
256 
257 FPDF_EXPORT int FPDF_CALLCONV
FPDF_GetSecurityHandlerRevision(FPDF_DOCUMENT document)258 FPDF_GetSecurityHandlerRevision(FPDF_DOCUMENT document) {
259   CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
260   if (!pDoc || !pDoc->GetParser())
261     return -1;
262 
263   const CPDF_Dictionary* pDict = pDoc->GetParser()->GetEncryptDict();
264   return pDict ? pDict->GetIntegerFor("R") : -1;
265 }
266 
FPDF_GetPageCount(FPDF_DOCUMENT document)267 FPDF_EXPORT int FPDF_CALLCONV FPDF_GetPageCount(FPDF_DOCUMENT document) {
268   auto* pDoc = CPDFDocumentFromFPDFDocument(document);
269   if (!pDoc)
270     return 0;
271 
272   auto* pExtension = pDoc->GetExtension();
273   return pExtension ? pExtension->GetPageCount() : pDoc->GetPageCount();
274 }
275 
FPDF_LoadPage(FPDF_DOCUMENT document,int page_index)276 FPDF_EXPORT FPDF_PAGE FPDF_CALLCONV FPDF_LoadPage(FPDF_DOCUMENT document,
277                                                   int page_index) {
278   auto* pDoc = CPDFDocumentFromFPDFDocument(document);
279   if (!pDoc)
280     return nullptr;
281 
282   if (page_index < 0 || page_index >= FPDF_GetPageCount(document))
283     return nullptr;
284 
285 #ifdef PDF_ENABLE_XFA
286   auto* pContext = static_cast<CPDFXFA_Context*>(pDoc->GetExtension());
287   if (pContext)
288     return FPDFPageFromIPDFPage(pContext->GetXFAPage(page_index).Leak());
289 #endif  // PDF_ENABLE_XFA
290 
291   CPDF_Dictionary* pDict = pDoc->GetPageDictionary(page_index);
292   if (!pDict)
293     return nullptr;
294 
295   auto pPage = pdfium::MakeRetain<CPDF_Page>(pDoc, pDict);
296   pPage->SetRenderCache(pdfium::MakeUnique<CPDF_PageRenderCache>(pPage.Get()));
297   pPage->ParseContent();
298   return FPDFPageFromIPDFPage(pPage.Leak());
299 }
300 
FPDF_GetPageWidthF(FPDF_PAGE page)301 FPDF_EXPORT float FPDF_CALLCONV FPDF_GetPageWidthF(FPDF_PAGE page) {
302   IPDF_Page* pPage = IPDFPageFromFPDFPage(page);
303   return pPage ? pPage->GetPageWidth() : 0.0f;
304 }
305 
FPDF_GetPageWidth(FPDF_PAGE page)306 FPDF_EXPORT double FPDF_CALLCONV FPDF_GetPageWidth(FPDF_PAGE page) {
307   return FPDF_GetPageWidthF(page);
308 }
309 
FPDF_GetPageHeightF(FPDF_PAGE page)310 FPDF_EXPORT float FPDF_CALLCONV FPDF_GetPageHeightF(FPDF_PAGE page) {
311   IPDF_Page* pPage = IPDFPageFromFPDFPage(page);
312   return pPage ? pPage->GetPageHeight() : 0.0f;
313 }
314 
FPDF_GetPageHeight(FPDF_PAGE page)315 FPDF_EXPORT double FPDF_CALLCONV FPDF_GetPageHeight(FPDF_PAGE page) {
316   return FPDF_GetPageHeightF(page);
317 }
318 
FPDF_GetPageBoundingBox(FPDF_PAGE page,FS_RECTF * rect)319 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_GetPageBoundingBox(FPDF_PAGE page,
320                                                             FS_RECTF* rect) {
321   if (!rect)
322     return false;
323 
324   CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
325   if (!pPage)
326     return false;
327 
328   *rect = FSRectFFromCFXFloatRect(pPage->GetBBox());
329   return true;
330 }
331 
332 #if defined(OS_WIN)
333 namespace {
334 
335 const double kEpsilonSize = 0.01f;
336 
GetScaling(CPDF_Page * pPage,int size_x,int size_y,int rotate,double * scale_x,double * scale_y)337 void GetScaling(CPDF_Page* pPage,
338                 int size_x,
339                 int size_y,
340                 int rotate,
341                 double* scale_x,
342                 double* scale_y) {
343   ASSERT(pPage);
344   ASSERT(scale_x);
345   ASSERT(scale_y);
346   double page_width = pPage->GetPageWidth();
347   double page_height = pPage->GetPageHeight();
348   if (page_width < kEpsilonSize || page_height < kEpsilonSize)
349     return;
350 
351   if (rotate % 2 == 0) {
352     *scale_x = size_x / page_width;
353     *scale_y = size_y / page_height;
354   } else {
355     *scale_x = size_y / page_width;
356     *scale_y = size_x / page_height;
357   }
358 }
359 
GetMaskDimensionsAndOffsets(CPDF_Page * pPage,int start_x,int start_y,int size_x,int size_y,int rotate,const CFX_FloatRect & mask_box)360 FX_RECT GetMaskDimensionsAndOffsets(CPDF_Page* pPage,
361                                     int start_x,
362                                     int start_y,
363                                     int size_x,
364                                     int size_y,
365                                     int rotate,
366                                     const CFX_FloatRect& mask_box) {
367   double scale_x = 0.0f;
368   double scale_y = 0.0f;
369   GetScaling(pPage, size_x, size_y, rotate, &scale_x, &scale_y);
370   if (scale_x < kEpsilonSize || scale_y < kEpsilonSize)
371     return FX_RECT();
372 
373   // Compute sizes in page points. Round down to catch the entire bitmap.
374   int start_x_bm = static_cast<int>(mask_box.left * scale_x);
375   int start_y_bm = static_cast<int>(mask_box.bottom * scale_y);
376   int size_x_bm = static_cast<int>(mask_box.right * scale_x + 1.0f) -
377                   static_cast<int>(mask_box.left * scale_x);
378   int size_y_bm = static_cast<int>(mask_box.top * scale_y + 1.0f) -
379                   static_cast<int>(mask_box.bottom * scale_y);
380 
381   // Get page rotation
382   int page_rotation = pPage->GetPageRotation();
383 
384   // Compute offsets
385   int offset_x = 0;
386   int offset_y = 0;
387   if (size_x > size_y)
388     std::swap(size_x_bm, size_y_bm);
389 
390   switch ((rotate + page_rotation) % 4) {
391     case 0:
392       offset_x = start_x_bm + start_x;
393       offset_y = start_y + size_y - size_y_bm - start_y_bm;
394       break;
395     case 1:
396       offset_x = start_y_bm + start_x;
397       offset_y = start_x_bm + start_y;
398       break;
399     case 2:
400       offset_x = start_x + size_x - size_x_bm - start_x_bm;
401       offset_y = start_y_bm + start_y;
402       break;
403     case 3:
404       offset_x = start_x + size_x - size_x_bm - start_y_bm;
405       offset_y = start_y + size_y - size_y_bm - start_x_bm;
406       break;
407   }
408   return FX_RECT(offset_x, offset_y, offset_x + size_x_bm,
409                  offset_y + size_y_bm);
410 }
411 
412 // Get a bitmap of just the mask section defined by |mask_box| from a full page
413 // bitmap |pBitmap|.
GetMaskBitmap(CPDF_Page * pPage,int start_x,int start_y,int size_x,int size_y,int rotate,const RetainPtr<CFX_DIBitmap> & pSrc,const CFX_FloatRect & mask_box,FX_RECT * bitmap_area)414 RetainPtr<CFX_DIBitmap> GetMaskBitmap(CPDF_Page* pPage,
415                                       int start_x,
416                                       int start_y,
417                                       int size_x,
418                                       int size_y,
419                                       int rotate,
420                                       const RetainPtr<CFX_DIBitmap>& pSrc,
421                                       const CFX_FloatRect& mask_box,
422                                       FX_RECT* bitmap_area) {
423   ASSERT(bitmap_area);
424   *bitmap_area = GetMaskDimensionsAndOffsets(pPage, start_x, start_y, size_x,
425                                              size_y, rotate, mask_box);
426   if (bitmap_area->IsEmpty())
427     return nullptr;
428 
429   // Create a new bitmap to transfer part of the page bitmap to.
430   RetainPtr<CFX_DIBitmap> pDst = pdfium::MakeRetain<CFX_DIBitmap>();
431   if (!pDst->Create(bitmap_area->Width(), bitmap_area->Height(), FXDIB_Argb))
432     return nullptr;
433 
434   pDst->Clear(0x00ffffff);
435   pDst->TransferBitmap(0, 0, bitmap_area->Width(), bitmap_area->Height(), pSrc,
436                        bitmap_area->left, bitmap_area->top);
437   return pDst;
438 }
439 
RenderBitmap(CFX_RenderDevice * device,const RetainPtr<CFX_DIBitmap> & pSrc,const FX_RECT & mask_area)440 void RenderBitmap(CFX_RenderDevice* device,
441                   const RetainPtr<CFX_DIBitmap>& pSrc,
442                   const FX_RECT& mask_area) {
443   int size_x_bm = mask_area.Width();
444   int size_y_bm = mask_area.Height();
445   if (size_x_bm == 0 || size_y_bm == 0)
446     return;
447 
448   // Create a new bitmap from the old one
449   RetainPtr<CFX_DIBitmap> pDst = pdfium::MakeRetain<CFX_DIBitmap>();
450   if (!pDst->Create(size_x_bm, size_y_bm, FXDIB_Rgb32))
451     return;
452 
453   pDst->Clear(0xffffffff);
454   pDst->CompositeBitmap(0, 0, size_x_bm, size_y_bm, pSrc, 0, 0,
455                         BlendMode::kNormal, nullptr, false);
456 
457   if (device->GetDeviceType() == DeviceType::kPrinter) {
458     device->StretchDIBits(pDst, mask_area.left, mask_area.top, size_x_bm,
459                           size_y_bm);
460   } else {
461     device->SetDIBits(pDst, mask_area.left, mask_area.top);
462   }
463 }
464 
465 }  // namespace
466 
FPDF_RenderPage(HDC dc,FPDF_PAGE page,int start_x,int start_y,int size_x,int size_y,int rotate,int flags)467 FPDF_EXPORT void FPDF_CALLCONV FPDF_RenderPage(HDC dc,
468                                                FPDF_PAGE page,
469                                                int start_x,
470                                                int start_y,
471                                                int size_x,
472                                                int size_y,
473                                                int rotate,
474                                                int flags) {
475   CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
476   if (!pPage)
477     return;
478 
479   auto pOwnedContext = pdfium::MakeUnique<CPDF_PageRenderContext>();
480   CPDF_PageRenderContext* pContext = pOwnedContext.get();
481   CPDF_Page::RenderContextClearer clearer(pPage);
482   pPage->SetRenderContext(std::move(pOwnedContext));
483 
484   // Don't render the full page to bitmap for a mask unless there are a lot
485   // of masks. Full page bitmaps result in large spool sizes, so they should
486   // only be used when necessary. For large numbers of masks, rendering each
487   // individually is inefficient and unlikely to significantly improve spool
488   // size. TODO(rbpotter): Find out why this still breaks printing for some
489   // PDFs (see crbug.com/777837).
490   const bool bEnableImageMasks = false;
491   const bool bNewBitmap = pPage->BackgroundAlphaNeeded() ||
492                           (pPage->HasImageMask() && !bEnableImageMasks) ||
493                           pPage->GetMaskBoundingBoxes().size() > 100;
494   const bool bHasMask = pPage->HasImageMask() && !bNewBitmap;
495   if (!bNewBitmap && !bHasMask) {
496     pContext->m_pDevice = pdfium::MakeUnique<CPDF_WindowsRenderDevice>(dc);
497     CPDFSDK_RenderPageWithContext(pContext, pPage, start_x, start_y, size_x,
498                                   size_y, rotate, flags,
499                                   /*need_to_restore=*/true, /*pause=*/nullptr);
500     return;
501   }
502 
503   RetainPtr<CFX_DIBitmap> pBitmap = pdfium::MakeRetain<CFX_DIBitmap>();
504   // Create will probably work fine even if it fails here: we will just attach
505   // a zero-sized bitmap to |pDevice|.
506   pBitmap->Create(size_x, size_y, FXDIB_Argb);
507   pBitmap->Clear(0x00ffffff);
508   CFX_DefaultRenderDevice* pDevice = new CFX_DefaultRenderDevice;
509   pContext->m_pDevice = pdfium::WrapUnique(pDevice);
510   pDevice->Attach(pBitmap, false, nullptr, false);
511   if (bHasMask) {
512     pContext->m_pOptions = pdfium::MakeUnique<CPDF_RenderOptions>();
513     pContext->m_pOptions->GetOptions().bBreakForMasks = true;
514   }
515 
516   CPDFSDK_RenderPageWithContext(pContext, pPage, start_x, start_y, size_x,
517                                 size_y, rotate, flags, /*need_to_restore=*/true,
518                                 /*pause=*/nullptr);
519 
520   if (!bHasMask) {
521     CPDF_WindowsRenderDevice WinDC(dc);
522     bool bitsStretched = false;
523     if (WinDC.GetDeviceType() == DeviceType::kPrinter) {
524       auto pDst = pdfium::MakeRetain<CFX_DIBitmap>();
525       if (pDst->Create(size_x, size_y, FXDIB_Rgb32)) {
526         memset(pDst->GetBuffer(), -1, pBitmap->GetPitch() * size_y);
527         pDst->CompositeBitmap(0, 0, size_x, size_y, pBitmap, 0, 0,
528                               BlendMode::kNormal, nullptr, false);
529         WinDC.StretchDIBits(pDst, 0, 0, size_x, size_y);
530         bitsStretched = true;
531       }
532     }
533     if (!bitsStretched)
534       WinDC.SetDIBits(pBitmap, 0, 0);
535     return;
536   }
537 
538   // Finish rendering the page to bitmap and copy the correct segments
539   // of the page to individual image mask bitmaps.
540   const std::vector<CFX_FloatRect>& mask_boxes = pPage->GetMaskBoundingBoxes();
541   std::vector<FX_RECT> bitmap_areas(mask_boxes.size());
542   std::vector<RetainPtr<CFX_DIBitmap>> bitmaps(mask_boxes.size());
543   for (size_t i = 0; i < mask_boxes.size(); i++) {
544     bitmaps[i] = GetMaskBitmap(pPage, start_x, start_y, size_x, size_y, rotate,
545                                pBitmap, mask_boxes[i], &bitmap_areas[i]);
546     pContext->m_pRenderer->Continue(nullptr);
547   }
548 
549   // Begin rendering to the printer. Add flag to indicate the renderer should
550   // pause after each image mask.
551   pOwnedContext = pdfium::MakeUnique<CPDF_PageRenderContext>();
552   pContext = pOwnedContext.get();
553   pPage->SetRenderContext(std::move(pOwnedContext));
554   pContext->m_pDevice = pdfium::MakeUnique<CPDF_WindowsRenderDevice>(dc);
555   pContext->m_pOptions = pdfium::MakeUnique<CPDF_RenderOptions>();
556   pContext->m_pOptions->GetOptions().bBreakForMasks = true;
557 
558   CPDFSDK_RenderPageWithContext(pContext, pPage, start_x, start_y, size_x,
559                                 size_y, rotate, flags, /*need_to_restore=*/true,
560                                 /*pause=*/nullptr);
561 
562   // Render masks
563   for (size_t i = 0; i < mask_boxes.size(); i++) {
564     // Render the bitmap for the mask and free the bitmap.
565     if (bitmaps[i]) {  // will be null if mask has zero area
566       RenderBitmap(pContext->m_pDevice.get(), bitmaps[i], bitmap_areas[i]);
567     }
568     // Render the next portion of page.
569     pContext->m_pRenderer->Continue(nullptr);
570   }
571 }
572 #endif  // defined(OS_WIN)
573 
FPDF_RenderPageBitmap(FPDF_BITMAP bitmap,FPDF_PAGE page,int start_x,int start_y,int size_x,int size_y,int rotate,int flags)574 FPDF_EXPORT void FPDF_CALLCONV FPDF_RenderPageBitmap(FPDF_BITMAP bitmap,
575                                                      FPDF_PAGE page,
576                                                      int start_x,
577                                                      int start_y,
578                                                      int size_x,
579                                                      int size_y,
580                                                      int rotate,
581                                                      int flags) {
582   if (!bitmap)
583     return;
584 
585   CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
586   if (!pPage)
587     return;
588 
589   auto pOwnedContext = pdfium::MakeUnique<CPDF_PageRenderContext>();
590   CPDF_PageRenderContext* pContext = pOwnedContext.get();
591   CPDF_Page::RenderContextClearer clearer(pPage);
592   pPage->SetRenderContext(std::move(pOwnedContext));
593 
594   auto pOwnedDevice = pdfium::MakeUnique<CFX_DefaultRenderDevice>();
595   CFX_DefaultRenderDevice* pDevice = pOwnedDevice.get();
596   pContext->m_pDevice = std::move(pOwnedDevice);
597 
598   RetainPtr<CFX_DIBitmap> pBitmap(CFXDIBitmapFromFPDFBitmap(bitmap));
599   pDevice->Attach(pBitmap, !!(flags & FPDF_REVERSE_BYTE_ORDER), nullptr, false);
600   CPDFSDK_RenderPageWithContext(pContext, pPage, start_x, start_y, size_x,
601                                 size_y, rotate, flags, /*need_to_restore=*/true,
602                                 /*pause=*/nullptr);
603 
604 #ifdef _SKIA_SUPPORT_PATHS_
605   pDevice->Flush(true);
606   pBitmap->UnPreMultiply();
607 #endif
608 }
609 
610 FPDF_EXPORT void FPDF_CALLCONV
FPDF_RenderPageBitmapWithMatrix(FPDF_BITMAP bitmap,FPDF_PAGE page,const FS_MATRIX * matrix,const FS_RECTF * clipping,int flags)611 FPDF_RenderPageBitmapWithMatrix(FPDF_BITMAP bitmap,
612                                 FPDF_PAGE page,
613                                 const FS_MATRIX* matrix,
614                                 const FS_RECTF* clipping,
615                                 int flags) {
616   if (!bitmap)
617     return;
618 
619   CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
620   if (!pPage)
621     return;
622 
623   auto pOwnedContext = pdfium::MakeUnique<CPDF_PageRenderContext>();
624   CPDF_PageRenderContext* pContext = pOwnedContext.get();
625   CPDF_Page::RenderContextClearer clearer(pPage);
626   pPage->SetRenderContext(std::move(pOwnedContext));
627 
628   auto pOwnedDevice = pdfium::MakeUnique<CFX_DefaultRenderDevice>();
629   CFX_DefaultRenderDevice* pDevice = pOwnedDevice.get();
630   pContext->m_pDevice = std::move(pOwnedDevice);
631 
632   RetainPtr<CFX_DIBitmap> pBitmap(CFXDIBitmapFromFPDFBitmap(bitmap));
633   pDevice->Attach(pBitmap, !!(flags & FPDF_REVERSE_BYTE_ORDER), nullptr, false);
634 
635   CFX_FloatRect clipping_rect;
636   if (clipping)
637     clipping_rect = CFXFloatRectFromFSRectF(*clipping);
638   FX_RECT clip_rect = clipping_rect.ToFxRect();
639 
640   const FX_RECT rect(0, 0, pPage->GetPageWidth(), pPage->GetPageHeight());
641   CFX_Matrix transform_matrix = pPage->GetDisplayMatrix(rect, 0);
642   if (matrix)
643     transform_matrix *= CFXMatrixFromFSMatrix(*matrix);
644   CPDFSDK_RenderPage(pContext, pPage, transform_matrix, clip_rect, flags);
645 }
646 
647 #ifdef _SKIA_SUPPORT_
FPDF_RenderPageSkp(FPDF_PAGE page,int size_x,int size_y)648 FPDF_EXPORT FPDF_RECORDER FPDF_CALLCONV FPDF_RenderPageSkp(FPDF_PAGE page,
649                                                            int size_x,
650                                                            int size_y) {
651   CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
652   if (!pPage)
653     return nullptr;
654 
655   auto pOwnedContext = pdfium::MakeUnique<CPDF_PageRenderContext>();
656   CPDF_PageRenderContext* pContext = pOwnedContext.get();
657   CPDF_Page::RenderContextClearer clearer(pPage);
658   pPage->SetRenderContext(std::move(pOwnedContext));
659 
660   auto skDevice = pdfium::MakeUnique<CFX_DefaultRenderDevice>();
661   FPDF_RECORDER recorder = skDevice->CreateRecorder(size_x, size_y);
662   pContext->m_pDevice = std::move(skDevice);
663 
664   CPDFSDK_RenderPageWithContext(pContext, pPage, 0, 0, size_x, size_y, 0, 0,
665                                 /*need_to_restore=*/true, /*pause=*/nullptr);
666   return recorder;
667 }
668 #endif  // _SKIA_SUPPORT_
669 
FPDF_ClosePage(FPDF_PAGE page)670 FPDF_EXPORT void FPDF_CALLCONV FPDF_ClosePage(FPDF_PAGE page) {
671   if (!page)
672     return;
673 
674   // Take it back across the API and hold for duration of this function.
675   RetainPtr<IPDF_Page> pPage;
676   pPage.Unleak(IPDFPageFromFPDFPage(page));
677 
678   if (pPage->AsXFAPage())
679     return;
680 
681   CPDFSDK_PageView* pPageView =
682       static_cast<CPDFSDK_PageView*>(pPage->AsPDFPage()->GetView());
683   if (!pPageView || pPageView->IsBeingDestroyed())
684     return;
685 
686   if (pPageView->IsLocked()) {
687     pPageView->TakePageOwnership();
688     return;
689   }
690 
691   // This will delete the |pPageView| object. We must cleanup the PageView
692   // first because it will attempt to reset the View on the |pPage| during
693   // destruction.
694   pPageView->GetFormFillEnv()->RemovePageView(pPage.Get());
695 }
696 
FPDF_CloseDocument(FPDF_DOCUMENT document)697 FPDF_EXPORT void FPDF_CALLCONV FPDF_CloseDocument(FPDF_DOCUMENT document) {
698   // Take it back across the API and throw it away,
699   std::unique_ptr<CPDF_Document>(CPDFDocumentFromFPDFDocument(document));
700 }
701 
FPDF_GetLastError()702 FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetLastError() {
703   return FXSYS_GetLastError();
704 }
705 
FPDF_DeviceToPage(FPDF_PAGE page,int start_x,int start_y,int size_x,int size_y,int rotate,int device_x,int device_y,double * page_x,double * page_y)706 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_DeviceToPage(FPDF_PAGE page,
707                                                       int start_x,
708                                                       int start_y,
709                                                       int size_x,
710                                                       int size_y,
711                                                       int rotate,
712                                                       int device_x,
713                                                       int device_y,
714                                                       double* page_x,
715                                                       double* page_y) {
716   if (!page || !page_x || !page_y)
717     return false;
718 
719   IPDF_Page* pPage = IPDFPageFromFPDFPage(page);
720   const FX_RECT rect(start_x, start_y, start_x + size_x, start_y + size_y);
721   Optional<CFX_PointF> pos =
722       pPage->DeviceToPage(rect, rotate, CFX_PointF(device_x, device_y));
723   if (!pos)
724     return false;
725 
726   *page_x = pos->x;
727   *page_y = pos->y;
728   return true;
729 }
730 
FPDF_PageToDevice(FPDF_PAGE page,int start_x,int start_y,int size_x,int size_y,int rotate,double page_x,double page_y,int * device_x,int * device_y)731 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_PageToDevice(FPDF_PAGE page,
732                                                       int start_x,
733                                                       int start_y,
734                                                       int size_x,
735                                                       int size_y,
736                                                       int rotate,
737                                                       double page_x,
738                                                       double page_y,
739                                                       int* device_x,
740                                                       int* device_y) {
741   if (!page || !device_x || !device_y)
742     return false;
743 
744   IPDF_Page* pPage = IPDFPageFromFPDFPage(page);
745   const FX_RECT rect(start_x, start_y, start_x + size_x, start_y + size_y);
746   CFX_PointF page_point(static_cast<float>(page_x), static_cast<float>(page_y));
747   Optional<CFX_PointF> pos = pPage->PageToDevice(rect, rotate, page_point);
748   if (!pos)
749     return false;
750 
751   *device_x = FXSYS_roundf(pos->x);
752   *device_y = FXSYS_roundf(pos->y);
753   return true;
754 }
755 
FPDFBitmap_Create(int width,int height,int alpha)756 FPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV FPDFBitmap_Create(int width,
757                                                         int height,
758                                                         int alpha) {
759   auto pBitmap = pdfium::MakeRetain<CFX_DIBitmap>();
760   if (!pBitmap->Create(width, height, alpha ? FXDIB_Argb : FXDIB_Rgb32))
761     return nullptr;
762 
763   return FPDFBitmapFromCFXDIBitmap(pBitmap.Leak());
764 }
765 
FPDFBitmap_CreateEx(int width,int height,int format,void * first_scan,int stride)766 FPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV FPDFBitmap_CreateEx(int width,
767                                                           int height,
768                                                           int format,
769                                                           void* first_scan,
770                                                           int stride) {
771   FXDIB_Format fx_format;
772   switch (format) {
773     case FPDFBitmap_Gray:
774       fx_format = FXDIB_8bppRgb;
775       break;
776     case FPDFBitmap_BGR:
777       fx_format = FXDIB_Rgb;
778       break;
779     case FPDFBitmap_BGRx:
780       fx_format = FXDIB_Rgb32;
781       break;
782     case FPDFBitmap_BGRA:
783       fx_format = FXDIB_Argb;
784       break;
785     default:
786       return nullptr;
787   }
788 
789   // Ensure external memory is good at least for the duration of this call.
790   UnownedPtr<uint8_t> pChecker(static_cast<uint8_t*>(first_scan));
791   auto pBitmap = pdfium::MakeRetain<CFX_DIBitmap>();
792   if (!pBitmap->Create(width, height, fx_format, pChecker.Get(), stride))
793     return nullptr;
794 
795   return FPDFBitmapFromCFXDIBitmap(pBitmap.Leak());
796 }
797 
FPDFBitmap_GetFormat(FPDF_BITMAP bitmap)798 FPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetFormat(FPDF_BITMAP bitmap) {
799   if (!bitmap)
800     return FPDFBitmap_Unknown;
801 
802   FXDIB_Format format = CFXDIBitmapFromFPDFBitmap(bitmap)->GetFormat();
803   switch (format) {
804     case FXDIB_8bppRgb:
805     case FXDIB_8bppMask:
806       return FPDFBitmap_Gray;
807     case FXDIB_Rgb:
808       return FPDFBitmap_BGR;
809     case FXDIB_Rgb32:
810       return FPDFBitmap_BGRx;
811     case FXDIB_Argb:
812       return FPDFBitmap_BGRA;
813     default:
814       return FPDFBitmap_Unknown;
815   }
816 }
817 
FPDFBitmap_FillRect(FPDF_BITMAP bitmap,int left,int top,int width,int height,FPDF_DWORD color)818 FPDF_EXPORT void FPDF_CALLCONV FPDFBitmap_FillRect(FPDF_BITMAP bitmap,
819                                                    int left,
820                                                    int top,
821                                                    int width,
822                                                    int height,
823                                                    FPDF_DWORD color) {
824   if (!bitmap)
825     return;
826 
827   CFX_DefaultRenderDevice device;
828   RetainPtr<CFX_DIBitmap> pBitmap(CFXDIBitmapFromFPDFBitmap(bitmap));
829   device.Attach(pBitmap, false, nullptr, false);
830   if (!pBitmap->HasAlpha())
831     color |= 0xFF000000;
832   device.FillRect(FX_RECT(left, top, left + width, top + height), color);
833 }
834 
FPDFBitmap_GetBuffer(FPDF_BITMAP bitmap)835 FPDF_EXPORT void* FPDF_CALLCONV FPDFBitmap_GetBuffer(FPDF_BITMAP bitmap) {
836   return bitmap ? CFXDIBitmapFromFPDFBitmap(bitmap)->GetBuffer() : nullptr;
837 }
838 
FPDFBitmap_GetWidth(FPDF_BITMAP bitmap)839 FPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetWidth(FPDF_BITMAP bitmap) {
840   return bitmap ? CFXDIBitmapFromFPDFBitmap(bitmap)->GetWidth() : 0;
841 }
842 
FPDFBitmap_GetHeight(FPDF_BITMAP bitmap)843 FPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetHeight(FPDF_BITMAP bitmap) {
844   return bitmap ? CFXDIBitmapFromFPDFBitmap(bitmap)->GetHeight() : 0;
845 }
846 
FPDFBitmap_GetStride(FPDF_BITMAP bitmap)847 FPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetStride(FPDF_BITMAP bitmap) {
848   return bitmap ? CFXDIBitmapFromFPDFBitmap(bitmap)->GetPitch() : 0;
849 }
850 
FPDFBitmap_Destroy(FPDF_BITMAP bitmap)851 FPDF_EXPORT void FPDF_CALLCONV FPDFBitmap_Destroy(FPDF_BITMAP bitmap) {
852   RetainPtr<CFX_DIBitmap> destroyer;
853   destroyer.Unleak(CFXDIBitmapFromFPDFBitmap(bitmap));
854 }
855 
856 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDF_GetPageSizeByIndexF(FPDF_DOCUMENT document,int page_index,FS_SIZEF * size)857 FPDF_GetPageSizeByIndexF(FPDF_DOCUMENT document,
858                          int page_index,
859                          FS_SIZEF* size) {
860   if (!size)
861     return false;
862 
863   auto* pDoc = CPDFDocumentFromFPDFDocument(document);
864   if (!pDoc)
865     return false;
866 
867 #ifdef PDF_ENABLE_XFA
868   if (page_index < 0 || page_index >= FPDF_GetPageCount(document))
869     return false;
870 
871   auto* pContext = static_cast<CPDFXFA_Context*>(pDoc->GetExtension());
872   if (pContext) {
873     RetainPtr<CPDFXFA_Page> pPage = pContext->GetXFAPage(page_index);
874     if (!pPage)
875       return false;
876 
877     size->width = pPage->GetPageWidth();
878     size->height = pPage->GetPageHeight();
879     return true;
880   }
881 #endif  // PDF_ENABLE_XFA
882 
883   CPDF_Dictionary* pDict = pDoc->GetPageDictionary(page_index);
884   if (!pDict)
885     return false;
886 
887   auto page = pdfium::MakeRetain<CPDF_Page>(pDoc, pDict);
888   page->SetRenderCache(pdfium::MakeUnique<CPDF_PageRenderCache>(page.Get()));
889   size->width = page->GetPageWidth();
890   size->height = page->GetPageHeight();
891   return true;
892 }
893 
FPDF_GetPageSizeByIndex(FPDF_DOCUMENT document,int page_index,double * width,double * height)894 FPDF_EXPORT int FPDF_CALLCONV FPDF_GetPageSizeByIndex(FPDF_DOCUMENT document,
895                                                       int page_index,
896                                                       double* width,
897                                                       double* height) {
898   if (!width || !height)
899     return false;
900 
901   FS_SIZEF size;
902   if (!FPDF_GetPageSizeByIndexF(document, page_index, &size))
903     return false;
904 
905   *width = size.width;
906   *height = size.height;
907   return true;
908 }
909 
910 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDF_VIEWERREF_GetPrintScaling(FPDF_DOCUMENT document)911 FPDF_VIEWERREF_GetPrintScaling(FPDF_DOCUMENT document) {
912   const CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
913   if (!pDoc)
914     return true;
915   CPDF_ViewerPreferences viewRef(pDoc);
916   return viewRef.PrintScaling();
917 }
918 
919 FPDF_EXPORT int FPDF_CALLCONV
FPDF_VIEWERREF_GetNumCopies(FPDF_DOCUMENT document)920 FPDF_VIEWERREF_GetNumCopies(FPDF_DOCUMENT document) {
921   const CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
922   if (!pDoc)
923     return 1;
924   CPDF_ViewerPreferences viewRef(pDoc);
925   return viewRef.NumCopies();
926 }
927 
928 FPDF_EXPORT FPDF_PAGERANGE FPDF_CALLCONV
FPDF_VIEWERREF_GetPrintPageRange(FPDF_DOCUMENT document)929 FPDF_VIEWERREF_GetPrintPageRange(FPDF_DOCUMENT document) {
930   const CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
931   if (!pDoc)
932     return nullptr;
933   CPDF_ViewerPreferences viewRef(pDoc);
934   return FPDFPageRangeFromCPDFArray(viewRef.PrintPageRange());
935 }
936 
937 FPDF_EXPORT size_t FPDF_CALLCONV
FPDF_VIEWERREF_GetPrintPageRangeCount(FPDF_PAGERANGE pagerange)938 FPDF_VIEWERREF_GetPrintPageRangeCount(FPDF_PAGERANGE pagerange) {
939   const CPDF_Array* pArray = CPDFArrayFromFPDFPageRange(pagerange);
940   return pArray ? pArray->size() : 0;
941 }
942 
943 FPDF_EXPORT int FPDF_CALLCONV
FPDF_VIEWERREF_GetPrintPageRangeElement(FPDF_PAGERANGE pagerange,size_t index)944 FPDF_VIEWERREF_GetPrintPageRangeElement(FPDF_PAGERANGE pagerange,
945                                         size_t index) {
946   const CPDF_Array* pArray = CPDFArrayFromFPDFPageRange(pagerange);
947   if (!pArray || index >= pArray->size())
948     return -1;
949   return pArray->GetIntegerAt(index);
950 }
951 
952 FPDF_EXPORT FPDF_DUPLEXTYPE FPDF_CALLCONV
FPDF_VIEWERREF_GetDuplex(FPDF_DOCUMENT document)953 FPDF_VIEWERREF_GetDuplex(FPDF_DOCUMENT document) {
954   const CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
955   if (!pDoc)
956     return DuplexUndefined;
957   CPDF_ViewerPreferences viewRef(pDoc);
958   ByteString duplex = viewRef.Duplex();
959   if ("Simplex" == duplex)
960     return Simplex;
961   if ("DuplexFlipShortEdge" == duplex)
962     return DuplexFlipShortEdge;
963   if ("DuplexFlipLongEdge" == duplex)
964     return DuplexFlipLongEdge;
965   return DuplexUndefined;
966 }
967 
968 FPDF_EXPORT unsigned long FPDF_CALLCONV
FPDF_VIEWERREF_GetName(FPDF_DOCUMENT document,FPDF_BYTESTRING key,char * buffer,unsigned long length)969 FPDF_VIEWERREF_GetName(FPDF_DOCUMENT document,
970                        FPDF_BYTESTRING key,
971                        char* buffer,
972                        unsigned long length) {
973   const CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
974   if (!pDoc)
975     return 0;
976 
977   CPDF_ViewerPreferences viewRef(pDoc);
978   Optional<ByteString> bsVal = viewRef.GenericName(key);
979   if (!bsVal)
980     return 0;
981 
982   unsigned long dwStringLen = bsVal->GetLength() + 1;
983   if (buffer && length >= dwStringLen)
984     memcpy(buffer, bsVal->c_str(), dwStringLen);
985   return dwStringLen;
986 }
987 
988 FPDF_EXPORT FPDF_DWORD FPDF_CALLCONV
FPDF_CountNamedDests(FPDF_DOCUMENT document)989 FPDF_CountNamedDests(FPDF_DOCUMENT document) {
990   CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
991   if (!pDoc)
992     return 0;
993 
994   const CPDF_Dictionary* pRoot = pDoc->GetRoot();
995   if (!pRoot)
996     return 0;
997 
998   CPDF_NameTree nameTree(pDoc, "Dests");
999   pdfium::base::CheckedNumeric<FPDF_DWORD> count = nameTree.GetCount();
1000   const CPDF_Dictionary* pDest = pRoot->GetDictFor("Dests");
1001   if (pDest)
1002     count += pDest->size();
1003 
1004   if (!count.IsValid())
1005     return 0;
1006 
1007   return count.ValueOrDie();
1008 }
1009 
1010 FPDF_EXPORT FPDF_DEST FPDF_CALLCONV
FPDF_GetNamedDestByName(FPDF_DOCUMENT document,FPDF_BYTESTRING name)1011 FPDF_GetNamedDestByName(FPDF_DOCUMENT document, FPDF_BYTESTRING name) {
1012   if (!name || name[0] == 0)
1013     return nullptr;
1014 
1015   CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
1016   if (!pDoc)
1017     return nullptr;
1018 
1019   CPDF_NameTree name_tree(pDoc, "Dests");
1020   ByteStringView name_view(name);
1021   return FPDFDestFromCPDFArray(
1022       name_tree.LookupNamedDest(pDoc, PDF_DecodeText(name_view.raw_span())));
1023 }
1024 
1025 #ifdef PDF_ENABLE_V8
FPDF_GetRecommendedV8Flags()1026 FPDF_EXPORT const char* FPDF_CALLCONV FPDF_GetRecommendedV8Flags() {
1027   // Reduce exposure since no PDF should contain web assembly.
1028   // Use interpreted JS only to avoid RWX pages in our address space.
1029   return "--no-expose-wasm --jitless";
1030 }
1031 #endif  // PDF_ENABLE_V8
1032 
1033 #ifdef PDF_ENABLE_XFA
FPDF_BStr_Init(FPDF_BSTR * bstr)1034 FPDF_EXPORT FPDF_RESULT FPDF_CALLCONV FPDF_BStr_Init(FPDF_BSTR* bstr) {
1035   if (!bstr)
1036     return -1;
1037 
1038   bstr->str = nullptr;
1039   bstr->len = 0;
1040   return 0;
1041 }
1042 
FPDF_BStr_Set(FPDF_BSTR * bstr,const char * cstr,int length)1043 FPDF_EXPORT FPDF_RESULT FPDF_CALLCONV FPDF_BStr_Set(FPDF_BSTR* bstr,
1044                                                     const char* cstr,
1045                                                     int length) {
1046   if (!bstr || !cstr)
1047     return -1;
1048 
1049   if (length == -1)
1050     length = strlen(cstr);
1051 
1052   if (length == 0) {
1053     FPDF_BStr_Clear(bstr);
1054     return 0;
1055   }
1056 
1057   if (bstr->str && bstr->len < length)
1058     bstr->str = FX_Realloc(char, bstr->str, length + 1);
1059   else if (!bstr->str)
1060     bstr->str = FX_Alloc(char, length + 1);
1061 
1062   bstr->str[length] = 0;
1063   memcpy(bstr->str, cstr, length);
1064   bstr->len = length;
1065   return 0;
1066 }
1067 
FPDF_BStr_Clear(FPDF_BSTR * bstr)1068 FPDF_EXPORT FPDF_RESULT FPDF_CALLCONV FPDF_BStr_Clear(FPDF_BSTR* bstr) {
1069   if (!bstr)
1070     return -1;
1071 
1072   if (bstr->str) {
1073     FX_Free(bstr->str);
1074     bstr->str = nullptr;
1075   }
1076   bstr->len = 0;
1077   return 0;
1078 }
1079 #endif  // PDF_ENABLE_XFA
1080 
FPDF_GetNamedDest(FPDF_DOCUMENT document,int index,void * buffer,long * buflen)1081 FPDF_EXPORT FPDF_DEST FPDF_CALLCONV FPDF_GetNamedDest(FPDF_DOCUMENT document,
1082                                                       int index,
1083                                                       void* buffer,
1084                                                       long* buflen) {
1085   if (!buffer)
1086     *buflen = 0;
1087 
1088   if (index < 0)
1089     return nullptr;
1090 
1091   CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
1092   if (!pDoc)
1093     return nullptr;
1094 
1095   const CPDF_Dictionary* pRoot = pDoc->GetRoot();
1096   if (!pRoot)
1097     return nullptr;
1098 
1099   CPDF_Object* pDestObj = nullptr;
1100   WideString wsName;
1101   CPDF_NameTree nameTree(pDoc, "Dests");
1102   int count = nameTree.GetCount();
1103   if (index >= count) {
1104     const CPDF_Dictionary* pDest = pRoot->GetDictFor("Dests");
1105     if (!pDest)
1106       return nullptr;
1107 
1108     pdfium::base::CheckedNumeric<int> checked_count = count;
1109     checked_count += pDest->size();
1110     if (!checked_count.IsValid() || index >= checked_count.ValueOrDie())
1111       return nullptr;
1112 
1113     index -= count;
1114     int i = 0;
1115     ByteStringView bsName;
1116     CPDF_DictionaryLocker locker(pDest);
1117     for (const auto& it : locker) {
1118       bsName = it.first.AsStringView();
1119       pDestObj = it.second.Get();
1120       if (!pDestObj)
1121         continue;
1122       if (i == index)
1123         break;
1124       i++;
1125     }
1126     wsName = PDF_DecodeText(bsName.raw_span());
1127   } else {
1128     pDestObj = nameTree.LookupValueAndName(index, &wsName);
1129   }
1130   if (!pDestObj)
1131     return nullptr;
1132   if (CPDF_Dictionary* pDict = pDestObj->AsDictionary()) {
1133     pDestObj = pDict->GetArrayFor("D");
1134     if (!pDestObj)
1135       return nullptr;
1136   }
1137   if (!pDestObj->IsArray())
1138     return nullptr;
1139 
1140   ByteString utf16Name = wsName.ToUTF16LE();
1141   int len = utf16Name.GetLength();
1142   if (!buffer) {
1143     *buflen = len;
1144   } else if (len <= *buflen) {
1145     memcpy(buffer, utf16Name.c_str(), len);
1146     *buflen = len;
1147   } else {
1148     *buflen = -1;
1149   }
1150   return FPDFDestFromCPDFArray(pDestObj->AsArray());
1151 }
1152