• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 The PDFium Authors
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_pageimagecache.h"
18 #include "core/fpdfapi/page/cpdf_pagemodule.h"
19 #include "core/fpdfapi/parser/cpdf_array.h"
20 #include "core/fpdfapi/parser/cpdf_dictionary.h"
21 #include "core/fpdfapi/parser/cpdf_document.h"
22 #include "core/fpdfapi/parser/cpdf_name.h"
23 #include "core/fpdfapi/parser/cpdf_parser.h"
24 #include "core/fpdfapi/parser/cpdf_stream.h"
25 #include "core/fpdfapi/parser/cpdf_string.h"
26 #include "core/fpdfapi/parser/fpdf_parser_decode.h"
27 #include "core/fpdfapi/render/cpdf_docrenderdata.h"
28 #include "core/fpdfapi/render/cpdf_pagerendercontext.h"
29 #include "core/fpdfapi/render/cpdf_rendercontext.h"
30 #include "core/fpdfapi/render/cpdf_renderoptions.h"
31 #include "core/fpdfdoc/cpdf_nametree.h"
32 #include "core/fpdfdoc/cpdf_viewerpreferences.h"
33 #include "core/fxcrt/cfx_read_only_span_stream.h"
34 #include "core/fxcrt/fx_safe_types.h"
35 #include "core/fxcrt/fx_stream.h"
36 #include "core/fxcrt/fx_system.h"
37 #include "core/fxcrt/span_util.h"
38 #include "core/fxcrt/stl_util.h"
39 #include "core/fxcrt/unowned_ptr.h"
40 #include "core/fxge/cfx_defaultrenderdevice.h"
41 #include "core/fxge/cfx_gemodule.h"
42 #include "core/fxge/cfx_renderdevice.h"
43 #include "fpdfsdk/cpdfsdk_customaccess.h"
44 #include "fpdfsdk/cpdfsdk_formfillenvironment.h"
45 #include "fpdfsdk/cpdfsdk_helpers.h"
46 #include "fpdfsdk/cpdfsdk_pageview.h"
47 #include "fpdfsdk/cpdfsdk_renderpage.h"
48 #include "fxjs/ijs_runtime.h"
49 #include "public/fpdf_formfill.h"
50 #include "third_party/base/check_op.h"
51 #include "third_party/base/numerics/safe_conversions.h"
52 #include "third_party/base/ptr_util.h"
53 #include "third_party/base/span.h"
54 
55 #if defined(_SKIA_SUPPORT_)
56 #include "third_party/skia/include/core/SkPictureRecorder.h"  // nogncheck
57 #include "third_party/skia/include/core/SkRect.h"             // nogncheck
58 #endif  // defined(_SKIA_SUPPORT_)
59 
60 #ifdef PDF_ENABLE_V8
61 #include "fxjs/cfx_v8_array_buffer_allocator.h"
62 #include "third_party/base/no_destructor.h"
63 #endif
64 
65 #ifdef PDF_ENABLE_XFA
66 #include "fpdfsdk/fpdfxfa/cpdfxfa_context.h"
67 #include "fpdfsdk/fpdfxfa/cpdfxfa_page.h"
68 #endif  // PDF_ENABLE_XFA
69 
70 #if BUILDFLAG(IS_WIN)
71 #include "core/fpdfapi/render/cpdf_progressiverenderer.h"
72 #include "core/fpdfapi/render/cpdf_windowsrenderdevice.h"
73 #include "public/fpdf_edit.h"
74 
75 // These checks are here because core/ and public/ cannot depend on each other.
76 static_assert(static_cast<int>(WindowsPrintMode::kEmf) == FPDF_PRINTMODE_EMF,
77               "WindowsPrintMode::kEmf value mismatch");
78 static_assert(static_cast<int>(WindowsPrintMode::kTextOnly) ==
79                   FPDF_PRINTMODE_TEXTONLY,
80               "WindowsPrintMode::kTextOnly value mismatch");
81 static_assert(static_cast<int>(WindowsPrintMode::kPostScript2) ==
82                   FPDF_PRINTMODE_POSTSCRIPT2,
83               "WindowsPrintMode::kPostScript2 value mismatch");
84 static_assert(static_cast<int>(WindowsPrintMode::kPostScript3) ==
85                   FPDF_PRINTMODE_POSTSCRIPT3,
86               "WindowsPrintMode::kPostScript3 value mismatch");
87 static_assert(static_cast<int>(WindowsPrintMode::kPostScript2PassThrough) ==
88                   FPDF_PRINTMODE_POSTSCRIPT2_PASSTHROUGH,
89               "WindowsPrintMode::kPostScript2PassThrough value mismatch");
90 static_assert(static_cast<int>(WindowsPrintMode::kPostScript3PassThrough) ==
91                   FPDF_PRINTMODE_POSTSCRIPT3_PASSTHROUGH,
92               "WindowsPrintMode::kPostScript3PassThrough value mismatch");
93 static_assert(static_cast<int>(WindowsPrintMode::kEmfImageMasks) ==
94                   FPDF_PRINTMODE_EMF_IMAGE_MASKS,
95               "WindowsPrintMode::kEmfImageMasks value mismatch");
96 static_assert(static_cast<int>(WindowsPrintMode::kPostScript3Type42) ==
97                   FPDF_PRINTMODE_POSTSCRIPT3_TYPE42,
98               "WindowsPrintMode::kPostScript3Type42 value mismatch");
99 static_assert(
100     static_cast<int>(WindowsPrintMode::kPostScript3Type42PassThrough) ==
101         FPDF_PRINTMODE_POSTSCRIPT3_TYPE42_PASSTHROUGH,
102     "WindowsPrintMode::kPostScript3Type42PassThrough value mismatch");
103 #endif  // BUILDFLAG(IS_WIN)
104 
105 #if defined(_SKIA_SUPPORT_)
106 // These checks are here because core/ and public/ cannot depend on each other.
107 static_assert(static_cast<int>(CFX_DefaultRenderDevice::RendererType::kAgg) ==
108                   FPDF_RENDERERTYPE_AGG,
109               "CFX_DefaultRenderDevice::RendererType::kAGG value mismatch");
110 static_assert(static_cast<int>(CFX_DefaultRenderDevice::RendererType::kSkia) ==
111                   FPDF_RENDERERTYPE_SKIA,
112               "CFX_DefaultRenderDevice::RendererType::kSkia value mismatch");
113 #endif  // defined(_SKIA_SUPPORT_)
114 
115 namespace {
116 
117 bool g_bLibraryInitialized = false;
118 
UseRendererType(FPDF_RENDERER_TYPE public_type)119 void UseRendererType(FPDF_RENDERER_TYPE public_type) {
120   // Internal definition of renderer types must stay updated with respect to
121   // the public definition, such that all public definitions can be mapped to
122   // an internal definition in `CFX_DefaultRenderDevice`. A public definition
123   // value might not be meaningful for a particular build configuration, which
124   // would mean use of that value is an error for that build.
125 
126   // AGG is always present in a build. |FPDF_RENDERERTYPE_SKIA| is valid to use
127   // only if it is included in the build.
128 #if defined(_SKIA_SUPPORT_)
129   // This build configuration has the option for runtime renderer selection.
130   if (public_type == FPDF_RENDERERTYPE_AGG ||
131       public_type == FPDF_RENDERERTYPE_SKIA) {
132     CFX_DefaultRenderDevice::SetDefaultRenderer(
133         static_cast<CFX_DefaultRenderDevice::RendererType>(public_type));
134     return;
135   }
136   CHECK(false);
137 #else
138   // `FPDF_RENDERERTYPE_AGG` is used for fully AGG builds.
139   CHECK_EQ(public_type, FPDF_RENDERERTYPE_AGG);
140 #endif
141 }
142 
GetXFAEntryFromDocument(const CPDF_Document * doc)143 RetainPtr<const CPDF_Object> GetXFAEntryFromDocument(const CPDF_Document* doc) {
144   const CPDF_Dictionary* root = doc->GetRoot();
145   if (!root)
146     return nullptr;
147 
148   RetainPtr<const CPDF_Dictionary> acro_form = root->GetDictFor("AcroForm");
149   return acro_form ? acro_form->GetObjectFor("XFA") : nullptr;
150 }
151 
152 struct XFAPacket {
153   ByteString name;
154   RetainPtr<const CPDF_Stream> data;
155 };
156 
GetXFAPackets(RetainPtr<const CPDF_Object> xfa_object)157 std::vector<XFAPacket> GetXFAPackets(RetainPtr<const CPDF_Object> xfa_object) {
158   std::vector<XFAPacket> packets;
159 
160   if (!xfa_object)
161     return packets;
162 
163   RetainPtr<const CPDF_Stream> xfa_stream = ToStream(xfa_object->GetDirect());
164   if (xfa_stream) {
165     packets.push_back({"", std::move(xfa_stream)});
166     return packets;
167   }
168 
169   RetainPtr<const CPDF_Array> xfa_array = ToArray(xfa_object->GetDirect());
170   if (!xfa_array)
171     return packets;
172 
173   packets.reserve(1 + (xfa_array->size() / 2));
174   for (size_t i = 0; i < xfa_array->size(); i += 2) {
175     if (i + 1 == xfa_array->size())
176       break;
177 
178     RetainPtr<const CPDF_String> name = xfa_array->GetStringAt(i);
179     if (!name)
180       continue;
181 
182     RetainPtr<const CPDF_Stream> data = xfa_array->GetStreamAt(i + 1);
183     if (!data)
184       continue;
185 
186     packets.push_back({name->GetString(), std::move(data)});
187   }
188   return packets;
189 }
190 
LoadDocumentImpl(RetainPtr<IFX_SeekableReadStream> pFileAccess,FPDF_BYTESTRING password)191 FPDF_DOCUMENT LoadDocumentImpl(RetainPtr<IFX_SeekableReadStream> pFileAccess,
192                                FPDF_BYTESTRING password) {
193   if (!pFileAccess) {
194     ProcessParseError(CPDF_Parser::FILE_ERROR);
195     return nullptr;
196   }
197 
198   auto pDocument =
199       std::make_unique<CPDF_Document>(std::make_unique<CPDF_DocRenderData>(),
200                                       std::make_unique<CPDF_DocPageData>());
201 
202   CPDF_Parser::Error error =
203       pDocument->LoadDoc(std::move(pFileAccess), password);
204   if (error != CPDF_Parser::SUCCESS) {
205     ProcessParseError(error);
206     return nullptr;
207   }
208 
209   ReportUnsupportedFeatures(pDocument.get());
210   return FPDFDocumentFromCPDFDocument(pDocument.release());
211 }
212 
213 }  // namespace
214 
FPDF_InitLibrary()215 FPDF_EXPORT void FPDF_CALLCONV FPDF_InitLibrary() {
216   FPDF_InitLibraryWithConfig(nullptr);
217 }
218 
219 FPDF_EXPORT void FPDF_CALLCONV
FPDF_InitLibraryWithConfig(const FPDF_LIBRARY_CONFIG * config)220 FPDF_InitLibraryWithConfig(const FPDF_LIBRARY_CONFIG* config) {
221   if (g_bLibraryInitialized)
222     return;
223 
224   FX_InitializeMemoryAllocators();
225   CFX_GEModule::Create(config ? config->m_pUserFontPaths : nullptr);
226   CPDF_PageModule::Create();
227 
228 #ifdef PDF_ENABLE_XFA
229   CPDFXFA_ModuleInit();
230 #endif  // PDF_ENABLE_XFA
231 
232   if (config && config->version >= 2) {
233     void* platform = config->version >= 3 ? config->m_pPlatform : nullptr;
234     IJS_Runtime::Initialize(config->m_v8EmbedderSlot, config->m_pIsolate,
235                             platform);
236 
237     if (config->version >= 4)
238       UseRendererType(config->m_RendererType);
239   }
240   g_bLibraryInitialized = true;
241 }
242 
FPDF_DestroyLibrary()243 FPDF_EXPORT void FPDF_CALLCONV FPDF_DestroyLibrary() {
244   if (!g_bLibraryInitialized)
245     return;
246 
247 #ifdef PDF_ENABLE_XFA
248   CPDFXFA_ModuleDestroy();
249 #endif  // PDF_ENABLE_XFA
250 
251   CPDF_PageModule::Destroy();
252   CFX_GEModule::Destroy();
253   IJS_Runtime::Destroy();
254 
255   g_bLibraryInitialized = false;
256 }
257 
FPDF_SetSandBoxPolicy(FPDF_DWORD policy,FPDF_BOOL enable)258 FPDF_EXPORT void FPDF_CALLCONV FPDF_SetSandBoxPolicy(FPDF_DWORD policy,
259                                                      FPDF_BOOL enable) {
260   return SetPDFSandboxPolicy(policy, enable);
261 }
262 
263 #if BUILDFLAG(IS_WIN)
FPDF_SetPrintMode(int mode)264 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_SetPrintMode(int mode) {
265   if (mode < FPDF_PRINTMODE_EMF ||
266       mode > FPDF_PRINTMODE_POSTSCRIPT3_TYPE42_PASSTHROUGH) {
267     return FALSE;
268   }
269 
270   g_pdfium_print_mode = static_cast<WindowsPrintMode>(mode);
271   return TRUE;
272 }
273 #endif  // BUILDFLAG(IS_WIN)
274 
275 FPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV
FPDF_LoadDocument(FPDF_STRING file_path,FPDF_BYTESTRING password)276 FPDF_LoadDocument(FPDF_STRING file_path, FPDF_BYTESTRING password) {
277   // NOTE: the creation of the file needs to be by the embedder on the
278   // other side of this API.
279   return LoadDocumentImpl(IFX_SeekableReadStream::CreateFromFilename(file_path),
280                           password);
281 }
282 
FPDF_GetFormType(FPDF_DOCUMENT document)283 FPDF_EXPORT int FPDF_CALLCONV FPDF_GetFormType(FPDF_DOCUMENT document) {
284   const CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
285   if (!pDoc)
286     return FORMTYPE_NONE;
287 
288   const CPDF_Dictionary* pRoot = pDoc->GetRoot();
289   if (!pRoot)
290     return FORMTYPE_NONE;
291 
292   RetainPtr<const CPDF_Dictionary> pAcroForm = pRoot->GetDictFor("AcroForm");
293   if (!pAcroForm)
294     return FORMTYPE_NONE;
295 
296   RetainPtr<const CPDF_Object> pXFA = pAcroForm->GetObjectFor("XFA");
297   if (!pXFA)
298     return FORMTYPE_ACRO_FORM;
299 
300   bool bNeedsRendering = pRoot->GetBooleanFor("NeedsRendering", false);
301   return bNeedsRendering ? FORMTYPE_XFA_FULL : FORMTYPE_XFA_FOREGROUND;
302 }
303 
FPDF_LoadXFA(FPDF_DOCUMENT document)304 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_LoadXFA(FPDF_DOCUMENT document) {
305 #ifdef PDF_ENABLE_XFA
306   auto* pDoc = CPDFDocumentFromFPDFDocument(document);
307   if (!pDoc)
308     return false;
309 
310   auto* pContext = static_cast<CPDFXFA_Context*>(pDoc->GetExtension());
311   if (pContext)
312     return pContext->LoadXFADoc();
313 #endif  // PDF_ENABLE_XFA
314   return false;
315 }
316 
317 FPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV
FPDF_LoadMemDocument(const void * data_buf,int size,FPDF_BYTESTRING password)318 FPDF_LoadMemDocument(const void* data_buf, int size, FPDF_BYTESTRING password) {
319   return LoadDocumentImpl(
320       pdfium::MakeRetain<CFX_ReadOnlySpanStream>(
321           pdfium::make_span(static_cast<const uint8_t*>(data_buf), size)),
322       password);
323 }
324 
325 FPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV
FPDF_LoadMemDocument64(const void * data_buf,size_t size,FPDF_BYTESTRING password)326 FPDF_LoadMemDocument64(const void* data_buf,
327                        size_t size,
328                        FPDF_BYTESTRING password) {
329   return LoadDocumentImpl(
330       pdfium::MakeRetain<CFX_ReadOnlySpanStream>(
331           pdfium::make_span(static_cast<const uint8_t*>(data_buf), size)),
332       password);
333 }
334 
335 FPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV
FPDF_LoadCustomDocument(FPDF_FILEACCESS * pFileAccess,FPDF_BYTESTRING password)336 FPDF_LoadCustomDocument(FPDF_FILEACCESS* pFileAccess,
337                         FPDF_BYTESTRING password) {
338   if (!pFileAccess)
339     return nullptr;
340   return LoadDocumentImpl(pdfium::MakeRetain<CPDFSDK_CustomAccess>(pFileAccess),
341                           password);
342 }
343 
FPDF_GetFileVersion(FPDF_DOCUMENT doc,int * fileVersion)344 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_GetFileVersion(FPDF_DOCUMENT doc,
345                                                         int* fileVersion) {
346   if (!fileVersion)
347     return false;
348 
349   *fileVersion = 0;
350   CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(doc);
351   if (!pDoc)
352     return false;
353 
354   const CPDF_Parser* pParser = pDoc->GetParser();
355   if (!pParser)
356     return false;
357 
358   *fileVersion = pParser->GetFileVersion();
359   return true;
360 }
361 
362 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDF_DocumentHasValidCrossReferenceTable(FPDF_DOCUMENT document)363 FPDF_DocumentHasValidCrossReferenceTable(FPDF_DOCUMENT document) {
364   CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
365   return pDoc && pDoc->has_valid_cross_reference_table();
366 }
367 
368 FPDF_EXPORT unsigned long FPDF_CALLCONV
FPDF_GetDocPermissions(FPDF_DOCUMENT document)369 FPDF_GetDocPermissions(FPDF_DOCUMENT document) {
370   CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
371   return pDoc ? pDoc->GetUserPermissions() : 0;
372 }
373 
374 FPDF_EXPORT int FPDF_CALLCONV
FPDF_GetSecurityHandlerRevision(FPDF_DOCUMENT document)375 FPDF_GetSecurityHandlerRevision(FPDF_DOCUMENT document) {
376   CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
377   if (!pDoc || !pDoc->GetParser())
378     return -1;
379 
380   RetainPtr<const CPDF_Dictionary> pDict = pDoc->GetParser()->GetEncryptDict();
381   return pDict ? pDict->GetIntegerFor("R") : -1;
382 }
383 
FPDF_GetPageCount(FPDF_DOCUMENT document)384 FPDF_EXPORT int FPDF_CALLCONV FPDF_GetPageCount(FPDF_DOCUMENT document) {
385   auto* pDoc = CPDFDocumentFromFPDFDocument(document);
386   if (!pDoc)
387     return 0;
388 
389   auto* pExtension = pDoc->GetExtension();
390   return pExtension ? pExtension->GetPageCount() : pDoc->GetPageCount();
391 }
392 
FPDF_LoadPage(FPDF_DOCUMENT document,int page_index)393 FPDF_EXPORT FPDF_PAGE FPDF_CALLCONV FPDF_LoadPage(FPDF_DOCUMENT document,
394                                                   int page_index) {
395   auto* pDoc = CPDFDocumentFromFPDFDocument(document);
396   if (!pDoc)
397     return nullptr;
398 
399   if (page_index < 0 || page_index >= FPDF_GetPageCount(document))
400     return nullptr;
401 
402 #ifdef PDF_ENABLE_XFA
403   auto* pContext = static_cast<CPDFXFA_Context*>(pDoc->GetExtension());
404   if (pContext) {
405     return FPDFPageFromIPDFPage(
406         pContext->GetOrCreateXFAPage(page_index).Leak());
407   }
408 #endif  // PDF_ENABLE_XFA
409 
410   RetainPtr<CPDF_Dictionary> pDict = pDoc->GetMutablePageDictionary(page_index);
411   if (!pDict)
412     return nullptr;
413 
414   auto pPage = pdfium::MakeRetain<CPDF_Page>(pDoc, std::move(pDict));
415   pPage->AddPageImageCache();
416   pPage->ParseContent();
417 
418   return FPDFPageFromIPDFPage(pPage.Leak());
419 }
420 
FPDF_GetPageWidthF(FPDF_PAGE page)421 FPDF_EXPORT float FPDF_CALLCONV FPDF_GetPageWidthF(FPDF_PAGE page) {
422   IPDF_Page* pPage = IPDFPageFromFPDFPage(page);
423   return pPage ? pPage->GetPageWidth() : 0.0f;
424 }
425 
FPDF_GetPageWidth(FPDF_PAGE page)426 FPDF_EXPORT double FPDF_CALLCONV FPDF_GetPageWidth(FPDF_PAGE page) {
427   return FPDF_GetPageWidthF(page);
428 }
429 
FPDF_GetPageHeightF(FPDF_PAGE page)430 FPDF_EXPORT float FPDF_CALLCONV FPDF_GetPageHeightF(FPDF_PAGE page) {
431   IPDF_Page* pPage = IPDFPageFromFPDFPage(page);
432   return pPage ? pPage->GetPageHeight() : 0.0f;
433 }
434 
FPDF_GetPageHeight(FPDF_PAGE page)435 FPDF_EXPORT double FPDF_CALLCONV FPDF_GetPageHeight(FPDF_PAGE page) {
436   return FPDF_GetPageHeightF(page);
437 }
438 
FPDF_GetPageBoundingBox(FPDF_PAGE page,FS_RECTF * rect)439 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_GetPageBoundingBox(FPDF_PAGE page,
440                                                             FS_RECTF* rect) {
441   if (!rect)
442     return false;
443 
444   CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
445   if (!pPage)
446     return false;
447 
448   *rect = FSRectFFromCFXFloatRect(pPage->GetBBox());
449   return true;
450 }
451 
452 #if BUILDFLAG(IS_WIN)
453 namespace {
454 
455 constexpr float kEpsilonSize = 0.01f;
456 
IsPageTooSmall(const CPDF_Page * page)457 bool IsPageTooSmall(const CPDF_Page* page) {
458   const CFX_SizeF& page_size = page->GetPageSize();
459   return page_size.width < kEpsilonSize || page_size.height < kEpsilonSize;
460 }
461 
IsScalingTooSmall(const CFX_Matrix & matrix)462 bool IsScalingTooSmall(const CFX_Matrix& matrix) {
463   float horizontal;
464   float vertical;
465   if (matrix.a == 0.0f && matrix.d == 0.0f) {
466     horizontal = matrix.b;
467     vertical = matrix.c;
468   } else {
469     horizontal = matrix.a;
470     vertical = matrix.d;
471   }
472   return fabsf(horizontal) < kEpsilonSize || fabsf(vertical) < kEpsilonSize;
473 }
474 
475 // Get a bitmap of just the mask section defined by |mask_box| from a full page
476 // 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)477 RetainPtr<CFX_DIBitmap> GetMaskBitmap(CPDF_Page* pPage,
478                                       int start_x,
479                                       int start_y,
480                                       int size_x,
481                                       int size_y,
482                                       int rotate,
483                                       const RetainPtr<CFX_DIBitmap>& pSrc,
484                                       const CFX_FloatRect& mask_box,
485                                       FX_RECT* bitmap_area) {
486   if (IsPageTooSmall(pPage))
487     return nullptr;
488 
489   FX_RECT page_rect(start_x, start_y, start_x + size_x, start_y + size_y);
490   CFX_Matrix matrix = pPage->GetDisplayMatrix(page_rect, rotate);
491   if (IsScalingTooSmall(matrix))
492     return nullptr;
493 
494   *bitmap_area = matrix.TransformRect(mask_box).GetOuterRect();
495   if (bitmap_area->IsEmpty())
496     return nullptr;
497 
498   // Create a new bitmap to transfer part of the page bitmap to.
499   RetainPtr<CFX_DIBitmap> pDst = pdfium::MakeRetain<CFX_DIBitmap>();
500   if (!pDst->Create(bitmap_area->Width(), bitmap_area->Height(),
501                     FXDIB_Format::kArgb)) {
502     return nullptr;
503   }
504   pDst->Clear(0x00ffffff);
505   pDst->TransferBitmap(0, 0, bitmap_area->Width(), bitmap_area->Height(), pSrc,
506                        bitmap_area->left, bitmap_area->top);
507   return pDst;
508 }
509 
RenderBitmap(CFX_RenderDevice * device,const RetainPtr<CFX_DIBitmap> & pSrc,const FX_RECT & mask_area)510 void RenderBitmap(CFX_RenderDevice* device,
511                   const RetainPtr<CFX_DIBitmap>& pSrc,
512                   const FX_RECT& mask_area) {
513   int size_x_bm = mask_area.Width();
514   int size_y_bm = mask_area.Height();
515   if (size_x_bm == 0 || size_y_bm == 0)
516     return;
517 
518   // Create a new bitmap from the old one
519   RetainPtr<CFX_DIBitmap> pDst = pdfium::MakeRetain<CFX_DIBitmap>();
520   if (!pDst->Create(size_x_bm, size_y_bm, FXDIB_Format::kRgb32))
521     return;
522 
523   pDst->Clear(0xffffffff);
524   pDst->CompositeBitmap(0, 0, size_x_bm, size_y_bm, pSrc, 0, 0,
525                         BlendMode::kNormal, nullptr, false);
526 
527   if (device->GetDeviceType() == DeviceType::kPrinter) {
528     device->StretchDIBits(pDst, mask_area.left, mask_area.top, size_x_bm,
529                           size_y_bm);
530   } else {
531     device->SetDIBits(pDst, mask_area.left, mask_area.top);
532   }
533 }
534 
535 }  // namespace
536 
FPDF_RenderPage(HDC dc,FPDF_PAGE page,int start_x,int start_y,int size_x,int size_y,int rotate,int flags)537 FPDF_EXPORT void FPDF_CALLCONV FPDF_RenderPage(HDC dc,
538                                                FPDF_PAGE page,
539                                                int start_x,
540                                                int start_y,
541                                                int size_x,
542                                                int size_y,
543                                                int rotate,
544                                                int flags) {
545   CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
546   if (!pPage)
547     return;
548 
549   auto pOwnedContext = std::make_unique<CPDF_PageRenderContext>();
550   CPDF_PageRenderContext* pContext = pOwnedContext.get();
551   CPDF_Page::RenderContextClearer clearer(pPage);
552   pPage->SetRenderContext(std::move(pOwnedContext));
553 
554   // Don't render the full page to bitmap for a mask unless there are a lot
555   // of masks. Full page bitmaps result in large spool sizes, so they should
556   // only be used when necessary. For large numbers of masks, rendering each
557   // individually is inefficient and unlikely to significantly improve spool
558   // size.
559   const bool bEnableImageMasks =
560       g_pdfium_print_mode == WindowsPrintMode::kEmfImageMasks;
561   const bool bNewBitmap = pPage->BackgroundAlphaNeeded() ||
562                           (pPage->HasImageMask() && !bEnableImageMasks) ||
563                           pPage->GetMaskBoundingBoxes().size() > 100;
564   const bool bHasMask = pPage->HasImageMask() && !bNewBitmap;
565   auto* render_data = CPDF_DocRenderData::FromDocument(pPage->GetDocument());
566   if (!bNewBitmap && !bHasMask) {
567     pContext->m_pDevice = std::make_unique<CPDF_WindowsRenderDevice>(
568         dc, render_data->GetPSFontTracker());
569     CPDFSDK_RenderPageWithContext(pContext, pPage, start_x, start_y, size_x,
570                                   size_y, rotate, flags,
571                                   /*color_scheme=*/nullptr,
572                                   /*need_to_restore=*/true, /*pause=*/nullptr);
573     return;
574   }
575 
576   RetainPtr<CFX_DIBitmap> pBitmap = pdfium::MakeRetain<CFX_DIBitmap>();
577   // Create will probably work fine even if it fails here: we will just attach
578   // a zero-sized bitmap to |pDevice|.
579   pBitmap->Create(size_x, size_y, FXDIB_Format::kArgb);
580   pBitmap->Clear(0x00ffffff);
581   CFX_DefaultRenderDevice* pDevice = new CFX_DefaultRenderDevice;
582   pContext->m_pDevice = pdfium::WrapUnique(pDevice);
583   pDevice->Attach(pBitmap);
584   if (bHasMask) {
585     pContext->m_pOptions = std::make_unique<CPDF_RenderOptions>();
586     pContext->m_pOptions->GetOptions().bBreakForMasks = true;
587   }
588 
589   CPDFSDK_RenderPageWithContext(pContext, pPage, start_x, start_y, size_x,
590                                 size_y, rotate, flags, /*color_scheme=*/nullptr,
591                                 /*need_to_restore=*/true,
592                                 /*pause=*/nullptr);
593 
594   if (!bHasMask) {
595     CPDF_WindowsRenderDevice win_dc(dc, render_data->GetPSFontTracker());
596     bool bitsStretched = false;
597     if (win_dc.GetDeviceType() == DeviceType::kPrinter) {
598       auto pDst = pdfium::MakeRetain<CFX_DIBitmap>();
599       if (pDst->Create(size_x, size_y, FXDIB_Format::kRgb32)) {
600         fxcrt::spanset(pDst->GetBuffer().first(pBitmap->GetPitch() * size_y),
601                        -1);
602         pDst->CompositeBitmap(0, 0, size_x, size_y, pBitmap, 0, 0,
603                               BlendMode::kNormal, nullptr, false);
604         win_dc.StretchDIBits(pDst, 0, 0, size_x, size_y);
605         bitsStretched = true;
606       }
607     }
608     if (!bitsStretched)
609       win_dc.SetDIBits(pBitmap, 0, 0);
610     return;
611   }
612 
613   // Finish rendering the page to bitmap and copy the correct segments
614   // of the page to individual image mask bitmaps.
615   const std::vector<CFX_FloatRect>& mask_boxes = pPage->GetMaskBoundingBoxes();
616   std::vector<FX_RECT> bitmap_areas(mask_boxes.size());
617   std::vector<RetainPtr<CFX_DIBitmap>> bitmaps(mask_boxes.size());
618   for (size_t i = 0; i < mask_boxes.size(); i++) {
619     bitmaps[i] = GetMaskBitmap(pPage, start_x, start_y, size_x, size_y, rotate,
620                                pBitmap, mask_boxes[i], &bitmap_areas[i]);
621     pContext->m_pRenderer->Continue(nullptr);
622   }
623 
624   // Begin rendering to the printer. Add flag to indicate the renderer should
625   // pause after each image mask.
626   pPage->ClearRenderContext();
627   pOwnedContext = std::make_unique<CPDF_PageRenderContext>();
628   pContext = pOwnedContext.get();
629   pPage->SetRenderContext(std::move(pOwnedContext));
630   pContext->m_pDevice = std::make_unique<CPDF_WindowsRenderDevice>(
631       dc, render_data->GetPSFontTracker());
632   pContext->m_pOptions = std::make_unique<CPDF_RenderOptions>();
633   pContext->m_pOptions->GetOptions().bBreakForMasks = true;
634 
635   CPDFSDK_RenderPageWithContext(pContext, pPage, start_x, start_y, size_x,
636                                 size_y, rotate, flags, /*color_scheme=*/nullptr,
637                                 /*need_to_restore=*/true,
638                                 /*pause=*/nullptr);
639 
640   // Render masks
641   for (size_t i = 0; i < mask_boxes.size(); i++) {
642     // Render the bitmap for the mask and free the bitmap.
643     if (bitmaps[i]) {  // will be null if mask has zero area
644       RenderBitmap(pContext->m_pDevice.get(), bitmaps[i], bitmap_areas[i]);
645     }
646     // Render the next portion of page.
647     pContext->m_pRenderer->Continue(nullptr);
648   }
649 }
650 #endif  // BUILDFLAG(IS_WIN)
651 
FPDF_RenderPageBitmap(FPDF_BITMAP bitmap,FPDF_PAGE page,int start_x,int start_y,int size_x,int size_y,int rotate,int flags)652 FPDF_EXPORT void FPDF_CALLCONV FPDF_RenderPageBitmap(FPDF_BITMAP bitmap,
653                                                      FPDF_PAGE page,
654                                                      int start_x,
655                                                      int start_y,
656                                                      int size_x,
657                                                      int size_y,
658                                                      int rotate,
659                                                      int flags) {
660   if (!bitmap)
661     return;
662 
663   CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
664   if (!pPage)
665     return;
666 
667   auto pOwnedContext = std::make_unique<CPDF_PageRenderContext>();
668   CPDF_PageRenderContext* pContext = pOwnedContext.get();
669   CPDF_Page::RenderContextClearer clearer(pPage);
670   pPage->SetRenderContext(std::move(pOwnedContext));
671 
672   auto pOwnedDevice = std::make_unique<CFX_DefaultRenderDevice>();
673   CFX_DefaultRenderDevice* pDevice = pOwnedDevice.get();
674   pContext->m_pDevice = std::move(pOwnedDevice);
675 
676   RetainPtr<CFX_DIBitmap> pBitmap(CFXDIBitmapFromFPDFBitmap(bitmap));
677   pDevice->AttachWithRgbByteOrder(pBitmap, !!(flags & FPDF_REVERSE_BYTE_ORDER));
678   CPDFSDK_RenderPageWithContext(pContext, pPage, start_x, start_y, size_x,
679                                 size_y, rotate, flags, /*color_scheme=*/nullptr,
680                                 /*need_to_restore=*/true,
681                                 /*pause=*/nullptr);
682 
683 #if defined(_SKIA_SUPPORT_)
684   if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer()) {
685     pBitmap->UnPreMultiply();
686   }
687 #endif
688 }
689 
690 FPDF_EXPORT void FPDF_CALLCONV
FPDF_RenderPageBitmapWithMatrix(FPDF_BITMAP bitmap,FPDF_PAGE page,const FS_MATRIX * matrix,const FS_RECTF * clipping,int flags)691 FPDF_RenderPageBitmapWithMatrix(FPDF_BITMAP bitmap,
692                                 FPDF_PAGE page,
693                                 const FS_MATRIX* matrix,
694                                 const FS_RECTF* clipping,
695                                 int flags) {
696   if (!bitmap)
697     return;
698 
699   CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
700   if (!pPage)
701     return;
702 
703   auto pOwnedContext = std::make_unique<CPDF_PageRenderContext>();
704   CPDF_PageRenderContext* pContext = pOwnedContext.get();
705   CPDF_Page::RenderContextClearer clearer(pPage);
706   pPage->SetRenderContext(std::move(pOwnedContext));
707 
708   auto pOwnedDevice = std::make_unique<CFX_DefaultRenderDevice>();
709   CFX_DefaultRenderDevice* pDevice = pOwnedDevice.get();
710   pContext->m_pDevice = std::move(pOwnedDevice);
711 
712   RetainPtr<CFX_DIBitmap> pBitmap(CFXDIBitmapFromFPDFBitmap(bitmap));
713   pDevice->AttachWithRgbByteOrder(std::move(pBitmap),
714                                   !!(flags & FPDF_REVERSE_BYTE_ORDER));
715 
716   CFX_FloatRect clipping_rect;
717   if (clipping)
718     clipping_rect = CFXFloatRectFromFSRectF(*clipping);
719   FX_RECT clip_rect = clipping_rect.ToFxRect();
720 
721   const FX_RECT rect(0, 0, pPage->GetPageWidth(), pPage->GetPageHeight());
722   CFX_Matrix transform_matrix = pPage->GetDisplayMatrix(rect, 0);
723   if (matrix)
724     transform_matrix *= CFXMatrixFromFSMatrix(*matrix);
725   CPDFSDK_RenderPage(pContext, pPage, transform_matrix, clip_rect, flags,
726                      /*color_scheme=*/nullptr);
727 }
728 
729 #if defined(_SKIA_SUPPORT_)
FPDF_RenderPageSkp(FPDF_PAGE page,int size_x,int size_y)730 FPDF_EXPORT FPDF_RECORDER FPDF_CALLCONV FPDF_RenderPageSkp(FPDF_PAGE page,
731                                                            int size_x,
732                                                            int size_y) {
733   auto skDevice = std::make_unique<CFX_DefaultRenderDevice>();
734   std::unique_ptr<SkPictureRecorder> recorder =
735       skDevice->CreateRecorder(SkRect::MakeWH(size_x, size_y));
736 
737   CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
738   if (!pPage) {
739     // The equivalent bitmap APIs don't signal failure in this case, but defer
740     // the real work to a later call to `FPDF_FFLDraw()`. This is the case for
741     // XFA pages, for example.
742     //
743     // The caller still needs the `SkPictureRecorder` in order to call
744     // `FPDF_FFLRecord()` later.
745     return recorder.release();
746   }
747 
748   auto pOwnedContext = std::make_unique<CPDF_PageRenderContext>();
749   pOwnedContext->m_pDevice = std::move(skDevice);
750 
751   CPDF_Page::RenderContextClearer clearer(pPage);
752   CPDF_PageRenderContext* pContext = pOwnedContext.get();
753   pPage->SetRenderContext(std::move(pOwnedContext));
754 
755   CPDFSDK_RenderPageWithContext(pContext, pPage, 0, 0, size_x, size_y, 0, 0,
756                                 /*color_scheme=*/nullptr,
757                                 /*need_to_restore=*/true, /*pause=*/nullptr);
758 
759   return recorder.release();
760 }
761 #endif  // defined(_SKIA_SUPPORT_)
762 
FPDF_ClosePage(FPDF_PAGE page)763 FPDF_EXPORT void FPDF_CALLCONV FPDF_ClosePage(FPDF_PAGE page) {
764   if (!page)
765     return;
766 
767   // Take it back across the API and hold for duration of this function.
768   RetainPtr<IPDF_Page> pPage;
769   pPage.Unleak(IPDFPageFromFPDFPage(page));
770 
771   if (pPage->AsXFAPage())
772     return;
773 
774   // This will delete the PageView object corresponding to |pPage|. We must
775   // cleanup the PageView before releasing the reference on |pPage| as it will
776   // attempt to reset the PageView during destruction.
777   pPage->AsPDFPage()->ClearView();
778 }
779 
FPDF_CloseDocument(FPDF_DOCUMENT document)780 FPDF_EXPORT void FPDF_CALLCONV FPDF_CloseDocument(FPDF_DOCUMENT document) {
781   // Take it back across the API and throw it away,
782   std::unique_ptr<CPDF_Document>(CPDFDocumentFromFPDFDocument(document));
783 }
784 
FPDF_GetLastError()785 FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetLastError() {
786   return FXSYS_GetLastError();
787 }
788 
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)789 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_DeviceToPage(FPDF_PAGE page,
790                                                       int start_x,
791                                                       int start_y,
792                                                       int size_x,
793                                                       int size_y,
794                                                       int rotate,
795                                                       int device_x,
796                                                       int device_y,
797                                                       double* page_x,
798                                                       double* page_y) {
799   if (!page || !page_x || !page_y)
800     return false;
801 
802   IPDF_Page* pPage = IPDFPageFromFPDFPage(page);
803   const FX_RECT rect(start_x, start_y, start_x + size_x, start_y + size_y);
804   absl::optional<CFX_PointF> pos =
805       pPage->DeviceToPage(rect, rotate, CFX_PointF(device_x, device_y));
806   if (!pos.has_value())
807     return false;
808 
809   *page_x = pos->x;
810   *page_y = pos->y;
811   return true;
812 }
813 
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)814 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_PageToDevice(FPDF_PAGE page,
815                                                       int start_x,
816                                                       int start_y,
817                                                       int size_x,
818                                                       int size_y,
819                                                       int rotate,
820                                                       double page_x,
821                                                       double page_y,
822                                                       int* device_x,
823                                                       int* device_y) {
824   if (!page || !device_x || !device_y)
825     return false;
826 
827   IPDF_Page* pPage = IPDFPageFromFPDFPage(page);
828   const FX_RECT rect(start_x, start_y, start_x + size_x, start_y + size_y);
829   CFX_PointF page_point(static_cast<float>(page_x), static_cast<float>(page_y));
830   absl::optional<CFX_PointF> pos =
831       pPage->PageToDevice(rect, rotate, page_point);
832   if (!pos.has_value())
833     return false;
834 
835   *device_x = FXSYS_roundf(pos->x);
836   *device_y = FXSYS_roundf(pos->y);
837   return true;
838 }
839 
FPDFBitmap_Create(int width,int height,int alpha)840 FPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV FPDFBitmap_Create(int width,
841                                                         int height,
842                                                         int alpha) {
843   auto pBitmap = pdfium::MakeRetain<CFX_DIBitmap>();
844   if (!pBitmap->Create(width, height,
845                        alpha ? FXDIB_Format::kArgb : FXDIB_Format::kRgb32)) {
846     return nullptr;
847   }
848   return FPDFBitmapFromCFXDIBitmap(pBitmap.Leak());
849 }
850 
FPDFBitmap_CreateEx(int width,int height,int format,void * first_scan,int stride)851 FPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV FPDFBitmap_CreateEx(int width,
852                                                           int height,
853                                                           int format,
854                                                           void* first_scan,
855                                                           int stride) {
856   FXDIB_Format fx_format;
857   switch (format) {
858     case FPDFBitmap_Gray:
859       fx_format = FXDIB_Format::k8bppRgb;
860       break;
861     case FPDFBitmap_BGR:
862       fx_format = FXDIB_Format::kRgb;
863       break;
864     case FPDFBitmap_BGRx:
865       fx_format = FXDIB_Format::kRgb32;
866       break;
867     case FPDFBitmap_BGRA:
868       fx_format = FXDIB_Format::kArgb;
869       break;
870     default:
871       return nullptr;
872   }
873 
874   // Ensure external memory is good at least for the duration of this call.
875   UnownedPtr<uint8_t> pChecker(static_cast<uint8_t*>(first_scan));
876   auto pBitmap = pdfium::MakeRetain<CFX_DIBitmap>();
877   if (!pBitmap->Create(width, height, fx_format, pChecker, stride))
878     return nullptr;
879 
880   return FPDFBitmapFromCFXDIBitmap(pBitmap.Leak());
881 }
882 
FPDFBitmap_GetFormat(FPDF_BITMAP bitmap)883 FPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetFormat(FPDF_BITMAP bitmap) {
884   if (!bitmap)
885     return FPDFBitmap_Unknown;
886 
887   FXDIB_Format format = CFXDIBitmapFromFPDFBitmap(bitmap)->GetFormat();
888   switch (format) {
889     case FXDIB_Format::k8bppRgb:
890     case FXDIB_Format::k8bppMask:
891       return FPDFBitmap_Gray;
892     case FXDIB_Format::kRgb:
893       return FPDFBitmap_BGR;
894     case FXDIB_Format::kRgb32:
895       return FPDFBitmap_BGRx;
896     case FXDIB_Format::kArgb:
897       return FPDFBitmap_BGRA;
898     default:
899       return FPDFBitmap_Unknown;
900   }
901 }
902 
FPDFBitmap_FillRect(FPDF_BITMAP bitmap,int left,int top,int width,int height,FPDF_DWORD color)903 FPDF_EXPORT void FPDF_CALLCONV FPDFBitmap_FillRect(FPDF_BITMAP bitmap,
904                                                    int left,
905                                                    int top,
906                                                    int width,
907                                                    int height,
908                                                    FPDF_DWORD color) {
909   if (!bitmap)
910     return;
911 
912   CFX_DefaultRenderDevice device;
913   RetainPtr<CFX_DIBitmap> pBitmap(CFXDIBitmapFromFPDFBitmap(bitmap));
914   device.Attach(pBitmap);
915   if (!pBitmap->IsAlphaFormat())
916     color |= 0xFF000000;
917   device.FillRect(FX_RECT(left, top, left + width, top + height),
918                   static_cast<uint32_t>(color));
919 }
920 
FPDFBitmap_GetBuffer(FPDF_BITMAP bitmap)921 FPDF_EXPORT void* FPDF_CALLCONV FPDFBitmap_GetBuffer(FPDF_BITMAP bitmap) {
922   return bitmap ? CFXDIBitmapFromFPDFBitmap(bitmap)->GetBuffer().data()
923                 : nullptr;
924 }
925 
FPDFBitmap_GetWidth(FPDF_BITMAP bitmap)926 FPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetWidth(FPDF_BITMAP bitmap) {
927   return bitmap ? CFXDIBitmapFromFPDFBitmap(bitmap)->GetWidth() : 0;
928 }
929 
FPDFBitmap_GetHeight(FPDF_BITMAP bitmap)930 FPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetHeight(FPDF_BITMAP bitmap) {
931   return bitmap ? CFXDIBitmapFromFPDFBitmap(bitmap)->GetHeight() : 0;
932 }
933 
FPDFBitmap_GetStride(FPDF_BITMAP bitmap)934 FPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetStride(FPDF_BITMAP bitmap) {
935   return bitmap ? CFXDIBitmapFromFPDFBitmap(bitmap)->GetPitch() : 0;
936 }
937 
FPDFBitmap_Destroy(FPDF_BITMAP bitmap)938 FPDF_EXPORT void FPDF_CALLCONV FPDFBitmap_Destroy(FPDF_BITMAP bitmap) {
939   RetainPtr<CFX_DIBitmap> destroyer;
940   destroyer.Unleak(CFXDIBitmapFromFPDFBitmap(bitmap));
941 }
942 
943 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDF_GetPageSizeByIndexF(FPDF_DOCUMENT document,int page_index,FS_SIZEF * size)944 FPDF_GetPageSizeByIndexF(FPDF_DOCUMENT document,
945                          int page_index,
946                          FS_SIZEF* size) {
947   if (!size)
948     return false;
949 
950   auto* pDoc = CPDFDocumentFromFPDFDocument(document);
951   if (!pDoc)
952     return false;
953 
954 #ifdef PDF_ENABLE_XFA
955   if (page_index < 0 || page_index >= FPDF_GetPageCount(document))
956     return false;
957 
958   auto* pContext = static_cast<CPDFXFA_Context*>(pDoc->GetExtension());
959   if (pContext) {
960     RetainPtr<CPDFXFA_Page> pPage = pContext->GetOrCreateXFAPage(page_index);
961     if (!pPage)
962       return false;
963 
964     size->width = pPage->GetPageWidth();
965     size->height = pPage->GetPageHeight();
966     return true;
967   }
968 #endif  // PDF_ENABLE_XFA
969 
970   RetainPtr<CPDF_Dictionary> pDict = pDoc->GetMutablePageDictionary(page_index);
971   if (!pDict)
972     return false;
973 
974   auto page = pdfium::MakeRetain<CPDF_Page>(pDoc, std::move(pDict));
975   page->AddPageImageCache();
976   size->width = page->GetPageWidth();
977   size->height = page->GetPageHeight();
978   return true;
979 }
980 
FPDF_GetPageSizeByIndex(FPDF_DOCUMENT document,int page_index,double * width,double * height)981 FPDF_EXPORT int FPDF_CALLCONV FPDF_GetPageSizeByIndex(FPDF_DOCUMENT document,
982                                                       int page_index,
983                                                       double* width,
984                                                       double* height) {
985   if (!width || !height)
986     return false;
987 
988   FS_SIZEF size;
989   if (!FPDF_GetPageSizeByIndexF(document, page_index, &size))
990     return false;
991 
992   *width = size.width;
993   *height = size.height;
994   return true;
995 }
996 
997 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDF_VIEWERREF_GetPrintScaling(FPDF_DOCUMENT document)998 FPDF_VIEWERREF_GetPrintScaling(FPDF_DOCUMENT document) {
999   const CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
1000   if (!pDoc)
1001     return true;
1002   CPDF_ViewerPreferences viewRef(pDoc);
1003   return viewRef.PrintScaling();
1004 }
1005 
1006 FPDF_EXPORT int FPDF_CALLCONV
FPDF_VIEWERREF_GetNumCopies(FPDF_DOCUMENT document)1007 FPDF_VIEWERREF_GetNumCopies(FPDF_DOCUMENT document) {
1008   const CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
1009   if (!pDoc)
1010     return 1;
1011   CPDF_ViewerPreferences viewRef(pDoc);
1012   return viewRef.NumCopies();
1013 }
1014 
1015 FPDF_EXPORT FPDF_PAGERANGE FPDF_CALLCONV
FPDF_VIEWERREF_GetPrintPageRange(FPDF_DOCUMENT document)1016 FPDF_VIEWERREF_GetPrintPageRange(FPDF_DOCUMENT document) {
1017   const CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
1018   if (!pDoc)
1019     return nullptr;
1020   CPDF_ViewerPreferences viewRef(pDoc);
1021 
1022   // Unretained reference in public API. NOLINTNEXTLINE
1023   return FPDFPageRangeFromCPDFArray(viewRef.PrintPageRange());
1024 }
1025 
1026 FPDF_EXPORT size_t FPDF_CALLCONV
FPDF_VIEWERREF_GetPrintPageRangeCount(FPDF_PAGERANGE pagerange)1027 FPDF_VIEWERREF_GetPrintPageRangeCount(FPDF_PAGERANGE pagerange) {
1028   const CPDF_Array* pArray = CPDFArrayFromFPDFPageRange(pagerange);
1029   return pArray ? pArray->size() : 0;
1030 }
1031 
1032 FPDF_EXPORT int FPDF_CALLCONV
FPDF_VIEWERREF_GetPrintPageRangeElement(FPDF_PAGERANGE pagerange,size_t index)1033 FPDF_VIEWERREF_GetPrintPageRangeElement(FPDF_PAGERANGE pagerange,
1034                                         size_t index) {
1035   const CPDF_Array* pArray = CPDFArrayFromFPDFPageRange(pagerange);
1036   if (!pArray || index >= pArray->size())
1037     return -1;
1038   return pArray->GetIntegerAt(index);
1039 }
1040 
1041 FPDF_EXPORT FPDF_DUPLEXTYPE FPDF_CALLCONV
FPDF_VIEWERREF_GetDuplex(FPDF_DOCUMENT document)1042 FPDF_VIEWERREF_GetDuplex(FPDF_DOCUMENT document) {
1043   const CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
1044   if (!pDoc)
1045     return DuplexUndefined;
1046   CPDF_ViewerPreferences viewRef(pDoc);
1047   ByteString duplex = viewRef.Duplex();
1048   if ("Simplex" == duplex)
1049     return Simplex;
1050   if ("DuplexFlipShortEdge" == duplex)
1051     return DuplexFlipShortEdge;
1052   if ("DuplexFlipLongEdge" == duplex)
1053     return DuplexFlipLongEdge;
1054   return DuplexUndefined;
1055 }
1056 
1057 FPDF_EXPORT unsigned long FPDF_CALLCONV
FPDF_VIEWERREF_GetName(FPDF_DOCUMENT document,FPDF_BYTESTRING key,char * buffer,unsigned long length)1058 FPDF_VIEWERREF_GetName(FPDF_DOCUMENT document,
1059                        FPDF_BYTESTRING key,
1060                        char* buffer,
1061                        unsigned long length) {
1062   const CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
1063   if (!pDoc)
1064     return 0;
1065 
1066   CPDF_ViewerPreferences viewRef(pDoc);
1067   absl::optional<ByteString> bsVal = viewRef.GenericName(key);
1068   if (!bsVal.has_value())
1069     return 0;
1070 
1071   return NulTerminateMaybeCopyAndReturnLength(bsVal.value(), buffer, length);
1072 }
1073 
1074 FPDF_EXPORT FPDF_DWORD FPDF_CALLCONV
FPDF_CountNamedDests(FPDF_DOCUMENT document)1075 FPDF_CountNamedDests(FPDF_DOCUMENT document) {
1076   CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
1077   if (!pDoc)
1078     return 0;
1079 
1080   const CPDF_Dictionary* pRoot = pDoc->GetRoot();
1081   if (!pRoot)
1082     return 0;
1083 
1084   auto name_tree = CPDF_NameTree::Create(pDoc, "Dests");
1085   FX_SAFE_UINT32 count = name_tree ? name_tree->GetCount() : 0;
1086   RetainPtr<const CPDF_Dictionary> pOldStyleDests = pRoot->GetDictFor("Dests");
1087   if (pOldStyleDests)
1088     count += pOldStyleDests->size();
1089   return count.ValueOrDefault(0);
1090 }
1091 
1092 FPDF_EXPORT FPDF_DEST FPDF_CALLCONV
FPDF_GetNamedDestByName(FPDF_DOCUMENT document,FPDF_BYTESTRING name)1093 FPDF_GetNamedDestByName(FPDF_DOCUMENT document, FPDF_BYTESTRING name) {
1094   if (!name || name[0] == 0)
1095     return nullptr;
1096 
1097   CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
1098   if (!pDoc)
1099     return nullptr;
1100 
1101   ByteString dest_name(name);
1102 
1103   // TODO(tsepez): murky ownership, should caller get a reference?
1104   // Unretained reference in public API. NOLINTNEXTLINE
1105   return FPDFDestFromCPDFArray(CPDF_NameTree::LookupNamedDest(pDoc, dest_name));
1106 }
1107 
1108 #ifdef PDF_ENABLE_V8
FPDF_GetRecommendedV8Flags()1109 FPDF_EXPORT const char* FPDF_CALLCONV FPDF_GetRecommendedV8Flags() {
1110   // Use interpreted JS only to avoid RWX pages in our address space. Also,
1111   // --jitless implies --no-expose-wasm, which reduce exposure since no PDF
1112   // should contain web assembly.
1113   return "--jitless";
1114 }
1115 
FPDF_GetArrayBufferAllocatorSharedInstance()1116 FPDF_EXPORT void* FPDF_CALLCONV FPDF_GetArrayBufferAllocatorSharedInstance() {
1117   static pdfium::base::NoDestructor<CFX_V8ArrayBufferAllocator> allocator;
1118   return allocator.get();
1119 }
1120 #endif  // PDF_ENABLE_V8
1121 
1122 #ifdef PDF_ENABLE_XFA
FPDF_BStr_Init(FPDF_BSTR * bstr)1123 FPDF_EXPORT FPDF_RESULT FPDF_CALLCONV FPDF_BStr_Init(FPDF_BSTR* bstr) {
1124   if (!bstr)
1125     return -1;
1126 
1127   bstr->str = nullptr;
1128   bstr->len = 0;
1129   return 0;
1130 }
1131 
FPDF_BStr_Set(FPDF_BSTR * bstr,const char * cstr,int length)1132 FPDF_EXPORT FPDF_RESULT FPDF_CALLCONV FPDF_BStr_Set(FPDF_BSTR* bstr,
1133                                                     const char* cstr,
1134                                                     int length) {
1135   if (!bstr || !cstr)
1136     return -1;
1137 
1138   if (length == -1)
1139     length = pdfium::base::checked_cast<int>(strlen(cstr));
1140 
1141   if (length == 0) {
1142     FPDF_BStr_Clear(bstr);
1143     return 0;
1144   }
1145 
1146   if (bstr->str && bstr->len < length)
1147     bstr->str = FX_Realloc(char, bstr->str, length + 1);
1148   else if (!bstr->str)
1149     bstr->str = FX_Alloc(char, length + 1);
1150 
1151   bstr->str[length] = 0;
1152   memcpy(bstr->str, cstr, length);
1153   bstr->len = length;
1154   return 0;
1155 }
1156 
FPDF_BStr_Clear(FPDF_BSTR * bstr)1157 FPDF_EXPORT FPDF_RESULT FPDF_CALLCONV FPDF_BStr_Clear(FPDF_BSTR* bstr) {
1158   if (!bstr)
1159     return -1;
1160 
1161   if (bstr->str) {
1162     FX_Free(bstr->str);
1163     bstr->str = nullptr;
1164   }
1165   bstr->len = 0;
1166   return 0;
1167 }
1168 #endif  // PDF_ENABLE_XFA
1169 
FPDF_GetNamedDest(FPDF_DOCUMENT document,int index,void * buffer,long * buflen)1170 FPDF_EXPORT FPDF_DEST FPDF_CALLCONV FPDF_GetNamedDest(FPDF_DOCUMENT document,
1171                                                       int index,
1172                                                       void* buffer,
1173                                                       long* buflen) {
1174   if (!buffer)
1175     *buflen = 0;
1176 
1177   if (index < 0)
1178     return nullptr;
1179 
1180   CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
1181   if (!pDoc)
1182     return nullptr;
1183 
1184   const CPDF_Dictionary* pRoot = pDoc->GetRoot();
1185   if (!pRoot)
1186     return nullptr;
1187 
1188   auto name_tree = CPDF_NameTree::Create(pDoc, "Dests");
1189   size_t name_tree_count = name_tree ? name_tree->GetCount() : 0;
1190   RetainPtr<const CPDF_Object> pDestObj;
1191   WideString wsName;
1192   if (static_cast<size_t>(index) >= name_tree_count) {
1193     // If |index| is out of bounds, then try to retrieve the Nth old style named
1194     // destination. Where N is 0-indexed, with N = index - name_tree_count.
1195     RetainPtr<const CPDF_Dictionary> pDest = pRoot->GetDictFor("Dests");
1196     if (!pDest)
1197       return nullptr;
1198 
1199     FX_SAFE_INT32 checked_count = name_tree_count;
1200     checked_count += pDest->size();
1201     if (!checked_count.IsValid() || index >= checked_count.ValueOrDie())
1202       return nullptr;
1203 
1204     index -= name_tree_count;
1205     int i = 0;
1206     ByteStringView bsName;
1207     CPDF_DictionaryLocker locker(pDest);
1208     for (const auto& it : locker) {
1209       bsName = it.first.AsStringView();
1210       pDestObj = it.second;
1211       if (i == index)
1212         break;
1213       i++;
1214     }
1215     wsName = PDF_DecodeText(bsName.raw_span());
1216   } else {
1217     pDestObj = name_tree->LookupValueAndName(index, &wsName);
1218   }
1219   if (!pDestObj)
1220     return nullptr;
1221   if (const CPDF_Dictionary* pDict = pDestObj->AsDictionary()) {
1222     pDestObj = pDict->GetArrayFor("D");
1223     if (!pDestObj)
1224       return nullptr;
1225   }
1226   if (!pDestObj->IsArray())
1227     return nullptr;
1228 
1229   ByteString utf16Name = wsName.ToUTF16LE();
1230   int len = pdfium::base::checked_cast<int>(utf16Name.GetLength());
1231   if (!buffer) {
1232     *buflen = len;
1233   } else if (len <= *buflen) {
1234     memcpy(buffer, utf16Name.c_str(), len);
1235     *buflen = len;
1236   } else {
1237     *buflen = -1;
1238   }
1239   return FPDFDestFromCPDFArray(pDestObj->AsArray());
1240 }
1241 
FPDF_GetXFAPacketCount(FPDF_DOCUMENT document)1242 FPDF_EXPORT int FPDF_CALLCONV FPDF_GetXFAPacketCount(FPDF_DOCUMENT document) {
1243   CPDF_Document* doc = CPDFDocumentFromFPDFDocument(document);
1244   if (!doc)
1245     return -1;
1246 
1247   return fxcrt::CollectionSize<int>(
1248       GetXFAPackets(GetXFAEntryFromDocument(doc)));
1249 }
1250 
1251 FPDF_EXPORT unsigned long FPDF_CALLCONV
FPDF_GetXFAPacketName(FPDF_DOCUMENT document,int index,void * buffer,unsigned long buflen)1252 FPDF_GetXFAPacketName(FPDF_DOCUMENT document,
1253                       int index,
1254                       void* buffer,
1255                       unsigned long buflen) {
1256   CPDF_Document* doc = CPDFDocumentFromFPDFDocument(document);
1257   if (!doc || index < 0)
1258     return 0;
1259 
1260   std::vector<XFAPacket> xfa_packets =
1261       GetXFAPackets(GetXFAEntryFromDocument(doc));
1262   if (static_cast<size_t>(index) >= xfa_packets.size())
1263     return 0;
1264 
1265   return NulTerminateMaybeCopyAndReturnLength(xfa_packets[index].name, buffer,
1266                                               buflen);
1267 }
1268 
1269 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDF_GetXFAPacketContent(FPDF_DOCUMENT document,int index,void * buffer,unsigned long buflen,unsigned long * out_buflen)1270 FPDF_GetXFAPacketContent(FPDF_DOCUMENT document,
1271                          int index,
1272                          void* buffer,
1273                          unsigned long buflen,
1274                          unsigned long* out_buflen) {
1275   CPDF_Document* doc = CPDFDocumentFromFPDFDocument(document);
1276   if (!doc || index < 0 || !out_buflen)
1277     return false;
1278 
1279   std::vector<XFAPacket> xfa_packets =
1280       GetXFAPackets(GetXFAEntryFromDocument(doc));
1281   if (static_cast<size_t>(index) >= xfa_packets.size())
1282     return false;
1283 
1284   *out_buflen = DecodeStreamMaybeCopyAndReturnLength(
1285       xfa_packets[index].data,
1286       {static_cast<uint8_t*>(buffer), static_cast<size_t>(buflen)});
1287   return true;
1288 }
1289 
1290 FPDF_EXPORT unsigned long FPDF_CALLCONV
FPDF_GetTrailerEnds(FPDF_DOCUMENT document,unsigned int * buffer,unsigned long length)1291 FPDF_GetTrailerEnds(FPDF_DOCUMENT document,
1292                     unsigned int* buffer,
1293                     unsigned long length) {
1294   auto* doc = CPDFDocumentFromFPDFDocument(document);
1295   if (!doc)
1296     return 0;
1297 
1298   // Start recording trailer ends.
1299   auto* parser = doc->GetParser();
1300   std::vector<unsigned int> trailer_ends = parser->GetTrailerEnds();
1301   const unsigned long trailer_ends_len =
1302       fxcrt::CollectionSize<unsigned long>(trailer_ends);
1303   if (buffer && length >= trailer_ends_len) {
1304     for (size_t i = 0; i < trailer_ends_len; ++i)
1305       buffer[i] = trailer_ends[i];
1306   }
1307 
1308   return trailer_ends_len;
1309 }
1310