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