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