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