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 "core/fxge/dib/cfx_dibitmap.h"
44 #include "fpdfsdk/cpdfsdk_customaccess.h"
45 #include "fpdfsdk/cpdfsdk_formfillenvironment.h"
46 #include "fpdfsdk/cpdfsdk_helpers.h"
47 #include "fpdfsdk/cpdfsdk_pageview.h"
48 #include "fpdfsdk/cpdfsdk_renderpage.h"
49 #include "fxjs/ijs_runtime.h"
50 #include "public/fpdf_formfill.h"
51 #include "third_party/base/check_op.h"
52 #include "third_party/base/containers/span.h"
53 #include "third_party/base/memory/ptr_util.h"
54 #include "third_party/base/numerics/safe_conversions.h"
55
56 #ifdef PDF_ENABLE_V8
57 #include "fxjs/cfx_v8_array_buffer_allocator.h"
58 #include "third_party/base/no_destructor.h"
59 #endif
60
61 #ifdef PDF_ENABLE_XFA
62 #include "fpdfsdk/fpdfxfa/cpdfxfa_context.h"
63 #include "fpdfsdk/fpdfxfa/cpdfxfa_page.h"
64 #endif // PDF_ENABLE_XFA
65
66 #if BUILDFLAG(IS_WIN)
67 #include "core/fpdfapi/render/cpdf_progressiverenderer.h"
68 #include "core/fpdfapi/render/cpdf_windowsrenderdevice.h"
69 #include "public/fpdf_edit.h"
70
71 #if defined(_SKIA_SUPPORT_)
72 class SkCanvas;
73 #endif // defined(_SKIA_SUPPORT_)
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 owned_context = std::make_unique<CPDF_PageRenderContext>();
550 CPDF_PageRenderContext* context = owned_context.get();
551 CPDF_Page::RenderContextClearer clearer(pPage);
552 pPage->SetRenderContext(std::move(owned_context));
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 context->m_pDevice = std::make_unique<CPDF_WindowsRenderDevice>(
568 dc, render_data->GetPSFontTracker());
569 CPDFSDK_RenderPageWithContext(context, 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 `device`.
579 pBitmap->Create(size_x, size_y, FXDIB_Format::kArgb);
580 pBitmap->Clear(0x00ffffff);
581 auto device = std::make_unique<CFX_DefaultRenderDevice>();
582 device->Attach(pBitmap);
583 context->m_pDevice = std::move(device);
584 if (bHasMask) {
585 context->m_pOptions = std::make_unique<CPDF_RenderOptions>();
586 context->m_pOptions->GetOptions().bBreakForMasks = true;
587 }
588
589 CPDFSDK_RenderPageWithContext(context, 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(
601 pDst->GetWritableBuffer().first(pBitmap->GetPitch() * size_y), -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 context->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 owned_context = std::make_unique<CPDF_PageRenderContext>();
628 context = owned_context.get();
629 pPage->SetRenderContext(std::move(owned_context));
630 context->m_pDevice = std::make_unique<CPDF_WindowsRenderDevice>(
631 dc, render_data->GetPSFontTracker());
632 context->m_pOptions = std::make_unique<CPDF_RenderOptions>();
633 context->m_pOptions->GetOptions().bBreakForMasks = true;
634
635 CPDFSDK_RenderPageWithContext(context, 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(context->m_pDevice.get(), bitmaps[i], bitmap_areas[i]);
645 }
646 // Render the next portion of page.
647 context->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 owned_context = std::make_unique<CPDF_PageRenderContext>();
668 CPDF_PageRenderContext* context = owned_context.get();
669 CPDF_Page::RenderContextClearer clearer(pPage);
670 pPage->SetRenderContext(std::move(owned_context));
671
672 RetainPtr<CFX_DIBitmap> pBitmap(CFXDIBitmapFromFPDFBitmap(bitmap));
673 auto device = std::make_unique<CFX_DefaultRenderDevice>();
674 device->AttachWithRgbByteOrder(pBitmap, !!(flags & FPDF_REVERSE_BYTE_ORDER));
675 context->m_pDevice = std::move(device);
676
677 CPDFSDK_RenderPageWithContext(context, pPage, start_x, start_y, size_x,
678 size_y, rotate, flags, /*color_scheme=*/nullptr,
679 /*need_to_restore=*/true,
680 /*pause=*/nullptr);
681
682 #if defined(_SKIA_SUPPORT_)
683 if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer()) {
684 pBitmap->UnPreMultiply();
685 }
686 #endif
687 }
688
689 FPDF_EXPORT void FPDF_CALLCONV
FPDF_RenderPageBitmapWithMatrix(FPDF_BITMAP bitmap,FPDF_PAGE page,const FS_MATRIX * matrix,const FS_RECTF * clipping,int flags)690 FPDF_RenderPageBitmapWithMatrix(FPDF_BITMAP bitmap,
691 FPDF_PAGE page,
692 const FS_MATRIX* matrix,
693 const FS_RECTF* clipping,
694 int flags) {
695 if (!bitmap)
696 return;
697
698 CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
699 if (!pPage)
700 return;
701
702 auto owned_context = std::make_unique<CPDF_PageRenderContext>();
703 CPDF_PageRenderContext* context = owned_context.get();
704 CPDF_Page::RenderContextClearer clearer(pPage);
705 pPage->SetRenderContext(std::move(owned_context));
706
707 RetainPtr<CFX_DIBitmap> pBitmap(CFXDIBitmapFromFPDFBitmap(bitmap));
708 auto device = std::make_unique<CFX_DefaultRenderDevice>();
709 device->AttachWithRgbByteOrder(std::move(pBitmap),
710 !!(flags & FPDF_REVERSE_BYTE_ORDER));
711 context->m_pDevice = std::move(device);
712
713 CFX_FloatRect clipping_rect;
714 if (clipping)
715 clipping_rect = CFXFloatRectFromFSRectF(*clipping);
716 FX_RECT clip_rect = clipping_rect.ToFxRect();
717
718 const FX_RECT rect(0, 0, pPage->GetPageWidth(), pPage->GetPageHeight());
719 CFX_Matrix transform_matrix = pPage->GetDisplayMatrix(rect, 0);
720 if (matrix)
721 transform_matrix *= CFXMatrixFromFSMatrix(*matrix);
722 CPDFSDK_RenderPage(context, pPage, transform_matrix, clip_rect, flags,
723 /*color_scheme=*/nullptr);
724 }
725
726 #if defined(_SKIA_SUPPORT_)
FPDF_RenderPageSkia(FPDF_SKIA_CANVAS canvas,FPDF_PAGE page,int size_x,int size_y)727 FPDF_EXPORT void FPDF_CALLCONV FPDF_RenderPageSkia(FPDF_SKIA_CANVAS canvas,
728 FPDF_PAGE page,
729 int size_x,
730 int size_y) {
731 if (!canvas) {
732 return;
733 }
734
735 CPDF_Page* cpdf_page = CPDFPageFromFPDFPage(page);
736 if (!cpdf_page) {
737 return;
738 }
739
740 auto owned_context = std::make_unique<CPDF_PageRenderContext>();
741 CPDF_PageRenderContext* context = owned_context.get();
742 CPDF_Page::RenderContextClearer clearer(cpdf_page);
743 cpdf_page->SetRenderContext(std::move(owned_context));
744
745 auto device = std::make_unique<CFX_DefaultRenderDevice>();
746 device->AttachCanvas(reinterpret_cast<SkCanvas*>(canvas));
747 context->m_pDevice = std::move(device);
748
749 CPDFSDK_RenderPageWithContext(context, cpdf_page, 0, 0, size_x, size_y, 0, 0,
750 /*color_scheme=*/nullptr,
751 /*need_to_restore=*/true, /*pause=*/nullptr);
752 }
753 #endif // defined(_SKIA_SUPPORT_)
754
FPDF_ClosePage(FPDF_PAGE page)755 FPDF_EXPORT void FPDF_CALLCONV FPDF_ClosePage(FPDF_PAGE page) {
756 if (!page)
757 return;
758
759 // Take it back across the API and hold for duration of this function.
760 RetainPtr<IPDF_Page> pPage;
761 pPage.Unleak(IPDFPageFromFPDFPage(page));
762
763 if (pPage->AsXFAPage())
764 return;
765
766 // This will delete the PageView object corresponding to |pPage|. We must
767 // cleanup the PageView before releasing the reference on |pPage| as it will
768 // attempt to reset the PageView during destruction.
769 pPage->AsPDFPage()->ClearView();
770 }
771
FPDF_CloseDocument(FPDF_DOCUMENT document)772 FPDF_EXPORT void FPDF_CALLCONV FPDF_CloseDocument(FPDF_DOCUMENT document) {
773 // Take it back across the API and throw it away,
774 std::unique_ptr<CPDF_Document>(CPDFDocumentFromFPDFDocument(document));
775 }
776
FPDF_GetLastError()777 FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetLastError() {
778 return FXSYS_GetLastError();
779 }
780
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)781 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_DeviceToPage(FPDF_PAGE page,
782 int start_x,
783 int start_y,
784 int size_x,
785 int size_y,
786 int rotate,
787 int device_x,
788 int device_y,
789 double* page_x,
790 double* page_y) {
791 if (!page || !page_x || !page_y)
792 return false;
793
794 IPDF_Page* pPage = IPDFPageFromFPDFPage(page);
795 const FX_RECT rect(start_x, start_y, start_x + size_x, start_y + size_y);
796 absl::optional<CFX_PointF> pos =
797 pPage->DeviceToPage(rect, rotate, CFX_PointF(device_x, device_y));
798 if (!pos.has_value())
799 return false;
800
801 *page_x = pos->x;
802 *page_y = pos->y;
803 return true;
804 }
805
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)806 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_PageToDevice(FPDF_PAGE page,
807 int start_x,
808 int start_y,
809 int size_x,
810 int size_y,
811 int rotate,
812 double page_x,
813 double page_y,
814 int* device_x,
815 int* device_y) {
816 if (!page || !device_x || !device_y)
817 return false;
818
819 IPDF_Page* pPage = IPDFPageFromFPDFPage(page);
820 const FX_RECT rect(start_x, start_y, start_x + size_x, start_y + size_y);
821 CFX_PointF page_point(static_cast<float>(page_x), static_cast<float>(page_y));
822 absl::optional<CFX_PointF> pos =
823 pPage->PageToDevice(rect, rotate, page_point);
824 if (!pos.has_value())
825 return false;
826
827 *device_x = FXSYS_roundf(pos->x);
828 *device_y = FXSYS_roundf(pos->y);
829 return true;
830 }
831
FPDFBitmap_Create(int width,int height,int alpha)832 FPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV FPDFBitmap_Create(int width,
833 int height,
834 int alpha) {
835 auto pBitmap = pdfium::MakeRetain<CFX_DIBitmap>();
836 if (!pBitmap->Create(width, height,
837 alpha ? FXDIB_Format::kArgb : FXDIB_Format::kRgb32)) {
838 return nullptr;
839 }
840 return FPDFBitmapFromCFXDIBitmap(pBitmap.Leak());
841 }
842
FPDFBitmap_CreateEx(int width,int height,int format,void * first_scan,int stride)843 FPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV FPDFBitmap_CreateEx(int width,
844 int height,
845 int format,
846 void* first_scan,
847 int stride) {
848 FXDIB_Format fx_format;
849 switch (format) {
850 case FPDFBitmap_Gray:
851 fx_format = FXDIB_Format::k8bppRgb;
852 break;
853 case FPDFBitmap_BGR:
854 fx_format = FXDIB_Format::kRgb;
855 break;
856 case FPDFBitmap_BGRx:
857 fx_format = FXDIB_Format::kRgb32;
858 break;
859 case FPDFBitmap_BGRA:
860 fx_format = FXDIB_Format::kArgb;
861 break;
862 default:
863 return nullptr;
864 }
865
866 // Ensure external memory is good at least for the duration of this call.
867 UnownedPtr<uint8_t> pChecker(static_cast<uint8_t*>(first_scan));
868 auto pBitmap = pdfium::MakeRetain<CFX_DIBitmap>();
869 if (!pBitmap->Create(width, height, fx_format, pChecker, stride))
870 return nullptr;
871
872 return FPDFBitmapFromCFXDIBitmap(pBitmap.Leak());
873 }
874
FPDFBitmap_GetFormat(FPDF_BITMAP bitmap)875 FPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetFormat(FPDF_BITMAP bitmap) {
876 if (!bitmap)
877 return FPDFBitmap_Unknown;
878
879 FXDIB_Format format = CFXDIBitmapFromFPDFBitmap(bitmap)->GetFormat();
880 switch (format) {
881 case FXDIB_Format::k8bppRgb:
882 case FXDIB_Format::k8bppMask:
883 return FPDFBitmap_Gray;
884 case FXDIB_Format::kRgb:
885 return FPDFBitmap_BGR;
886 case FXDIB_Format::kRgb32:
887 return FPDFBitmap_BGRx;
888 case FXDIB_Format::kArgb:
889 return FPDFBitmap_BGRA;
890 default:
891 return FPDFBitmap_Unknown;
892 }
893 }
894
FPDFBitmap_FillRect(FPDF_BITMAP bitmap,int left,int top,int width,int height,FPDF_DWORD color)895 FPDF_EXPORT void FPDF_CALLCONV FPDFBitmap_FillRect(FPDF_BITMAP bitmap,
896 int left,
897 int top,
898 int width,
899 int height,
900 FPDF_DWORD color) {
901 if (!bitmap)
902 return;
903
904 CFX_DefaultRenderDevice device;
905 RetainPtr<CFX_DIBitmap> pBitmap(CFXDIBitmapFromFPDFBitmap(bitmap));
906 device.Attach(pBitmap);
907 if (!pBitmap->IsAlphaFormat())
908 color |= 0xFF000000;
909 device.FillRect(FX_RECT(left, top, left + width, top + height),
910 static_cast<uint32_t>(color));
911 }
912
FPDFBitmap_GetBuffer(FPDF_BITMAP bitmap)913 FPDF_EXPORT void* FPDF_CALLCONV FPDFBitmap_GetBuffer(FPDF_BITMAP bitmap) {
914 return bitmap ? CFXDIBitmapFromFPDFBitmap(bitmap)->GetWritableBuffer().data()
915 : nullptr;
916 }
917
FPDFBitmap_GetWidth(FPDF_BITMAP bitmap)918 FPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetWidth(FPDF_BITMAP bitmap) {
919 return bitmap ? CFXDIBitmapFromFPDFBitmap(bitmap)->GetWidth() : 0;
920 }
921
FPDFBitmap_GetHeight(FPDF_BITMAP bitmap)922 FPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetHeight(FPDF_BITMAP bitmap) {
923 return bitmap ? CFXDIBitmapFromFPDFBitmap(bitmap)->GetHeight() : 0;
924 }
925
FPDFBitmap_GetStride(FPDF_BITMAP bitmap)926 FPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetStride(FPDF_BITMAP bitmap) {
927 return bitmap ? CFXDIBitmapFromFPDFBitmap(bitmap)->GetPitch() : 0;
928 }
929
FPDFBitmap_Destroy(FPDF_BITMAP bitmap)930 FPDF_EXPORT void FPDF_CALLCONV FPDFBitmap_Destroy(FPDF_BITMAP bitmap) {
931 RetainPtr<CFX_DIBitmap> destroyer;
932 destroyer.Unleak(CFXDIBitmapFromFPDFBitmap(bitmap));
933 }
934
935 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDF_GetPageSizeByIndexF(FPDF_DOCUMENT document,int page_index,FS_SIZEF * size)936 FPDF_GetPageSizeByIndexF(FPDF_DOCUMENT document,
937 int page_index,
938 FS_SIZEF* size) {
939 if (!size)
940 return false;
941
942 auto* pDoc = CPDFDocumentFromFPDFDocument(document);
943 if (!pDoc)
944 return false;
945
946 #ifdef PDF_ENABLE_XFA
947 if (page_index < 0 || page_index >= FPDF_GetPageCount(document))
948 return false;
949
950 auto* pContext = static_cast<CPDFXFA_Context*>(pDoc->GetExtension());
951 if (pContext) {
952 RetainPtr<CPDFXFA_Page> pPage = pContext->GetOrCreateXFAPage(page_index);
953 if (!pPage)
954 return false;
955
956 size->width = pPage->GetPageWidth();
957 size->height = pPage->GetPageHeight();
958 return true;
959 }
960 #endif // PDF_ENABLE_XFA
961
962 RetainPtr<CPDF_Dictionary> pDict = pDoc->GetMutablePageDictionary(page_index);
963 if (!pDict)
964 return false;
965
966 auto page = pdfium::MakeRetain<CPDF_Page>(pDoc, std::move(pDict));
967 page->AddPageImageCache();
968 size->width = page->GetPageWidth();
969 size->height = page->GetPageHeight();
970 return true;
971 }
972
FPDF_GetPageSizeByIndex(FPDF_DOCUMENT document,int page_index,double * width,double * height)973 FPDF_EXPORT int FPDF_CALLCONV FPDF_GetPageSizeByIndex(FPDF_DOCUMENT document,
974 int page_index,
975 double* width,
976 double* height) {
977 if (!width || !height)
978 return false;
979
980 FS_SIZEF size;
981 if (!FPDF_GetPageSizeByIndexF(document, page_index, &size))
982 return false;
983
984 *width = size.width;
985 *height = size.height;
986 return true;
987 }
988
989 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDF_VIEWERREF_GetPrintScaling(FPDF_DOCUMENT document)990 FPDF_VIEWERREF_GetPrintScaling(FPDF_DOCUMENT document) {
991 const CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
992 if (!pDoc)
993 return true;
994 CPDF_ViewerPreferences viewRef(pDoc);
995 return viewRef.PrintScaling();
996 }
997
998 FPDF_EXPORT int FPDF_CALLCONV
FPDF_VIEWERREF_GetNumCopies(FPDF_DOCUMENT document)999 FPDF_VIEWERREF_GetNumCopies(FPDF_DOCUMENT document) {
1000 const CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
1001 if (!pDoc)
1002 return 1;
1003 CPDF_ViewerPreferences viewRef(pDoc);
1004 return viewRef.NumCopies();
1005 }
1006
1007 FPDF_EXPORT FPDF_PAGERANGE FPDF_CALLCONV
FPDF_VIEWERREF_GetPrintPageRange(FPDF_DOCUMENT document)1008 FPDF_VIEWERREF_GetPrintPageRange(FPDF_DOCUMENT document) {
1009 const CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
1010 if (!pDoc)
1011 return nullptr;
1012 CPDF_ViewerPreferences viewRef(pDoc);
1013
1014 // Unretained reference in public API. NOLINTNEXTLINE
1015 return FPDFPageRangeFromCPDFArray(viewRef.PrintPageRange());
1016 }
1017
1018 FPDF_EXPORT size_t FPDF_CALLCONV
FPDF_VIEWERREF_GetPrintPageRangeCount(FPDF_PAGERANGE pagerange)1019 FPDF_VIEWERREF_GetPrintPageRangeCount(FPDF_PAGERANGE pagerange) {
1020 const CPDF_Array* pArray = CPDFArrayFromFPDFPageRange(pagerange);
1021 return pArray ? pArray->size() : 0;
1022 }
1023
1024 FPDF_EXPORT int FPDF_CALLCONV
FPDF_VIEWERREF_GetPrintPageRangeElement(FPDF_PAGERANGE pagerange,size_t index)1025 FPDF_VIEWERREF_GetPrintPageRangeElement(FPDF_PAGERANGE pagerange,
1026 size_t index) {
1027 const CPDF_Array* pArray = CPDFArrayFromFPDFPageRange(pagerange);
1028 if (!pArray || index >= pArray->size())
1029 return -1;
1030 return pArray->GetIntegerAt(index);
1031 }
1032
1033 FPDF_EXPORT FPDF_DUPLEXTYPE FPDF_CALLCONV
FPDF_VIEWERREF_GetDuplex(FPDF_DOCUMENT document)1034 FPDF_VIEWERREF_GetDuplex(FPDF_DOCUMENT document) {
1035 const CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
1036 if (!pDoc)
1037 return DuplexUndefined;
1038 CPDF_ViewerPreferences viewRef(pDoc);
1039 ByteString duplex = viewRef.Duplex();
1040 if ("Simplex" == duplex)
1041 return Simplex;
1042 if ("DuplexFlipShortEdge" == duplex)
1043 return DuplexFlipShortEdge;
1044 if ("DuplexFlipLongEdge" == duplex)
1045 return DuplexFlipLongEdge;
1046 return DuplexUndefined;
1047 }
1048
1049 FPDF_EXPORT unsigned long FPDF_CALLCONV
FPDF_VIEWERREF_GetName(FPDF_DOCUMENT document,FPDF_BYTESTRING key,char * buffer,unsigned long length)1050 FPDF_VIEWERREF_GetName(FPDF_DOCUMENT document,
1051 FPDF_BYTESTRING key,
1052 char* buffer,
1053 unsigned long length) {
1054 const CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
1055 if (!pDoc)
1056 return 0;
1057
1058 CPDF_ViewerPreferences viewRef(pDoc);
1059 absl::optional<ByteString> bsVal = viewRef.GenericName(key);
1060 if (!bsVal.has_value())
1061 return 0;
1062
1063 return NulTerminateMaybeCopyAndReturnLength(bsVal.value(), buffer, length);
1064 }
1065
1066 FPDF_EXPORT FPDF_DWORD FPDF_CALLCONV
FPDF_CountNamedDests(FPDF_DOCUMENT document)1067 FPDF_CountNamedDests(FPDF_DOCUMENT document) {
1068 CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
1069 if (!pDoc)
1070 return 0;
1071
1072 const CPDF_Dictionary* pRoot = pDoc->GetRoot();
1073 if (!pRoot)
1074 return 0;
1075
1076 auto name_tree = CPDF_NameTree::Create(pDoc, "Dests");
1077 FX_SAFE_UINT32 count = name_tree ? name_tree->GetCount() : 0;
1078 RetainPtr<const CPDF_Dictionary> pOldStyleDests = pRoot->GetDictFor("Dests");
1079 if (pOldStyleDests)
1080 count += pOldStyleDests->size();
1081 return count.ValueOrDefault(0);
1082 }
1083
1084 FPDF_EXPORT FPDF_DEST FPDF_CALLCONV
FPDF_GetNamedDestByName(FPDF_DOCUMENT document,FPDF_BYTESTRING name)1085 FPDF_GetNamedDestByName(FPDF_DOCUMENT document, FPDF_BYTESTRING name) {
1086 if (!name || name[0] == 0)
1087 return nullptr;
1088
1089 CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
1090 if (!pDoc)
1091 return nullptr;
1092
1093 ByteString dest_name(name);
1094
1095 // TODO(tsepez): murky ownership, should caller get a reference?
1096 // Unretained reference in public API. NOLINTNEXTLINE
1097 return FPDFDestFromCPDFArray(CPDF_NameTree::LookupNamedDest(pDoc, dest_name));
1098 }
1099
1100 #ifdef PDF_ENABLE_V8
FPDF_GetRecommendedV8Flags()1101 FPDF_EXPORT const char* FPDF_CALLCONV FPDF_GetRecommendedV8Flags() {
1102 // Use interpreted JS only to avoid RWX pages in our address space. Also,
1103 // --jitless implies --no-expose-wasm, which reduce exposure since no PDF
1104 // should contain web assembly.
1105 return "--jitless";
1106 }
1107
FPDF_GetArrayBufferAllocatorSharedInstance()1108 FPDF_EXPORT void* FPDF_CALLCONV FPDF_GetArrayBufferAllocatorSharedInstance() {
1109 static pdfium::base::NoDestructor<CFX_V8ArrayBufferAllocator> allocator;
1110 return allocator.get();
1111 }
1112 #endif // PDF_ENABLE_V8
1113
1114 #ifdef PDF_ENABLE_XFA
FPDF_BStr_Init(FPDF_BSTR * bstr)1115 FPDF_EXPORT FPDF_RESULT FPDF_CALLCONV FPDF_BStr_Init(FPDF_BSTR* bstr) {
1116 if (!bstr)
1117 return -1;
1118
1119 bstr->str = nullptr;
1120 bstr->len = 0;
1121 return 0;
1122 }
1123
FPDF_BStr_Set(FPDF_BSTR * bstr,const char * cstr,int length)1124 FPDF_EXPORT FPDF_RESULT FPDF_CALLCONV FPDF_BStr_Set(FPDF_BSTR* bstr,
1125 const char* cstr,
1126 int length) {
1127 if (!bstr || !cstr)
1128 return -1;
1129
1130 if (length == -1)
1131 length = pdfium::base::checked_cast<int>(strlen(cstr));
1132
1133 if (length == 0) {
1134 FPDF_BStr_Clear(bstr);
1135 return 0;
1136 }
1137
1138 if (bstr->str && bstr->len < length)
1139 bstr->str = FX_Realloc(char, bstr->str, length + 1);
1140 else if (!bstr->str)
1141 bstr->str = FX_Alloc(char, length + 1);
1142
1143 bstr->str[length] = 0;
1144 memcpy(bstr->str, cstr, length);
1145 bstr->len = length;
1146 return 0;
1147 }
1148
FPDF_BStr_Clear(FPDF_BSTR * bstr)1149 FPDF_EXPORT FPDF_RESULT FPDF_CALLCONV FPDF_BStr_Clear(FPDF_BSTR* bstr) {
1150 if (!bstr)
1151 return -1;
1152
1153 if (bstr->str) {
1154 FX_Free(bstr->str);
1155 bstr->str = nullptr;
1156 }
1157 bstr->len = 0;
1158 return 0;
1159 }
1160 #endif // PDF_ENABLE_XFA
1161
FPDF_GetNamedDest(FPDF_DOCUMENT document,int index,void * buffer,long * buflen)1162 FPDF_EXPORT FPDF_DEST FPDF_CALLCONV FPDF_GetNamedDest(FPDF_DOCUMENT document,
1163 int index,
1164 void* buffer,
1165 long* buflen) {
1166 if (!buffer)
1167 *buflen = 0;
1168
1169 if (index < 0)
1170 return nullptr;
1171
1172 CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
1173 if (!pDoc)
1174 return nullptr;
1175
1176 const CPDF_Dictionary* pRoot = pDoc->GetRoot();
1177 if (!pRoot)
1178 return nullptr;
1179
1180 auto name_tree = CPDF_NameTree::Create(pDoc, "Dests");
1181 size_t name_tree_count = name_tree ? name_tree->GetCount() : 0;
1182 RetainPtr<const CPDF_Object> pDestObj;
1183 WideString wsName;
1184 if (static_cast<size_t>(index) >= name_tree_count) {
1185 // If |index| is out of bounds, then try to retrieve the Nth old style named
1186 // destination. Where N is 0-indexed, with N = index - name_tree_count.
1187 RetainPtr<const CPDF_Dictionary> pDest = pRoot->GetDictFor("Dests");
1188 if (!pDest)
1189 return nullptr;
1190
1191 FX_SAFE_INT32 checked_count = name_tree_count;
1192 checked_count += pDest->size();
1193 if (!checked_count.IsValid() || index >= checked_count.ValueOrDie())
1194 return nullptr;
1195
1196 index -= name_tree_count;
1197 int i = 0;
1198 ByteStringView bsName;
1199 CPDF_DictionaryLocker locker(pDest);
1200 for (const auto& it : locker) {
1201 bsName = it.first.AsStringView();
1202 pDestObj = it.second;
1203 if (i == index)
1204 break;
1205 i++;
1206 }
1207 wsName = PDF_DecodeText(bsName.raw_span());
1208 } else {
1209 pDestObj = name_tree->LookupValueAndName(index, &wsName);
1210 }
1211 if (!pDestObj)
1212 return nullptr;
1213 if (const CPDF_Dictionary* pDict = pDestObj->AsDictionary()) {
1214 pDestObj = pDict->GetArrayFor("D");
1215 if (!pDestObj)
1216 return nullptr;
1217 }
1218 if (!pDestObj->IsArray())
1219 return nullptr;
1220
1221 ByteString utf16Name = wsName.ToUTF16LE();
1222 int len = pdfium::base::checked_cast<int>(utf16Name.GetLength());
1223 if (!buffer) {
1224 *buflen = len;
1225 } else if (len <= *buflen) {
1226 memcpy(buffer, utf16Name.c_str(), len);
1227 *buflen = len;
1228 } else {
1229 *buflen = -1;
1230 }
1231 return FPDFDestFromCPDFArray(pDestObj->AsArray());
1232 }
1233
FPDF_GetXFAPacketCount(FPDF_DOCUMENT document)1234 FPDF_EXPORT int FPDF_CALLCONV FPDF_GetXFAPacketCount(FPDF_DOCUMENT document) {
1235 CPDF_Document* doc = CPDFDocumentFromFPDFDocument(document);
1236 if (!doc)
1237 return -1;
1238
1239 return fxcrt::CollectionSize<int>(
1240 GetXFAPackets(GetXFAEntryFromDocument(doc)));
1241 }
1242
1243 FPDF_EXPORT unsigned long FPDF_CALLCONV
FPDF_GetXFAPacketName(FPDF_DOCUMENT document,int index,void * buffer,unsigned long buflen)1244 FPDF_GetXFAPacketName(FPDF_DOCUMENT document,
1245 int index,
1246 void* buffer,
1247 unsigned long buflen) {
1248 CPDF_Document* doc = CPDFDocumentFromFPDFDocument(document);
1249 if (!doc || index < 0)
1250 return 0;
1251
1252 std::vector<XFAPacket> xfa_packets =
1253 GetXFAPackets(GetXFAEntryFromDocument(doc));
1254 if (static_cast<size_t>(index) >= xfa_packets.size())
1255 return 0;
1256
1257 return NulTerminateMaybeCopyAndReturnLength(xfa_packets[index].name, buffer,
1258 buflen);
1259 }
1260
1261 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDF_GetXFAPacketContent(FPDF_DOCUMENT document,int index,void * buffer,unsigned long buflen,unsigned long * out_buflen)1262 FPDF_GetXFAPacketContent(FPDF_DOCUMENT document,
1263 int index,
1264 void* buffer,
1265 unsigned long buflen,
1266 unsigned long* out_buflen) {
1267 CPDF_Document* doc = CPDFDocumentFromFPDFDocument(document);
1268 if (!doc || index < 0 || !out_buflen)
1269 return false;
1270
1271 std::vector<XFAPacket> xfa_packets =
1272 GetXFAPackets(GetXFAEntryFromDocument(doc));
1273 if (static_cast<size_t>(index) >= xfa_packets.size())
1274 return false;
1275
1276 *out_buflen = DecodeStreamMaybeCopyAndReturnLength(
1277 xfa_packets[index].data,
1278 {static_cast<uint8_t*>(buffer), static_cast<size_t>(buflen)});
1279 return true;
1280 }
1281
1282 FPDF_EXPORT unsigned long FPDF_CALLCONV
FPDF_GetTrailerEnds(FPDF_DOCUMENT document,unsigned int * buffer,unsigned long length)1283 FPDF_GetTrailerEnds(FPDF_DOCUMENT document,
1284 unsigned int* buffer,
1285 unsigned long length) {
1286 auto* doc = CPDFDocumentFromFPDFDocument(document);
1287 if (!doc)
1288 return 0;
1289
1290 // Start recording trailer ends.
1291 auto* parser = doc->GetParser();
1292 std::vector<unsigned int> trailer_ends = parser->GetTrailerEnds();
1293 const unsigned long trailer_ends_len =
1294 fxcrt::CollectionSize<unsigned long>(trailer_ends);
1295 if (buffer && length >= trailer_ends_len) {
1296 for (size_t i = 0; i < trailer_ends_len; ++i)
1297 buffer[i] = trailer_ends[i];
1298 }
1299
1300 return trailer_ends_len;
1301 }
1302