Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
fpdf_view.cpp
Go to the documentation of this file.
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)
74class SkCanvas;
75#endif // defined(PDF_USE_SKIA)
76
77// These checks are here because core/ and public/ cannot depend on each other.
78static_assert(static_cast<int>(WindowsPrintMode::kEmf) == FPDF_PRINTMODE_EMF,
79 "WindowsPrintMode::kEmf value mismatch");
80static_assert(static_cast<int>(WindowsPrintMode::kTextOnly) ==
81 FPDF_PRINTMODE_TEXTONLY,
82 "WindowsPrintMode::kTextOnly value mismatch");
83static_assert(static_cast<int>(WindowsPrintMode::kPostScript2) ==
84 FPDF_PRINTMODE_POSTSCRIPT2,
85 "WindowsPrintMode::kPostScript2 value mismatch");
86static_assert(static_cast<int>(WindowsPrintMode::kPostScript3) ==
87 FPDF_PRINTMODE_POSTSCRIPT3,
88 "WindowsPrintMode::kPostScript3 value mismatch");
89static_assert(static_cast<int>(WindowsPrintMode::kPostScript2PassThrough) ==
90 FPDF_PRINTMODE_POSTSCRIPT2_PASSTHROUGH,
91 "WindowsPrintMode::kPostScript2PassThrough value mismatch");
92static_assert(static_cast<int>(WindowsPrintMode::kPostScript3PassThrough) ==
93 FPDF_PRINTMODE_POSTSCRIPT3_PASSTHROUGH,
94 "WindowsPrintMode::kPostScript3PassThrough value mismatch");
95static_assert(static_cast<int>(WindowsPrintMode::kEmfImageMasks) ==
96 FPDF_PRINTMODE_EMF_IMAGE_MASKS,
97 "WindowsPrintMode::kEmfImageMasks value mismatch");
98static_assert(static_cast<int>(WindowsPrintMode::kPostScript3Type42) ==
99 FPDF_PRINTMODE_POSTSCRIPT3_TYPE42,
100 "WindowsPrintMode::kPostScript3Type42 value mismatch");
101static_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.
109static_assert(static_cast<int>(CFX_DefaultRenderDevice::RendererType::kAgg) ==
110 FPDF_RENDERERTYPE_AGG,
111 "CFX_DefaultRenderDevice::RendererType::kAGG value mismatch");
112static_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
117namespace {
118
119bool g_bLibraryInitialized = false;
120
121void 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
145void ResetRendererType() {
146#if defined(PDF_USE_SKIA)
147 CFX_DefaultRenderDevice::SetRendererType(
148 CFX_DefaultRenderDevice::kDefaultRenderer);
149#endif
150}
151
152RetainPtr<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
161struct XFAPacket {
162 ByteString name;
163 RetainPtr<const CPDF_Stream> data;
164};
165
166std::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
200FPDF_DOCUMENT LoadDocumentImpl(RetainPtr<IFX_SeekableReadStream> pFileAccess,
201 FPDF_BYTESTRING password) {
202 if (!pFileAccess) {
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) {
215 return nullptr;
216 }
217
218 ReportUnsupportedFeatures(pDocument.get());
219 return FPDFDocumentFromCPDFDocument(pDocument.release());
220}
221
222} // namespace
223
227
229FPDF_InitLibraryWithConfig(const FPDF_LIBRARY_CONFIG* config) {
230 if (g_bLibraryInitialized)
231 return;
232
235 CFX_GEModule::Create(config ? config->m_pUserFontPaths : nullptr);
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
258 if (!g_bLibraryInitialized)
259 return;
260
261 // Note: we teardown/destroy things in reverse order.
262 ResetRendererType();
263
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
278
279 g_bLibraryInitialized = false;
280}
281
283 FPDF_BOOL enable) {
284 return SetPDFSandboxPolicy(policy, enable);
285}
286
287#if BUILDFLAG(IS_WIN)
288FPDF_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
299FPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV
300FPDF_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
307FPDF_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
328FPDF_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
341FPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV
342FPDF_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
353FPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV
354FPDF_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
364FPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV
365FPDF_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
374 int* fileVersion) {
375 if (!fileVersion)
376 return false;
377
378 *fileVersion = 0;
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
396
397FPDF_EXPORT unsigned long FPDF_CALLCONV
398FPDF_GetDocPermissions(FPDF_DOCUMENT document) {
400 return pDoc ? pDoc->GetUserPermissions(/*get_owner_perms=*/true) : 0;
401}
402
403FPDF_EXPORT unsigned long FPDF_CALLCONV
404FPDF_GetDocUserPermissions(FPDF_DOCUMENT document) {
406 return pDoc ? pDoc->GetUserPermissions(/*get_owner_perms=*/false) : 0;
407}
408
410FPDF_GetSecurityHandlerRevision(FPDF_DOCUMENT 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
419FPDF_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
428FPDF_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
458 return pPage ? pPage->GetPageWidth() : 0.0f;
459}
460
462 return FPDF_GetPageWidthF(page);
463}
464
467 return pPage ? pPage->GetPageHeight() : 0.0f;
468}
469
471 return FPDF_GetPageHeightF(page);
472}
473
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)
488namespace {
489
490constexpr float kEpsilonSize = 0.01f;
491
492bool 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
497bool 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|.
512RetainPtr<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
545void 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
573FPDF_EXPORT void 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;
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;
610 }
611
612 RetainPtr<CFX_DIBitmap> pBitmap = pdfium::MakeRetain<CFX_DIBitmap>();
613 CHECK(pBitmap->Create(size_x, size_y, FXDIB_Format::kBgra));
614 if (!CFX_DefaultRenderDevice::UseSkiaRenderer()) {
615 // Not needed by Skia. Call it for AGG to preserve pre-existing behavior.
616 pBitmap->Clear(0x00ffffff);
617 }
618
619 auto device = std::make_unique<CFX_DefaultRenderDevice>();
620 device->Attach(pBitmap);
621 context->m_pDevice = std::move(device);
622 if (bHasMask) {
623 context->m_pOptions = std::make_unique<CPDF_RenderOptions>();
624 context->m_pOptions->GetOptions().bBreakForMasks = true;
625 }
626
627 CPDFSDK_RenderPageWithContext(context, pPage, start_x, start_y, size_x,
628 size_y, rotate, flags, /*color_scheme=*/nullptr,
629 /*need_to_restore=*/true,
630 /*pause=*/nullptr);
631
632 if (!bHasMask) {
633 CPDF_WindowsRenderDevice win_dc(dc, render_data->GetPSFontTracker());
634 bool bitsStretched = false;
635 if (win_dc.GetDeviceType() == DeviceType::kPrinter) {
636 auto dest_bitmap = pdfium::MakeRetain<CFX_DIBitmap>();
637 if (dest_bitmap->Create(size_x, size_y, FXDIB_Format::kBgrx)) {
638 fxcrt::Fill(dest_bitmap->GetWritableBuffer().first(pBitmap->GetPitch() *
639 size_y),
640 -1);
641 dest_bitmap->CompositeBitmap(0, 0, size_x, size_y, pBitmap, 0, 0,
642 BlendMode::kNormal, nullptr, false);
643 win_dc.StretchDIBits(std::move(dest_bitmap), 0, 0, size_x, size_y);
644 bitsStretched = true;
645 }
646 }
647 if (!bitsStretched)
648 win_dc.SetDIBits(std::move(pBitmap), 0, 0);
649 return;
650 }
651
652 // Finish rendering the page to bitmap and copy the correct segments
653 // of the page to individual image mask bitmaps.
654 const std::vector<CFX_FloatRect>& mask_boxes = pPage->GetMaskBoundingBoxes();
655 std::vector<FX_RECT> bitmap_areas(mask_boxes.size());
656 std::vector<RetainPtr<CFX_DIBitmap>> bitmaps(mask_boxes.size());
657 for (size_t i = 0; i < mask_boxes.size(); i++) {
658 bitmaps[i] = GetMaskBitmap(pPage, start_x, start_y, size_x, size_y, rotate,
659 pBitmap, mask_boxes[i], &bitmap_areas[i]);
660 context->m_pRenderer->Continue(nullptr);
661 }
662
663 // Begin rendering to the printer. Add flag to indicate the renderer should
664 // pause after each image mask.
665 pPage->ClearRenderContext();
666 owned_context = std::make_unique<CPDF_PageRenderContext>();
667 context = owned_context.get();
668 pPage->SetRenderContext(std::move(owned_context));
669 context->m_pDevice = std::make_unique<CPDF_WindowsRenderDevice>(
670 dc, render_data->GetPSFontTracker());
671 context->m_pOptions = std::make_unique<CPDF_RenderOptions>();
672 context->m_pOptions->GetOptions().bBreakForMasks = true;
673
674 CPDFSDK_RenderPageWithContext(context, pPage, start_x, start_y, size_x,
675 size_y, rotate, flags, /*color_scheme=*/nullptr,
676 /*need_to_restore=*/true,
677 /*pause=*/nullptr);
678
679 // Render masks
680 for (size_t i = 0; i < mask_boxes.size(); i++) {
681 // Render the bitmap for the mask and free the bitmap.
682 if (bitmaps[i]) { // will be null if mask has zero area
683 RenderBitmap(context->m_pDevice.get(), std::move(bitmaps[i]),
684 bitmap_areas[i]);
685 }
686 // Render the next portion of page.
687 context->m_pRenderer->Continue(nullptr);
688 }
689}
690#endif // BUILDFLAG(IS_WIN)
691
693 FPDF_PAGE page,
694 int start_x,
695 int start_y,
696 int size_x,
697 int size_y,
698 int rotate,
699 int flags) {
700 CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
701 if (!pPage) {
702 return;
703 }
704
705 RetainPtr<CFX_DIBitmap> pBitmap(CFXDIBitmapFromFPDFBitmap(bitmap));
706 if (!pBitmap) {
707 return;
708 }
709 CHECK(!pBitmap->IsPremultiplied());
710
711 auto owned_context = std::make_unique<CPDF_PageRenderContext>();
712 CPDF_PageRenderContext* context = owned_context.get();
713 CPDF_Page::RenderContextClearer clearer(pPage);
714 pPage->SetRenderContext(std::move(owned_context));
715
716#if defined(PDF_USE_SKIA)
717 CFX_DIBitmap::ScopedPremultiplier scoped_premultiplier(
718 pBitmap, CFX_DefaultRenderDevice::UseSkiaRenderer());
719#endif
720 auto device = std::make_unique<CFX_DefaultRenderDevice>();
721 device->AttachWithRgbByteOrder(std::move(pBitmap),
722 !!(flags & FPDF_REVERSE_BYTE_ORDER));
723 context->m_pDevice = std::move(device);
724
725 CPDFSDK_RenderPageWithContext(context, pPage, start_x, start_y, size_x,
726 size_y, rotate, flags, /*color_scheme=*/nullptr,
727 /*need_to_restore=*/true,
728 /*pause=*/nullptr);
729}
730
733 FPDF_PAGE page,
734 const FS_MATRIX* matrix,
735 const FS_RECTF* clipping,
736 int flags) {
737 CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
738 if (!pPage) {
739 return;
740 }
741
742 RetainPtr<CFX_DIBitmap> pBitmap(CFXDIBitmapFromFPDFBitmap(bitmap));
743 if (!pBitmap) {
744 return;
745 }
746 CHECK(!pBitmap->IsPremultiplied());
747
748 auto owned_context = std::make_unique<CPDF_PageRenderContext>();
749 CPDF_PageRenderContext* context = owned_context.get();
750 CPDF_Page::RenderContextClearer clearer(pPage);
751 pPage->SetRenderContext(std::move(owned_context));
752
753#if defined(PDF_USE_SKIA)
754 CFX_DIBitmap::ScopedPremultiplier scoped_premultiplier(
755 pBitmap, CFX_DefaultRenderDevice::UseSkiaRenderer());
756#endif
757 auto device = std::make_unique<CFX_DefaultRenderDevice>();
758 device->AttachWithRgbByteOrder(std::move(pBitmap),
759 !!(flags & FPDF_REVERSE_BYTE_ORDER));
760 context->m_pDevice = std::move(device);
761
762 CFX_FloatRect clipping_rect;
763 if (clipping)
764 clipping_rect = CFXFloatRectFromFSRectF(*clipping);
765 FX_RECT clip_rect = clipping_rect.ToFxRect();
766
767 const FX_RECT rect(0, 0, pPage->GetPageWidth(), pPage->GetPageHeight());
768 CFX_Matrix transform_matrix = pPage->GetDisplayMatrix(rect, 0);
769 if (matrix)
770 transform_matrix *= CFXMatrixFromFSMatrix(*matrix);
771 CPDFSDK_RenderPage(context, pPage, transform_matrix, clip_rect, flags,
772 /*color_scheme=*/nullptr);
773}
774
775#if defined(PDF_USE_SKIA)
776FPDF_EXPORT void FPDF_CALLCONV FPDF_RenderPageSkia(FPDF_SKIA_CANVAS canvas,
777 FPDF_PAGE page,
778 int size_x,
779 int size_y) {
780 SkCanvas* sk_canvas = SkCanvasFromFPDFSkiaCanvas(canvas);
781 if (!sk_canvas) {
782 return;
783 }
784
785 CPDF_Page* cpdf_page = CPDFPageFromFPDFPage(page);
786 if (!cpdf_page) {
787 return;
788 }
789
790 auto owned_context = std::make_unique<CPDF_PageRenderContext>();
791 CPDF_PageRenderContext* context = owned_context.get();
792 CPDF_Page::RenderContextClearer clearer(cpdf_page);
793 cpdf_page->SetRenderContext(std::move(owned_context));
794
795 auto device = std::make_unique<CFX_DefaultRenderDevice>();
796 if (!device->AttachCanvas(*sk_canvas)) {
797 return;
798 }
799 context->m_pDevice = std::move(device);
800
801 CPDFSDK_RenderPageWithContext(context, cpdf_page, 0, 0, size_x, size_y, 0, 0,
802 /*color_scheme=*/nullptr,
803 /*need_to_restore=*/true, /*pause=*/nullptr);
804}
805#endif // defined(PDF_USE_SKIA)
806
808 if (!page)
809 return;
810
811 // Take it back across the API and hold for duration of this function.
812 RetainPtr<IPDF_Page> pPage;
813 pPage.Unleak(IPDFPageFromFPDFPage(page));
814
815 if (pPage->AsXFAPage())
816 return;
817
818 // This will delete the PageView object corresponding to |pPage|. We must
819 // cleanup the PageView before releasing the reference on |pPage| as it will
820 // attempt to reset the PageView during destruction.
821 pPage->AsPDFPage()->ClearView();
822}
823
824FPDF_EXPORT void FPDF_CALLCONV FPDF_CloseDocument(FPDF_DOCUMENT document) {
825 // Take it back across the API and throw it away,
826 std::unique_ptr<CPDF_Document>(CPDFDocumentFromFPDFDocument(document));
827}
828
832
834 int start_x,
835 int start_y,
836 int size_x,
837 int size_y,
838 int rotate,
839 int device_x,
840 int device_y,
841 double* page_x,
842 double* page_y) {
843 if (!page || !page_x || !page_y)
844 return false;
845
847 const FX_RECT rect(start_x, start_y, start_x + size_x, start_y + size_y);
848 std::optional<CFX_PointF> pos =
849 pPage->DeviceToPage(rect, rotate, CFX_PointF(device_x, device_y));
850 if (!pos.has_value())
851 return false;
852
853 *page_x = pos->x;
854 *page_y = pos->y;
855 return true;
856}
857
859 int start_x,
860 int start_y,
861 int size_x,
862 int size_y,
863 int rotate,
864 double page_x,
865 double page_y,
866 int* device_x,
867 int* device_y) {
868 if (!page || !device_x || !device_y)
869 return false;
870
872 const FX_RECT rect(start_x, start_y, start_x + size_x, start_y + size_y);
873 CFX_PointF page_point(static_cast<float>(page_x), static_cast<float>(page_y));
874 std::optional<CFX_PointF> pos = pPage->PageToDevice(rect, rotate, page_point);
875 if (!pos.has_value())
876 return false;
877
878 *device_x = FXSYS_roundf(pos->x);
879 *device_y = FXSYS_roundf(pos->y);
880 return true;
881}
882
884 int height,
885 int alpha) {
886 auto pBitmap = pdfium::MakeRetain<CFX_DIBitmap>();
887 if (!pBitmap->Create(width, height,
889 return nullptr;
890 }
891
892 CHECK(!pBitmap->IsPremultiplied());
893
894 // Caller takes ownership.
895 return FPDFBitmapFromCFXDIBitmap(pBitmap.Leak());
896}
897
899 int height,
900 int format,
901 void* first_scan,
902 int stride) {
904 if (fx_format == FXDIB_Format::kInvalid) {
905 return nullptr;
906 }
907
908 // Ensure external memory is good at least for the duration of this call.
909 UnownedPtr<uint8_t> pChecker(static_cast<uint8_t*>(first_scan));
910 auto pBitmap = pdfium::MakeRetain<CFX_DIBitmap>();
911 if (!pBitmap->Create(width, height, fx_format, pChecker, stride)) {
912 return nullptr;
913 }
914
915 CHECK(!pBitmap->IsPremultiplied());
916
917 // Caller takes ownership.
918 return FPDFBitmapFromCFXDIBitmap(pBitmap.Leak());
919}
920
922 RetainPtr<CFX_DIBitmap> pBitmap(CFXDIBitmapFromFPDFBitmap(bitmap));
923 if (!pBitmap) {
924 return FPDFBitmap_Unknown;
925 }
926
927 switch (pBitmap->GetFormat()) {
930 return FPDFBitmap_Gray;
932 return FPDFBitmap_BGR;
934 return FPDFBitmap_BGRx;
936 return FPDFBitmap_BGRA;
937 default:
938 return FPDFBitmap_Unknown;
939 }
940}
941
942FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFBitmap_FillRect(FPDF_BITMAP bitmap,
943 int left,
944 int top,
945 int width,
946 int height,
947 FPDF_DWORD color) {
948 RetainPtr<CFX_DIBitmap> pBitmap(CFXDIBitmapFromFPDFBitmap(bitmap));
949 if (!pBitmap) {
950 return false;
951 }
952 CHECK(!pBitmap->IsPremultiplied());
953
954 FX_SAFE_INT32 right = left;
955 right += width;
956 if (!right.IsValid()) {
957 return false;
958 }
959
960 FX_SAFE_INT32 bottom = top;
961 bottom += height;
962 if (!bottom.IsValid()) {
963 return false;
964 }
965
966 FX_RECT fill_rect(left, top, right.ValueOrDie(), bottom.ValueOrDie());
967
968 if (!pBitmap->IsAlphaFormat()) {
969 color |= 0xFF000000;
970 }
971
972 // Let CFX_DefaultRenderDevice handle the 8-bit case.
973 const int bpp = pBitmap->GetBPP();
974 if (bpp == 8) {
975 CFX_DefaultRenderDevice device;
976 device.Attach(std::move(pBitmap));
977 return device.FillRect(fill_rect, static_cast<uint32_t>(color));
978 }
979
980 // Handle filling 24/32-bit bitmaps directly without CFX_DefaultRenderDevice.
981 // When CFX_DefaultRenderDevice is using Skia, this avoids extra work to
982 // change `pBitmap` to be premultiplied and back, or extra work to change
983 // `pBitmap` to 32 BPP and back.
984 fill_rect.Intersect(FX_RECT(0, 0, pBitmap->GetWidth(), pBitmap->GetHeight()));
985 if (fill_rect.IsEmpty()) {
986 // CFX_DefaultRenderDevice treats this as success. Match that.
987 return true;
988 }
989
990 const int row_end = fill_rect.top + fill_rect.Height();
991 if (bpp == 32) {
992 for (int row = fill_rect.top; row < row_end; ++row) {
993 auto span32 = pBitmap->GetWritableScanlineAs<uint32_t>(row).subspan(
994 fill_rect.left, fill_rect.Width());
995 fxcrt::Fill(span32, static_cast<uint32_t>(color));
996 }
997 return true;
998 }
999
1000 CHECK_EQ(bpp, 24);
1001 const FX_BGR_STRUCT<uint8_t> bgr = {.blue = FXARGB_B(color),
1002 .green = FXARGB_G(color),
1003 .red = FXARGB_R(color)};
1004 for (int row = fill_rect.top; row < row_end; ++row) {
1005 auto bgr_span =
1006 pBitmap->GetWritableScanlineAs<FX_BGR_STRUCT<uint8_t>>(row).subspan(
1007 fill_rect.left, fill_rect.Width());
1008 fxcrt::Fill(bgr_span, bgr);
1009 }
1010 return true;
1011}
1012
1014 RetainPtr<CFX_DIBitmap> pBitmap(CFXDIBitmapFromFPDFBitmap(bitmap));
1015 return pBitmap ? pBitmap->GetWritableBuffer().data() : nullptr;
1016}
1017
1019 RetainPtr<CFX_DIBitmap> pBitmap(CFXDIBitmapFromFPDFBitmap(bitmap));
1020 return pBitmap ? pBitmap->GetWidth() : 0;
1021}
1022
1024 RetainPtr<CFX_DIBitmap> pBitmap(CFXDIBitmapFromFPDFBitmap(bitmap));
1025 return pBitmap ? pBitmap->GetHeight() : 0;
1026}
1027
1029 RetainPtr<CFX_DIBitmap> pBitmap(CFXDIBitmapFromFPDFBitmap(bitmap));
1030 return pBitmap ? pBitmap->GetPitch() : 0;
1031}
1032
1034 RetainPtr<CFX_DIBitmap> destroyer;
1035 destroyer.Unleak(CFXDIBitmapFromFPDFBitmap(bitmap));
1036}
1037
1038FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
1039FPDF_GetPageSizeByIndexF(FPDF_DOCUMENT document,
1040 int page_index,
1041 FS_SIZEF* size) {
1042 if (!size)
1043 return false;
1044
1045 auto* pDoc = CPDFDocumentFromFPDFDocument(document);
1046 if (!pDoc)
1047 return false;
1048
1049#ifdef PDF_ENABLE_XFA
1050 if (page_index < 0 || page_index >= FPDF_GetPageCount(document))
1051 return false;
1052
1053 auto* pContext = static_cast<CPDFXFA_Context*>(pDoc->GetExtension());
1054 if (pContext) {
1055 RetainPtr<CPDFXFA_Page> pPage = pContext->GetOrCreateXFAPage(page_index);
1056 if (!pPage)
1057 return false;
1058
1059 size->width = pPage->GetPageWidth();
1060 size->height = pPage->GetPageHeight();
1061 return true;
1062 }
1063#endif // PDF_ENABLE_XFA
1064
1065 RetainPtr<CPDF_Dictionary> pDict = pDoc->GetMutablePageDictionary(page_index);
1066 if (!pDict)
1067 return false;
1068
1069 auto page = pdfium::MakeRetain<CPDF_Page>(pDoc, std::move(pDict));
1070 page->AddPageImageCache();
1071 size->width = page->GetPageWidth();
1072 size->height = page->GetPageHeight();
1073 return true;
1074}
1075
1077 int page_index,
1078 double* width,
1079 double* height) {
1080 if (!width || !height)
1081 return false;
1082
1083 FS_SIZEF size;
1084 if (!FPDF_GetPageSizeByIndexF(document, page_index, &size))
1085 return false;
1086
1087 *width = size.width;
1088 *height = size.height;
1089 return true;
1090}
1091
1092FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
1093FPDF_VIEWERREF_GetPrintScaling(FPDF_DOCUMENT document) {
1094 const CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
1095 if (!pDoc)
1096 return true;
1097 CPDF_ViewerPreferences viewRef(pDoc);
1098 return viewRef.PrintScaling();
1099}
1100
1102FPDF_VIEWERREF_GetNumCopies(FPDF_DOCUMENT document) {
1103 const CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
1104 if (!pDoc)
1105 return 1;
1106 CPDF_ViewerPreferences viewRef(pDoc);
1107 return viewRef.NumCopies();
1108}
1109
1110FPDF_EXPORT FPDF_PAGERANGE FPDF_CALLCONV
1111FPDF_VIEWERREF_GetPrintPageRange(FPDF_DOCUMENT document) {
1112 const CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
1113 if (!pDoc)
1114 return nullptr;
1115 CPDF_ViewerPreferences viewRef(pDoc);
1116
1117 // Unretained reference in public API. NOLINTNEXTLINE
1118 return FPDFPageRangeFromCPDFArray(viewRef.PrintPageRange());
1119}
1120
1122FPDF_VIEWERREF_GetPrintPageRangeCount(FPDF_PAGERANGE pagerange) {
1123 const CPDF_Array* pArray = CPDFArrayFromFPDFPageRange(pagerange);
1124 return pArray ? pArray->size() : 0;
1125}
1126
1129 size_t index) {
1130 const CPDF_Array* pArray = CPDFArrayFromFPDFPageRange(pagerange);
1131 if (!pArray || index >= pArray->size())
1132 return -1;
1133 return pArray->GetIntegerAt(index);
1134}
1135
1136FPDF_EXPORT FPDF_DUPLEXTYPE FPDF_CALLCONV
1137FPDF_VIEWERREF_GetDuplex(FPDF_DOCUMENT document) {
1138 const CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
1139 if (!pDoc)
1140 return DuplexUndefined;
1141 CPDF_ViewerPreferences viewRef(pDoc);
1142 ByteString duplex = viewRef.Duplex();
1143 if ("Simplex" == duplex)
1144 return Simplex;
1145 if ("DuplexFlipShortEdge" == duplex)
1146 return DuplexFlipShortEdge;
1147 if ("DuplexFlipLongEdge" == duplex)
1148 return DuplexFlipLongEdge;
1149 return DuplexUndefined;
1150}
1151
1152FPDF_EXPORT unsigned long FPDF_CALLCONV
1153FPDF_VIEWERREF_GetName(FPDF_DOCUMENT document,
1154 FPDF_BYTESTRING key,
1155 char* buffer,
1156 unsigned long length) {
1157 const CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
1158 if (!pDoc)
1159 return 0;
1160
1161 CPDF_ViewerPreferences viewRef(pDoc);
1162 std::optional<ByteString> bsVal = viewRef.GenericName(key);
1163 if (!bsVal.has_value()) {
1164 return 0;
1165 }
1166 // SAFETY: required from caller.
1167 return NulTerminateMaybeCopyAndReturnLength(
1168 bsVal.value(), UNSAFE_BUFFERS(SpanFromFPDFApiArgs(buffer, length)));
1169}
1170
1171FPDF_EXPORT FPDF_DWORD FPDF_CALLCONV
1172FPDF_CountNamedDests(FPDF_DOCUMENT document) {
1174 if (!pDoc)
1175 return 0;
1176
1177 const CPDF_Dictionary* pRoot = pDoc->GetRoot();
1178 if (!pRoot)
1179 return 0;
1180
1181 auto name_tree = CPDF_NameTree::Create(pDoc, "Dests");
1182 FX_SAFE_UINT32 count = name_tree ? name_tree->GetCount() : 0;
1183 RetainPtr<const CPDF_Dictionary> pOldStyleDests = pRoot->GetDictFor("Dests");
1184 if (pOldStyleDests)
1185 count += pOldStyleDests->size();
1186 return count.ValueOrDefault(0);
1187}
1188
1189FPDF_EXPORT FPDF_DEST FPDF_CALLCONV
1190FPDF_GetNamedDestByName(FPDF_DOCUMENT document, FPDF_BYTESTRING name) {
1191 if (!name || name[0] == 0)
1192 return nullptr;
1193
1195 if (!pDoc)
1196 return nullptr;
1197
1198 ByteString dest_name(name);
1199
1200 // TODO(tsepez): murky ownership, should caller get a reference?
1201 // Unretained reference in public API. NOLINTNEXTLINE
1202 return FPDFDestFromCPDFArray(CPDF_NameTree::LookupNamedDest(pDoc, dest_name));
1203}
1204
1205#ifdef PDF_ENABLE_V8
1206FPDF_EXPORT const char* FPDF_CALLCONV FPDF_GetRecommendedV8Flags() {
1207 // Use interpreted JS only to avoid RWX pages in our address space. Also,
1208 // --jitless implies --no-expose-wasm, which reduce exposure since no PDF
1209 // should contain web assembly.
1210 return "--jitless";
1211}
1212
1213FPDF_EXPORT void* FPDF_CALLCONV FPDF_GetArrayBufferAllocatorSharedInstance() {
1214 // Deliberately leaked. This allocator is used outside of the library
1215 // initialization / destruction lifecycle, and the caller does not take
1216 // ownership of the object. Thus there is no existing way to delete this.
1217 static auto* s_allocator = new CFX_V8ArrayBufferAllocator();
1218 return s_allocator;
1219}
1220#endif // PDF_ENABLE_V8
1221
1222#ifdef PDF_ENABLE_XFA
1223FPDF_EXPORT FPDF_RESULT FPDF_CALLCONV FPDF_BStr_Init(FPDF_BSTR* bstr) {
1224 if (!bstr)
1225 return -1;
1226
1227 bstr->str = nullptr;
1228 bstr->len = 0;
1229 return 0;
1230}
1231
1232FPDF_EXPORT FPDF_RESULT FPDF_CALLCONV FPDF_BStr_Set(FPDF_BSTR* bstr,
1233 const char* cstr,
1234 int length) {
1235 if (!bstr || !cstr)
1236 return -1;
1237
1238 if (length == -1)
1239 length = pdfium::checked_cast<int>(strlen(cstr));
1240
1241 if (length == 0) {
1242 FPDF_BStr_Clear(bstr);
1243 return 0;
1244 }
1245
1246 if (!bstr->str) {
1247 bstr->str = FX_Alloc(char, length + 1);
1248 } else if (bstr->len < length) {
1249 bstr->str = FX_Realloc(char, bstr->str, length + 1);
1250 }
1251
1252 // SAFETY: only alloc/realloc is performed above and will ensure at least
1253 // length + 1 bytes are available.
1254 UNSAFE_BUFFERS({
1255 bstr->str[length] = 0;
1256 FXSYS_memcpy(bstr->str, cstr, length);
1257 });
1258 bstr->len = length;
1259 return 0;
1260}
1261
1262FPDF_EXPORT FPDF_RESULT FPDF_CALLCONV FPDF_BStr_Clear(FPDF_BSTR* bstr) {
1263 if (!bstr)
1264 return -1;
1265
1266 if (bstr->str) {
1267 FX_Free(bstr->str);
1268 bstr->str = nullptr;
1269 }
1270 bstr->len = 0;
1271 return 0;
1272}
1273#endif // PDF_ENABLE_XFA
1274
1275FPDF_EXPORT FPDF_DEST FPDF_CALLCONV FPDF_GetNamedDest(FPDF_DOCUMENT document,
1276 int index,
1277 void* buffer,
1278 long* buflen) {
1279 if (!buffer)
1280 *buflen = 0;
1281
1282 if (index < 0)
1283 return nullptr;
1284
1286 if (!pDoc)
1287 return nullptr;
1288
1289 const CPDF_Dictionary* pRoot = pDoc->GetRoot();
1290 if (!pRoot)
1291 return nullptr;
1292
1293 auto name_tree = CPDF_NameTree::Create(pDoc, "Dests");
1294 size_t name_tree_count = name_tree ? name_tree->GetCount() : 0;
1295 RetainPtr<const CPDF_Object> pDestObj;
1296 WideString wsName;
1297 if (static_cast<size_t>(index) >= name_tree_count) {
1298 // If |index| is out of bounds, then try to retrieve the Nth old style named
1299 // destination. Where N is 0-indexed, with N = index - name_tree_count.
1300 RetainPtr<const CPDF_Dictionary> pDest = pRoot->GetDictFor("Dests");
1301 if (!pDest)
1302 return nullptr;
1303
1304 FX_SAFE_INT32 checked_count = name_tree_count;
1305 checked_count += pDest->size();
1306 if (!checked_count.IsValid() || index >= checked_count.ValueOrDie())
1307 return nullptr;
1308
1309 index -= name_tree_count;
1310 int i = 0;
1311 ByteStringView bsName;
1312 CPDF_DictionaryLocker locker(pDest);
1313 for (const auto& it : locker) {
1314 bsName = it.first.AsStringView();
1315 pDestObj = it.second;
1316 if (i == index)
1317 break;
1318 i++;
1319 }
1320 wsName = PDF_DecodeText(bsName.unsigned_span());
1321 } else {
1322 pDestObj = name_tree->LookupValueAndName(index, &wsName);
1323 }
1324 if (!pDestObj)
1325 return nullptr;
1326 if (const CPDF_Dictionary* pDict = pDestObj->AsDictionary()) {
1327 pDestObj = pDict->GetArrayFor("D");
1328 if (!pDestObj)
1329 return nullptr;
1330 }
1331 if (!pDestObj->IsArray())
1332 return nullptr;
1333
1334 ByteString utf16Name = wsName.ToUTF16LE();
1335 int len = pdfium::checked_cast<int>(utf16Name.GetLength());
1336 if (!buffer) {
1337 *buflen = len;
1338 } else if (len <= *buflen) {
1339 // SAFETY: required from caller.
1340 auto buffer_span =
1341 UNSAFE_BUFFERS(pdfium::make_span(static_cast<char*>(buffer), *buflen));
1342 fxcrt::Copy(utf16Name.span(), buffer_span);
1343 *buflen = len;
1344 } else {
1345 *buflen = -1;
1346 }
1347 return FPDFDestFromCPDFArray(pDestObj->AsArray());
1348}
1349
1352 if (!doc)
1353 return -1;
1354
1355 return fxcrt::CollectionSize<int>(
1356 GetXFAPackets(GetXFAEntryFromDocument(doc)));
1357}
1358
1359FPDF_EXPORT unsigned long FPDF_CALLCONV
1360FPDF_GetXFAPacketName(FPDF_DOCUMENT document,
1361 int index,
1362 void* buffer,
1363 unsigned long buflen) {
1365 if (!doc || index < 0)
1366 return 0;
1367
1368 std::vector<XFAPacket> xfa_packets =
1369 GetXFAPackets(GetXFAEntryFromDocument(doc));
1370 if (static_cast<size_t>(index) >= xfa_packets.size()) {
1371 return 0;
1372 }
1373 // SAFETY: required from caller.
1374 return NulTerminateMaybeCopyAndReturnLength(
1375 xfa_packets[index].name,
1376 UNSAFE_BUFFERS(SpanFromFPDFApiArgs(buffer, buflen)));
1377}
1378
1379FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
1380FPDF_GetXFAPacketContent(FPDF_DOCUMENT document,
1381 int index,
1382 void* buffer,
1383 unsigned long buflen,
1384 unsigned long* out_buflen) {
1386 if (!doc || index < 0 || !out_buflen)
1387 return false;
1388
1389 std::vector<XFAPacket> xfa_packets =
1390 GetXFAPackets(GetXFAEntryFromDocument(doc));
1391 if (static_cast<size_t>(index) >= xfa_packets.size())
1392 return false;
1393
1394 // SAFETY: caller ensures `buffer` points to at least `buflen` bytes.
1395 *out_buflen = DecodeStreamMaybeCopyAndReturnLength(
1396 xfa_packets[index].data,
1397 UNSAFE_BUFFERS(pdfium::make_span(static_cast<uint8_t*>(buffer),
1398 static_cast<size_t>(buflen))));
1399 return true;
1400}
1401
1402FPDF_EXPORT unsigned long FPDF_CALLCONV
1403FPDF_GetTrailerEnds(FPDF_DOCUMENT document,
1404 unsigned int* buffer,
1405 unsigned long length) {
1406 auto* doc = CPDFDocumentFromFPDFDocument(document);
1407 if (!doc)
1408 return 0;
1409
1410 // Start recording trailer ends.
1411 auto* parser = doc->GetParser();
1412 std::vector<unsigned int> trailer_ends = parser->GetTrailerEnds();
1413 const unsigned long trailer_ends_len =
1414 fxcrt::CollectionSize<unsigned long>(trailer_ends);
1415 if (buffer && length >= trailer_ends_len) {
1416 // SAFETY: required from caller.
1417 fxcrt::Copy(trailer_ends,
1418 UNSAFE_BUFFERS(pdfium::make_span(buffer, length)));
1419 }
1420
1421 return trailer_ends_len;
1422}
fxcrt::ByteString ByteString
Definition bytestring.h:180
#define CHECK_EQ(x, y)
Definition check_op.h:10
bool Attach(RetainPtr< CFX_DIBitmap > pBitmap)
CFX_FloatRect & operator=(const CFX_FloatRect &that)=default
FX_RECT ToFxRect() const
static void Create(const char **pUserFontPaths)
static void Destroy()
CFX_Matrix & operator*=(const CFX_Matrix &other)
bool FillRect(const FX_RECT &rect, uint32_t color)
static void DestroyGlobals()
Definition cfx_timer.cpp:27
static void InitializeGlobals()
Definition cfx_timer.cpp:21
std::vector< RetainPtr< CPDF_Object > >::const_iterator const_iterator
Definition cpdf_array.h:29
bool GetBooleanFor(const ByteString &key, bool bDefault) const
RetainPtr< const CPDF_Array > GetArrayFor(const ByteString &key) const
std::map< ByteString, RetainPtr< CPDF_Object >, std::less<> > DictMap
virtual int GetPageCount() const =0
bool has_valid_cross_reference_table() const
int GetPageCount() const
CPDF_Parser * GetParser() const
Extension * GetExtension() const
uint32_t GetUserPermissions(bool get_owner_perms) const
const CPDF_Dictionary * GetRoot() const
static RetainPtr< const CPDF_Array > LookupNamedDest(CPDF_Document *doc, const ByteString &name)
static void Destroy()
static void Create()
const CFX_FloatRect & GetBBox() const
RenderContextClearer(CPDF_Page *pPage)
float GetPageHeight() const override
Definition cpdf_page.cpp:59
float GetPageWidth() const override
Definition cpdf_page.cpp:55
CFX_Matrix GetDisplayMatrix(const FX_RECT &rect, int iRotate) const override
int GetFileVersion() const
RetainPtr< const CPDF_Array > PrintPageRange() const
CPDF_ViewerPreferences(const CPDF_Document *pDoc)
static RetainPtr< IFX_SeekableReadStream > CreateFromFilename(const char *filename)
Definition fx_stream.cpp:68
static void Initialize(unsigned int slot, void *isolate, void *platform)
static void Destroy()
virtual float GetPageWidth() const =0
virtual float GetPageHeight() const =0
ByteString(const char *ptr)
ByteString ToUTF16LE() const
#define UNSAFE_BUFFERS(...)
const CPDF_Array * CPDFArrayFromFPDFPageRange(FPDF_PAGERANGE range)
IPDF_Page * IPDFPageFromFPDFPage(FPDF_PAGE page)
void ProcessParseError(CPDF_Parser::Error err)
CFX_DIBitmap * CFXDIBitmapFromFPDFBitmap(FPDF_BITMAP bitmap)
FXDIB_Format FXDIBFormatFromFPDFFormat(int format)
void SetPDFSandboxPolicy(FPDF_DWORD policy, FPDF_BOOL enable)
CFX_FloatRect CFXFloatRectFromFSRectF(const FS_RECTF &rect)
CPDF_Page * CPDFPageFromFPDFPage(FPDF_PAGE page)
CPDF_Document * CPDFDocumentFromFPDFDocument(FPDF_DOCUMENT doc)
CFX_Matrix CFXMatrixFromFSMatrix(const FS_MATRIX &matrix)
void CPDFSDK_RenderPageWithContext(CPDF_PageRenderContext *pContext, CPDF_Page *pPage, int start_x, int start_y, int size_x, int size_y, int rotate, int flags, const FPDF_COLORSCHEME *color_scheme, bool need_to_restore, CPDFSDK_PauseAdapter *pause)
void CPDFSDK_RenderPage(CPDF_PageRenderContext *pContext, CPDF_Page *pPage, const CFX_Matrix &matrix, const FX_RECT &clipping_rect, int flags, const FPDF_COLORSCHEME *color_scheme)
#define FORMTYPE_NONE
#define FORMTYPE_XFA_FOREGROUND
#define FORMTYPE_XFA_FULL
FPDF_EXPORT int FPDF_CALLCONV FPDF_GetFormType(FPDF_DOCUMENT document)
FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_LoadXFA(FPDF_DOCUMENT document)
#define FORMTYPE_ACRO_FORM
FPDF_EXPORT FPDF_PAGE FPDF_CALLCONV FPDF_LoadPage(FPDF_DOCUMENT document, int page_index)
FPDF_EXPORT int FPDF_CALLCONV FPDF_GetPageCount(FPDF_DOCUMENT document)
FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetLastError()
FPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV FPDFBitmap_CreateEx(int width, int height, int format, void *first_scan, int stride)
FPDF_EXPORT void FPDF_CALLCONV FPDF_SetSandBoxPolicy(FPDF_DWORD policy, FPDF_BOOL enable)
FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_VIEWERREF_GetPrintScaling(FPDF_DOCUMENT document)
FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV 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)
FPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV FPDF_LoadCustomDocument(FPDF_FILEACCESS *pFileAccess, FPDF_BYTESTRING password)
FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV 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)
FPDF_EXPORT size_t FPDF_CALLCONV FPDF_VIEWERREF_GetPrintPageRangeCount(FPDF_PAGERANGE pagerange)
FPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV FPDF_LoadDocument(FPDF_STRING file_path, FPDF_BYTESTRING password)
FPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetHeight(FPDF_BITMAP bitmap)
FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_DocumentHasValidCrossReferenceTable(FPDF_DOCUMENT document)
FPDF_EXPORT void FPDF_CALLCONV FPDFBitmap_Destroy(FPDF_BITMAP bitmap)
FPDF_EXPORT FPDF_DUPLEXTYPE FPDF_CALLCONV FPDF_VIEWERREF_GetDuplex(FPDF_DOCUMENT document)
FPDF_EXPORT float FPDF_CALLCONV FPDF_GetPageHeightF(FPDF_PAGE page)
FPDF_EXPORT void FPDF_CALLCONV FPDF_DestroyLibrary()
FPDF_EXPORT int FPDF_CALLCONV FPDF_GetXFAPacketCount(FPDF_DOCUMENT document)
FPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV FPDFBitmap_Create(int width, int height, int alpha)
FPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetStride(FPDF_BITMAP bitmap)
FPDF_EXPORT FPDF_PAGERANGE FPDF_CALLCONV FPDF_VIEWERREF_GetPrintPageRange(FPDF_DOCUMENT document)
FPDF_EXPORT int FPDF_CALLCONV FPDF_GetPageSizeByIndex(FPDF_DOCUMENT document, int page_index, double *width, double *height)
FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetDocUserPermissions(FPDF_DOCUMENT document)
FPDF_EXPORT double FPDF_CALLCONV FPDF_GetPageWidth(FPDF_PAGE page)
FPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV FPDF_LoadMemDocument64(const void *data_buf, size_t size, FPDF_BYTESTRING password)
FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFBitmap_FillRect(FPDF_BITMAP bitmap, int left, int top, int width, int height, FPDF_DWORD color)
FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetDocPermissions(FPDF_DOCUMENT document)
FPDF_EXPORT void FPDF_CALLCONV FPDF_InitLibrary()
FPDF_EXPORT FPDF_DEST FPDF_CALLCONV FPDF_GetNamedDest(FPDF_DOCUMENT document, int index, void *buffer, long *buflen)
FPDF_EXPORT FPDF_DEST FPDF_CALLCONV FPDF_GetNamedDestByName(FPDF_DOCUMENT document, FPDF_BYTESTRING name)
FPDF_EXPORT void FPDF_CALLCONV FPDF_RenderPageBitmap(FPDF_BITMAP bitmap, FPDF_PAGE page, int start_x, int start_y, int size_x, int size_y, int rotate, int flags)
FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_GetFileVersion(FPDF_DOCUMENT doc, int *fileVersion)
FPDF_EXPORT void FPDF_CALLCONV FPDF_RenderPageBitmapWithMatrix(FPDF_BITMAP bitmap, FPDF_PAGE page, const FS_MATRIX *matrix, const FS_RECTF *clipping, int flags)
FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_GetPageBoundingBox(FPDF_PAGE page, FS_RECTF *rect)
FPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetFormat(FPDF_BITMAP bitmap)
FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_VIEWERREF_GetName(FPDF_DOCUMENT document, FPDF_BYTESTRING key, char *buffer, unsigned long length)
FPDF_EXPORT void FPDF_CALLCONV FPDF_InitLibraryWithConfig(const FPDF_LIBRARY_CONFIG *config)
FPDF_EXPORT void *FPDF_CALLCONV FPDFBitmap_GetBuffer(FPDF_BITMAP bitmap)
FPDF_EXPORT FPDF_DWORD FPDF_CALLCONV FPDF_CountNamedDests(FPDF_DOCUMENT document)
FPDF_EXPORT void FPDF_CALLCONV FPDF_CloseDocument(FPDF_DOCUMENT document)
FPDF_EXPORT int FPDF_CALLCONV FPDF_VIEWERREF_GetPrintPageRangeElement(FPDF_PAGERANGE pagerange, size_t index)
FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_GetPageSizeByIndexF(FPDF_DOCUMENT document, int page_index, FS_SIZEF *size)
FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_GetXFAPacketContent(FPDF_DOCUMENT document, int index, void *buffer, unsigned long buflen, unsigned long *out_buflen)
FPDF_EXPORT int FPDF_CALLCONV FPDF_VIEWERREF_GetNumCopies(FPDF_DOCUMENT document)
FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetXFAPacketName(FPDF_DOCUMENT document, int index, void *buffer, unsigned long buflen)
FPDF_EXPORT double FPDF_CALLCONV FPDF_GetPageHeight(FPDF_PAGE page)
FPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetWidth(FPDF_BITMAP bitmap)
FPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV FPDF_LoadMemDocument(const void *data_buf, int size, FPDF_BYTESTRING password)
FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetTrailerEnds(FPDF_DOCUMENT document, unsigned int *buffer, unsigned long length)
FPDF_EXPORT float FPDF_CALLCONV FPDF_GetPageWidthF(FPDF_PAGE page)
FPDF_EXPORT void FPDF_CALLCONV FPDF_ClosePage(FPDF_PAGE page)
FPDF_EXPORT int FPDF_CALLCONV FPDF_GetSecurityHandlerRevision(FPDF_DOCUMENT document)
#define FPDFBitmap_BGR
Definition fpdfview.h:1086
#define FPDFBitmap_BGRx
Definition fpdfview.h:1088
#define FPDF_REVERSE_BYTE_ORDER
Definition fpdfview.h:817
#define FPDFBitmap_BGRA
Definition fpdfview.h:1090
#define FPDF_CALLCONV
Definition fpdfview.h:229
#define FPDFBitmap_Unknown
Definition fpdfview.h:1082
#define FPDF_EXPORT
Definition fpdfview.h:223
#define FPDFBitmap_Gray
Definition fpdfview.h:1084
CFX_PTemplate< float > CFX_PointF
#define FXARGB_B(argb)
Definition fx_dib.h:199
#define FXARGB_G(argb)
Definition fx_dib.h:198
#define FXARGB_R(argb)
Definition fx_dib.h:197
FXDIB_Format
Definition fx_dib.h:21
void FX_DestroyMemoryAllocators()
void FX_InitializeMemoryAllocators()
pdfium::CheckedNumeric< uint32_t > FX_SAFE_UINT32
pdfium::CheckedNumeric< int32_t > FX_SAFE_INT32
uint32_t FXSYS_GetLastError()
bool operator==(const char *lhs, const ByteString &rhs)
Definition bytestring.h:109
#define CHECK(cvref)
fxcrt::ByteStringView ByteStringView
int Height() const
int Width() const
int32_t top
int32_t left
void Intersect(const FX_RECT &src)
bool IsEmpty() const
constexpr FX_RECT(int l, int t, int r, int b)
fxcrt::WideString WideString
Definition widestring.h:207