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 "core/fpdfapi/cpdf_modulemgr.h" 14 #include "core/fpdfapi/cpdf_pagerendercontext.h" 15 #include "core/fpdfapi/page/cpdf_image.h" 16 #include "core/fpdfapi/page/cpdf_imageobject.h" 17 #include "core/fpdfapi/page/cpdf_page.h" 18 #include "core/fpdfapi/page/cpdf_pageobject.h" 19 #include "core/fpdfapi/page/cpdf_pathobject.h" 20 #include "core/fpdfapi/parser/cpdf_array.h" 21 #include "core/fpdfapi/parser/cpdf_dictionary.h" 22 #include "core/fpdfapi/parser/cpdf_document.h" 23 #include "core/fpdfapi/parser/fpdf_parser_decode.h" 24 #include "core/fpdfapi/render/cpdf_progressiverenderer.h" 25 #include "core/fpdfapi/render/cpdf_renderoptions.h" 26 #include "core/fpdfdoc/cpdf_annotlist.h" 27 #include "core/fpdfdoc/cpdf_nametree.h" 28 #include "core/fpdfdoc/cpdf_occontext.h" 29 #include "core/fpdfdoc/cpdf_viewerpreferences.h" 30 #include "core/fxcrt/fx_memory.h" 31 #include "core/fxcrt/fx_safe_types.h" 32 #include "core/fxcrt/fx_stream.h" 33 #include "core/fxge/cfx_defaultrenderdevice.h" 34 #include "core/fxge/cfx_gemodule.h" 35 #include "fpdfsdk/cpdfsdk_formfillenvironment.h" 36 #include "fpdfsdk/cpdfsdk_pageview.h" 37 #include "fpdfsdk/fsdk_define.h" 38 #include "fpdfsdk/fsdk_pauseadapter.h" 39 #include "fxjs/ijs_runtime.h" 40 #include "public/fpdf_edit.h" 41 #include "public/fpdf_ext.h" 42 #include "public/fpdf_formfill.h" 43 #include "public/fpdf_progressive.h" 44 #include "third_party/base/allocator/partition_allocator/partition_alloc.h" 45 #include "third_party/base/numerics/safe_conversions_impl.h" 46 #include "third_party/base/ptr_util.h" 47 48 #ifdef PDF_ENABLE_XFA 49 #include "fpdfsdk/fpdfxfa/cpdfxfa_context.h" 50 #include "fpdfsdk/fpdfxfa/cpdfxfa_page.h" 51 #include "fpdfsdk/fpdfxfa/cxfa_fwladaptertimermgr.h" 52 #include "fxbarcode/BC_Library.h" 53 #endif // PDF_ENABLE_XFA 54 55 #if _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_ 56 #include "core/fxge/cfx_windowsrenderdevice.h" 57 58 // These checks are here because core/ and public/ cannot depend on each other. 59 static_assert(WindowsPrintMode::kModeEmf == FPDF_PRINTMODE_EMF, 60 "WindowsPrintMode::kModeEmf value mismatch"); 61 static_assert(WindowsPrintMode::kModeTextOnly == FPDF_PRINTMODE_TEXTONLY, 62 "WindowsPrintMode::kModeTextOnly value mismatch"); 63 static_assert(WindowsPrintMode::kModePostScript2 == FPDF_PRINTMODE_POSTSCRIPT2, 64 "WindowsPrintMode::kModePostScript2 value mismatch"); 65 static_assert(WindowsPrintMode::kModePostScript3 == FPDF_PRINTMODE_POSTSCRIPT3, 66 "WindowsPrintMode::kModePostScript3 value mismatch"); 67 #endif 68 69 namespace { 70 71 bool g_bLibraryInitialized = false; 72 73 void RenderPageImpl(CPDF_PageRenderContext* pContext, 74 CPDF_Page* pPage, 75 const CFX_Matrix& matrix, 76 const FX_RECT& clipping_rect, 77 int flags, 78 bool bNeedToRestore, 79 IFSDK_PAUSE_Adapter* pause) { 80 if (!pContext->m_pOptions) 81 pContext->m_pOptions = pdfium::MakeUnique<CPDF_RenderOptions>(); 82 83 uint32_t option_flags = pContext->m_pOptions->GetFlags(); 84 if (flags & FPDF_LCD_TEXT) 85 option_flags |= RENDER_CLEARTYPE; 86 else 87 option_flags &= ~RENDER_CLEARTYPE; 88 89 if (flags & FPDF_NO_NATIVETEXT) 90 option_flags |= RENDER_NO_NATIVETEXT; 91 if (flags & FPDF_RENDER_LIMITEDIMAGECACHE) 92 option_flags |= RENDER_LIMITEDIMAGECACHE; 93 if (flags & FPDF_RENDER_FORCEHALFTONE) 94 option_flags |= RENDER_FORCE_HALFTONE; 95 #ifndef PDF_ENABLE_XFA 96 if (flags & FPDF_RENDER_NO_SMOOTHTEXT) 97 option_flags |= RENDER_NOTEXTSMOOTH; 98 if (flags & FPDF_RENDER_NO_SMOOTHIMAGE) 99 option_flags |= RENDER_NOIMAGESMOOTH; 100 if (flags & FPDF_RENDER_NO_SMOOTHPATH) 101 option_flags |= RENDER_NOPATHSMOOTH; 102 #endif // PDF_ENABLE_XFA 103 pContext->m_pOptions->SetFlags(option_flags); 104 105 // Grayscale output 106 if (flags & FPDF_GRAYSCALE) 107 pContext->m_pOptions->SetColorMode(CPDF_RenderOptions::kGray); 108 109 const CPDF_OCContext::UsageType usage = 110 (flags & FPDF_PRINTING) ? CPDF_OCContext::Print : CPDF_OCContext::View; 111 pContext->m_pOptions->SetOCContext( 112 pdfium::MakeRetain<CPDF_OCContext>(pPage->m_pDocument.Get(), usage)); 113 114 pContext->m_pDevice->SaveState(); 115 pContext->m_pDevice->SetClip_Rect(clipping_rect); 116 pContext->m_pContext = pdfium::MakeUnique<CPDF_RenderContext>(pPage); 117 pContext->m_pContext->AppendLayer(pPage, &matrix); 118 119 if (flags & FPDF_ANNOT) { 120 pContext->m_pAnnots = pdfium::MakeUnique<CPDF_AnnotList>(pPage); 121 bool bPrinting = pContext->m_pDevice->GetDeviceClass() != FXDC_DISPLAY; 122 pContext->m_pAnnots->DisplayAnnots(pPage, pContext->m_pContext.get(), 123 bPrinting, &matrix, false, nullptr); 124 } 125 126 pContext->m_pRenderer = pdfium::MakeUnique<CPDF_ProgressiveRenderer>( 127 pContext->m_pContext.get(), pContext->m_pDevice.get(), 128 pContext->m_pOptions.get()); 129 pContext->m_pRenderer->Start(pause); 130 if (bNeedToRestore) 131 pContext->m_pDevice->RestoreState(false); 132 } 133 134 class CPDF_CustomAccess final : public IFX_SeekableReadStream { 135 public: 136 template <typename T, typename... Args> 137 friend RetainPtr<T> pdfium::MakeRetain(Args&&... args); 138 139 // IFX_SeekableReadStream 140 FX_FILESIZE GetSize() override; 141 bool ReadBlock(void* buffer, FX_FILESIZE offset, size_t size) override; 142 143 private: 144 explicit CPDF_CustomAccess(FPDF_FILEACCESS* pFileAccess); 145 146 FPDF_FILEACCESS m_FileAccess; 147 }; 148 149 CPDF_CustomAccess::CPDF_CustomAccess(FPDF_FILEACCESS* pFileAccess) 150 : m_FileAccess(*pFileAccess) {} 151 152 FX_FILESIZE CPDF_CustomAccess::GetSize() { 153 return m_FileAccess.m_FileLen; 154 } 155 156 bool CPDF_CustomAccess::ReadBlock(void* buffer, 157 FX_FILESIZE offset, 158 size_t size) { 159 if (offset < 0) 160 return false; 161 162 FX_SAFE_FILESIZE newPos = pdfium::base::checked_cast<FX_FILESIZE>(size); 163 newPos += offset; 164 if (!newPos.IsValid() || 165 newPos.ValueOrDie() > static_cast<FX_FILESIZE>(m_FileAccess.m_FileLen)) { 166 return false; 167 } 168 return !!m_FileAccess.m_GetBlock(m_FileAccess.m_Param, offset, 169 static_cast<uint8_t*>(buffer), size); 170 } 171 172 #ifdef PDF_ENABLE_XFA 173 class FPDF_FileHandlerContext : public IFX_SeekableStream { 174 public: 175 template <typename T, typename... Args> 176 friend RetainPtr<T> pdfium::MakeRetain(Args&&... args); 177 178 ~FPDF_FileHandlerContext() override; 179 180 // IFX_SeekableStream: 181 FX_FILESIZE GetSize() override; 182 bool IsEOF() override; 183 FX_FILESIZE GetPosition() override; 184 bool ReadBlock(void* buffer, FX_FILESIZE offset, size_t size) override; 185 size_t ReadBlock(void* buffer, size_t size) override; 186 bool WriteBlock(const void* buffer, FX_FILESIZE offset, size_t size) override; 187 bool Flush() override; 188 189 void SetPosition(FX_FILESIZE pos) { m_nCurPos = pos; } 190 191 protected: 192 explicit FPDF_FileHandlerContext(FPDF_FILEHANDLER* pFS); 193 194 FPDF_FILEHANDLER* m_pFS; 195 FX_FILESIZE m_nCurPos; 196 }; 197 198 FPDF_FileHandlerContext::FPDF_FileHandlerContext(FPDF_FILEHANDLER* pFS) { 199 m_pFS = pFS; 200 m_nCurPos = 0; 201 } 202 203 FPDF_FileHandlerContext::~FPDF_FileHandlerContext() { 204 if (m_pFS && m_pFS->Release) 205 m_pFS->Release(m_pFS->clientData); 206 } 207 208 FX_FILESIZE FPDF_FileHandlerContext::GetSize() { 209 if (m_pFS && m_pFS->GetSize) 210 return (FX_FILESIZE)m_pFS->GetSize(m_pFS->clientData); 211 return 0; 212 } 213 214 bool FPDF_FileHandlerContext::IsEOF() { 215 return m_nCurPos >= GetSize(); 216 } 217 218 FX_FILESIZE FPDF_FileHandlerContext::GetPosition() { 219 return m_nCurPos; 220 } 221 222 bool FPDF_FileHandlerContext::ReadBlock(void* buffer, 223 FX_FILESIZE offset, 224 size_t size) { 225 if (!buffer || !size || !m_pFS->ReadBlock) 226 return false; 227 228 if (m_pFS->ReadBlock(m_pFS->clientData, (FPDF_DWORD)offset, buffer, 229 (FPDF_DWORD)size) == 0) { 230 m_nCurPos = offset + size; 231 return true; 232 } 233 return false; 234 } 235 236 size_t FPDF_FileHandlerContext::ReadBlock(void* buffer, size_t size) { 237 if (!buffer || !size || !m_pFS->ReadBlock) 238 return 0; 239 240 FX_FILESIZE nSize = GetSize(); 241 if (m_nCurPos >= nSize) 242 return 0; 243 FX_FILESIZE dwAvail = nSize - m_nCurPos; 244 if (dwAvail < (FX_FILESIZE)size) 245 size = static_cast<size_t>(dwAvail); 246 if (m_pFS->ReadBlock(m_pFS->clientData, (FPDF_DWORD)m_nCurPos, buffer, 247 (FPDF_DWORD)size) == 0) { 248 m_nCurPos += size; 249 return size; 250 } 251 252 return 0; 253 } 254 255 bool FPDF_FileHandlerContext::WriteBlock(const void* buffer, 256 FX_FILESIZE offset, 257 size_t size) { 258 if (!m_pFS || !m_pFS->WriteBlock) 259 return false; 260 261 if (m_pFS->WriteBlock(m_pFS->clientData, (FPDF_DWORD)offset, buffer, 262 (FPDF_DWORD)size) == 0) { 263 m_nCurPos = offset + size; 264 return true; 265 } 266 return false; 267 } 268 269 bool FPDF_FileHandlerContext::Flush() { 270 if (!m_pFS || !m_pFS->Flush) 271 return true; 272 273 return m_pFS->Flush(m_pFS->clientData) == 0; 274 } 275 #endif // PDF_ENABLE_XFA 276 277 FPDF_DOCUMENT LoadDocumentImpl( 278 const RetainPtr<IFX_SeekableReadStream>& pFileAccess, 279 FPDF_BYTESTRING password) { 280 if (!pFileAccess) { 281 ProcessParseError(CPDF_Parser::FILE_ERROR); 282 return nullptr; 283 } 284 285 auto pParser = pdfium::MakeUnique<CPDF_Parser>(); 286 pParser->SetPassword(password); 287 288 auto pDocument = pdfium::MakeUnique<CPDF_Document>(std::move(pParser)); 289 CPDF_Parser::Error error = 290 pDocument->GetParser()->StartParse(pFileAccess, pDocument.get()); 291 if (error != CPDF_Parser::SUCCESS) { 292 ProcessParseError(error); 293 return nullptr; 294 } 295 CheckUnSupportError(pDocument.get(), error); 296 return FPDFDocumentFromCPDFDocument(pDocument.release()); 297 } 298 299 } // namespace 300 301 UnderlyingDocumentType* UnderlyingFromFPDFDocument(FPDF_DOCUMENT doc) { 302 return static_cast<UnderlyingDocumentType*>(doc); 303 } 304 305 FPDF_DOCUMENT FPDFDocumentFromUnderlying(UnderlyingDocumentType* doc) { 306 return static_cast<FPDF_DOCUMENT>(doc); 307 } 308 309 UnderlyingPageType* UnderlyingFromFPDFPage(FPDF_PAGE page) { 310 return static_cast<UnderlyingPageType*>(page); 311 } 312 313 CPDF_Document* CPDFDocumentFromFPDFDocument(FPDF_DOCUMENT doc) { 314 #ifdef PDF_ENABLE_XFA 315 return doc ? UnderlyingFromFPDFDocument(doc)->GetPDFDoc() : nullptr; 316 #else // PDF_ENABLE_XFA 317 return UnderlyingFromFPDFDocument(doc); 318 #endif // PDF_ENABLE_XFA 319 } 320 321 FPDF_DOCUMENT FPDFDocumentFromCPDFDocument(CPDF_Document* doc) { 322 #ifdef PDF_ENABLE_XFA 323 return doc ? FPDFDocumentFromUnderlying( 324 new CPDFXFA_Context(pdfium::WrapUnique(doc))) 325 : nullptr; 326 #else // PDF_ENABLE_XFA 327 return FPDFDocumentFromUnderlying(doc); 328 #endif // PDF_ENABLE_XFA 329 } 330 331 CPDF_Page* CPDFPageFromFPDFPage(FPDF_PAGE page) { 332 #ifdef PDF_ENABLE_XFA 333 return page ? UnderlyingFromFPDFPage(page)->GetPDFPage() : nullptr; 334 #else // PDF_ENABLE_XFA 335 return UnderlyingFromFPDFPage(page); 336 #endif // PDF_ENABLE_XFA 337 } 338 339 CPDF_PathObject* CPDFPathObjectFromFPDFPageObject(FPDF_PAGEOBJECT page_object) { 340 auto* obj = CPDFPageObjectFromFPDFPageObject(page_object); 341 return obj ? obj->AsPath() : nullptr; 342 } 343 344 CPDF_PageObject* CPDFPageObjectFromFPDFPageObject(FPDF_PAGEOBJECT page_object) { 345 return static_cast<CPDF_PageObject*>(page_object); 346 } 347 348 CPDF_Object* CPDFObjectFromFPDFAttachment(FPDF_ATTACHMENT attachment) { 349 return static_cast<CPDF_Object*>(attachment); 350 } 351 352 ByteString CFXByteStringFromFPDFWideString(FPDF_WIDESTRING wide_string) { 353 return WideString::FromUTF16LE(wide_string, 354 WideString::WStringLength(wide_string)) 355 .UTF8Encode(); 356 } 357 358 CFX_DIBitmap* CFXBitmapFromFPDFBitmap(FPDF_BITMAP bitmap) { 359 return static_cast<CFX_DIBitmap*>(bitmap); 360 } 361 362 CFX_FloatRect CFXFloatRectFromFSRECTF(const FS_RECTF& rect) { 363 return CFX_FloatRect(rect.left, rect.bottom, rect.right, rect.top); 364 } 365 366 void FSRECTFFromCFXFloatRect(const CFX_FloatRect& rect, FS_RECTF* out_rect) { 367 out_rect->left = rect.left; 368 out_rect->top = rect.top; 369 out_rect->right = rect.right; 370 out_rect->bottom = rect.bottom; 371 } 372 373 const FX_PATHPOINT* FXPathPointFromFPDFPathSegment(FPDF_PATHSEGMENT segment) { 374 return static_cast<const FX_PATHPOINT*>(segment); 375 } 376 377 unsigned long Utf16EncodeMaybeCopyAndReturnLength(const WideString& text, 378 void* buffer, 379 unsigned long buflen) { 380 ByteString encoded_text = text.UTF16LE_Encode(); 381 unsigned long len = encoded_text.GetLength(); 382 if (buffer && len <= buflen) 383 memcpy(buffer, encoded_text.c_str(), len); 384 return len; 385 } 386 387 unsigned long DecodeStreamMaybeCopyAndReturnLength(const CPDF_Stream* stream, 388 void* buffer, 389 unsigned long buflen) { 390 ASSERT(stream); 391 uint8_t* data = stream->GetRawData(); 392 uint32_t len = stream->GetRawSize(); 393 CPDF_Dictionary* dict = stream->GetDict(); 394 CPDF_Object* decoder = dict ? dict->GetDirectObjectFor("Filter") : nullptr; 395 if (decoder && (decoder->IsArray() || decoder->IsName())) { 396 // Decode the stream if one or more stream filters are specified. 397 uint8_t* decoded_data = nullptr; 398 uint32_t decoded_len = 0; 399 ByteString dummy_last_decoder; 400 CPDF_Dictionary* dummy_last_param; 401 if (PDF_DataDecode(data, len, dict, dict->GetIntegerFor("DL"), false, 402 &decoded_data, &decoded_len, &dummy_last_decoder, 403 &dummy_last_param)) { 404 if (buffer && buflen >= decoded_len) 405 memcpy(buffer, decoded_data, decoded_len); 406 407 // Free the buffer for the decoded data if it was allocated by 408 // PDF_DataDecode(). Note that for images with a single image-specific 409 // filter, |decoded_data| is directly assigned to be |data|, so 410 // |decoded_data| does not need to be freed. 411 if (decoded_data != data) 412 FX_Free(decoded_data); 413 414 return decoded_len; 415 } 416 } 417 // Copy the raw data and return its length if there is no valid filter 418 // specified or if decoding failed. 419 if (buffer && buflen >= len) 420 memcpy(buffer, data, len); 421 422 return len; 423 } 424 425 RetainPtr<IFX_SeekableReadStream> MakeSeekableReadStream( 426 FPDF_FILEACCESS* pFileAccess) { 427 return pdfium::MakeRetain<CPDF_CustomAccess>(pFileAccess); 428 } 429 430 #ifdef PDF_ENABLE_XFA 431 RetainPtr<IFX_SeekableStream> MakeSeekableStream( 432 FPDF_FILEHANDLER* pFilehandler) { 433 return pdfium::MakeRetain<FPDF_FileHandlerContext>(pFilehandler); 434 } 435 #endif // PDF_ENABLE_XFA 436 437 // 0 bit: FPDF_POLICY_MACHINETIME_ACCESS 438 static uint32_t foxit_sandbox_policy = 0xFFFFFFFF; 439 440 void FSDK_SetSandBoxPolicy(FPDF_DWORD policy, FPDF_BOOL enable) { 441 switch (policy) { 442 case FPDF_POLICY_MACHINETIME_ACCESS: { 443 if (enable) 444 foxit_sandbox_policy |= 0x01; 445 else 446 foxit_sandbox_policy &= 0xFFFFFFFE; 447 } break; 448 default: 449 break; 450 } 451 } 452 453 FPDF_BOOL FSDK_IsSandBoxPolicyEnabled(FPDF_DWORD policy) { 454 switch (policy) { 455 case FPDF_POLICY_MACHINETIME_ACCESS: 456 return !!(foxit_sandbox_policy & 0x01); 457 default: 458 return false; 459 } 460 } 461 462 FPDF_EXPORT void FPDF_CALLCONV FPDF_InitLibrary() { 463 FPDF_InitLibraryWithConfig(nullptr); 464 } 465 466 FPDF_EXPORT void FPDF_CALLCONV 467 FPDF_InitLibraryWithConfig(const FPDF_LIBRARY_CONFIG* cfg) { 468 if (g_bLibraryInitialized) 469 return; 470 471 FXMEM_InitializePartitionAlloc(); 472 473 CFX_GEModule* pModule = CFX_GEModule::Get(); 474 pModule->Init(cfg ? cfg->m_pUserFontPaths : nullptr); 475 476 CPDF_ModuleMgr* pModuleMgr = CPDF_ModuleMgr::Get(); 477 pModuleMgr->Init(); 478 479 #ifdef PDF_ENABLE_XFA 480 BC_Library_Init(); 481 #endif // PDF_ENABLE_XFA 482 if (cfg && cfg->version >= 2) 483 IJS_Runtime::Initialize(cfg->m_v8EmbedderSlot, cfg->m_pIsolate); 484 485 g_bLibraryInitialized = true; 486 } 487 488 FPDF_EXPORT void FPDF_CALLCONV FPDF_DestroyLibrary() { 489 if (!g_bLibraryInitialized) 490 return; 491 492 #ifdef PDF_ENABLE_XFA 493 BC_Library_Destroy(); 494 #endif // PDF_ENABLE_XFA 495 496 CPDF_ModuleMgr::Destroy(); 497 CFX_GEModule::Destroy(); 498 499 IJS_Runtime::Destroy(); 500 501 g_bLibraryInitialized = false; 502 } 503 504 #ifndef _WIN32 505 int g_LastError; 506 void SetLastError(int err) { 507 g_LastError = err; 508 } 509 510 int GetLastError() { 511 return g_LastError; 512 } 513 #endif // _WIN32 514 515 void ProcessParseError(CPDF_Parser::Error err) { 516 uint32_t err_code = FPDF_ERR_SUCCESS; 517 // Translate FPDFAPI error code to FPDFVIEW error code 518 switch (err) { 519 case CPDF_Parser::SUCCESS: 520 err_code = FPDF_ERR_SUCCESS; 521 break; 522 case CPDF_Parser::FILE_ERROR: 523 err_code = FPDF_ERR_FILE; 524 break; 525 case CPDF_Parser::FORMAT_ERROR: 526 err_code = FPDF_ERR_FORMAT; 527 break; 528 case CPDF_Parser::PASSWORD_ERROR: 529 err_code = FPDF_ERR_PASSWORD; 530 break; 531 case CPDF_Parser::HANDLER_ERROR: 532 err_code = FPDF_ERR_SECURITY; 533 break; 534 } 535 SetLastError(err_code); 536 } 537 538 FPDF_EXPORT void FPDF_CALLCONV FPDF_SetSandBoxPolicy(FPDF_DWORD policy, 539 FPDF_BOOL enable) { 540 return FSDK_SetSandBoxPolicy(policy, enable); 541 } 542 543 #if defined(_WIN32) 544 #if defined(PDFIUM_PRINT_TEXT_WITH_GDI) 545 FPDF_EXPORT void FPDF_CALLCONV 546 FPDF_SetTypefaceAccessibleFunc(PDFiumEnsureTypefaceCharactersAccessible func) { 547 g_pdfium_typeface_accessible_func = func; 548 } 549 550 FPDF_EXPORT void FPDF_CALLCONV FPDF_SetPrintTextWithGDI(FPDF_BOOL use_gdi) { 551 g_pdfium_print_text_with_gdi = !!use_gdi; 552 } 553 #endif // PDFIUM_PRINT_TEXT_WITH_GDI 554 555 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV 556 FPDF_SetPrintPostscriptLevel(int postscript_level) { 557 return postscript_level != 1 && FPDF_SetPrintMode(postscript_level); 558 } 559 560 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_SetPrintMode(int mode) { 561 if (mode < FPDF_PRINTMODE_EMF || mode > FPDF_PRINTMODE_POSTSCRIPT3) 562 return FALSE; 563 g_pdfium_print_mode = mode; 564 return TRUE; 565 } 566 #endif // defined(_WIN32) 567 568 FPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV 569 FPDF_LoadDocument(FPDF_STRING file_path, FPDF_BYTESTRING password) { 570 // NOTE: the creation of the file needs to be by the embedder on the 571 // other side of this API. 572 return LoadDocumentImpl(IFX_SeekableReadStream::CreateFromFilename(file_path), 573 password); 574 } 575 576 FPDF_EXPORT int FPDF_CALLCONV FPDF_GetFormType(FPDF_DOCUMENT document) { 577 if (!document) 578 return false; 579 580 const CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document); 581 if (!pDoc) 582 return FORMTYPE_NONE; 583 584 const CPDF_Dictionary* pRoot = pDoc->GetRoot(); 585 if (!pRoot) 586 return FORMTYPE_NONE; 587 588 CPDF_Dictionary* pAcroForm = pRoot->GetDictFor("AcroForm"); 589 if (!pAcroForm) 590 return FORMTYPE_NONE; 591 592 CPDF_Object* pXFA = pAcroForm->GetObjectFor("XFA"); 593 if (!pXFA) 594 return FORMTYPE_ACRO_FORM; 595 596 bool needsRendering = pRoot->GetBooleanFor("NeedsRendering", false); 597 return needsRendering ? FORMTYPE_XFA_FULL : FORMTYPE_XFA_FOREGROUND; 598 } 599 600 #ifdef PDF_ENABLE_XFA 601 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_LoadXFA(FPDF_DOCUMENT document) { 602 return document && static_cast<CPDFXFA_Context*>(document)->LoadXFADoc(); 603 } 604 #endif // PDF_ENABLE_XFA 605 606 class CMemFile final : public IFX_SeekableReadStream { 607 public: 608 static RetainPtr<CMemFile> Create(const uint8_t* pBuf, FX_FILESIZE size) { 609 return RetainPtr<CMemFile>(new CMemFile(pBuf, size)); 610 } 611 612 FX_FILESIZE GetSize() override { return m_size; } 613 bool ReadBlock(void* buffer, FX_FILESIZE offset, size_t size) override { 614 if (offset < 0) 615 return false; 616 617 FX_SAFE_FILESIZE newPos = pdfium::base::checked_cast<FX_FILESIZE>(size); 618 newPos += offset; 619 if (!newPos.IsValid() || newPos.ValueOrDie() > m_size) 620 return false; 621 622 memcpy(buffer, m_pBuf + offset, size); 623 return true; 624 } 625 626 private: 627 CMemFile(const uint8_t* pBuf, FX_FILESIZE size) 628 : m_pBuf(pBuf), m_size(size) {} 629 630 const uint8_t* const m_pBuf; 631 const FX_FILESIZE m_size; 632 }; 633 634 FPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV 635 FPDF_LoadMemDocument(const void* data_buf, int size, FPDF_BYTESTRING password) { 636 return LoadDocumentImpl( 637 CMemFile::Create(static_cast<const uint8_t*>(data_buf), size), password); 638 } 639 640 FPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV 641 FPDF_LoadCustomDocument(FPDF_FILEACCESS* pFileAccess, 642 FPDF_BYTESTRING password) { 643 return LoadDocumentImpl(pdfium::MakeRetain<CPDF_CustomAccess>(pFileAccess), 644 password); 645 } 646 647 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_GetFileVersion(FPDF_DOCUMENT doc, 648 int* fileVersion) { 649 if (!fileVersion) 650 return false; 651 652 *fileVersion = 0; 653 CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(doc); 654 if (!pDoc) 655 return false; 656 657 const CPDF_Parser* pParser = pDoc->GetParser(); 658 if (!pParser) 659 return false; 660 661 *fileVersion = pParser->GetFileVersion(); 662 return true; 663 } 664 665 // jabdelmalek: changed return type from uint32_t to build on Linux (and match 666 // header). 667 FPDF_EXPORT unsigned long FPDF_CALLCONV 668 FPDF_GetDocPermissions(FPDF_DOCUMENT document) { 669 CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document); 670 // https://bugs.chromium.org/p/pdfium/issues/detail?id=499 671 if (!pDoc) { 672 #ifndef PDF_ENABLE_XFA 673 return 0; 674 #else // PDF_ENABLE_XFA 675 return 0xFFFFFFFF; 676 #endif // PDF_ENABLE_XFA 677 } 678 679 return pDoc->GetUserPermissions(); 680 } 681 682 FPDF_EXPORT int FPDF_CALLCONV 683 FPDF_GetSecurityHandlerRevision(FPDF_DOCUMENT document) { 684 CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document); 685 if (!pDoc || !pDoc->GetParser()) 686 return -1; 687 688 CPDF_Dictionary* pDict = pDoc->GetParser()->GetEncryptDict(); 689 return pDict ? pDict->GetIntegerFor("R") : -1; 690 } 691 692 FPDF_EXPORT int FPDF_CALLCONV FPDF_GetPageCount(FPDF_DOCUMENT document) { 693 UnderlyingDocumentType* pDoc = UnderlyingFromFPDFDocument(document); 694 return pDoc ? pDoc->GetPageCount() : 0; 695 } 696 697 FPDF_EXPORT FPDF_PAGE FPDF_CALLCONV FPDF_LoadPage(FPDF_DOCUMENT document, 698 int page_index) { 699 UnderlyingDocumentType* pDoc = UnderlyingFromFPDFDocument(document); 700 if (!pDoc) 701 return nullptr; 702 703 if (page_index < 0 || page_index >= pDoc->GetPageCount()) 704 return nullptr; 705 706 #ifdef PDF_ENABLE_XFA 707 return pDoc->GetXFAPage(page_index).Leak(); 708 #else // PDF_ENABLE_XFA 709 CPDF_Dictionary* pDict = pDoc->GetPage(page_index); 710 if (!pDict) 711 return nullptr; 712 713 CPDF_Page* pPage = new CPDF_Page(pDoc, pDict, true); 714 pPage->ParseContent(); 715 return pPage; 716 #endif // PDF_ENABLE_XFA 717 } 718 719 FPDF_EXPORT double FPDF_CALLCONV FPDF_GetPageWidth(FPDF_PAGE page) { 720 UnderlyingPageType* pPage = UnderlyingFromFPDFPage(page); 721 return pPage ? pPage->GetPageWidth() : 0.0; 722 } 723 724 FPDF_EXPORT double FPDF_CALLCONV FPDF_GetPageHeight(FPDF_PAGE page) { 725 UnderlyingPageType* pPage = UnderlyingFromFPDFPage(page); 726 return pPage ? pPage->GetPageHeight() : 0.0; 727 } 728 729 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_GetPageBoundingBox(FPDF_PAGE page, 730 FS_RECTF* rect) { 731 if (!rect) 732 return false; 733 734 CPDF_Page* pPage = CPDFPageFromFPDFPage(page); 735 if (!pPage) 736 return false; 737 738 FSRECTFFromCFXFloatRect(pPage->GetPageBBox(), rect); 739 return true; 740 } 741 742 #if defined(_WIN32) 743 namespace { 744 745 const double kEpsilonSize = 0.01f; 746 747 void GetScaling(CPDF_Page* pPage, 748 int size_x, 749 int size_y, 750 int rotate, 751 double* scale_x, 752 double* scale_y) { 753 ASSERT(pPage); 754 ASSERT(scale_x); 755 ASSERT(scale_y); 756 double page_width = pPage->GetPageWidth(); 757 double page_height = pPage->GetPageHeight(); 758 if (page_width < kEpsilonSize || page_height < kEpsilonSize) 759 return; 760 761 if (rotate % 2 == 0) { 762 *scale_x = size_x / page_width; 763 *scale_y = size_y / page_height; 764 } else { 765 *scale_x = size_y / page_width; 766 *scale_y = size_x / page_height; 767 } 768 } 769 770 FX_RECT GetMaskDimensionsAndOffsets(CPDF_Page* pPage, 771 int start_x, 772 int start_y, 773 int size_x, 774 int size_y, 775 int rotate, 776 const CFX_FloatRect& mask_box) { 777 double scale_x = 0.0f; 778 double scale_y = 0.0f; 779 GetScaling(pPage, size_x, size_y, rotate, &scale_x, &scale_y); 780 if (scale_x < kEpsilonSize || scale_y < kEpsilonSize) 781 return FX_RECT(); 782 783 // Compute sizes in page points. Round down to catch the entire bitmap. 784 int start_x_bm = static_cast<int>(mask_box.left * scale_x); 785 int start_y_bm = static_cast<int>(mask_box.bottom * scale_y); 786 int size_x_bm = static_cast<int>(mask_box.right * scale_x + 1.0f) - 787 static_cast<int>(mask_box.left * scale_x); 788 int size_y_bm = static_cast<int>(mask_box.top * scale_y + 1.0f) - 789 static_cast<int>(mask_box.bottom * scale_y); 790 791 // Get page rotation 792 int page_rotation = pPage->GetPageRotation(); 793 794 // Compute offsets 795 int offset_x = 0; 796 int offset_y = 0; 797 if (size_x > size_y) 798 std::swap(size_x_bm, size_y_bm); 799 800 switch ((rotate + page_rotation) % 4) { 801 case 0: 802 offset_x = start_x_bm + start_x; 803 offset_y = start_y + size_y - size_y_bm - start_y_bm; 804 break; 805 case 1: 806 offset_x = start_y_bm + start_x; 807 offset_y = start_x_bm + start_y; 808 break; 809 case 2: 810 offset_x = start_x + size_x - size_x_bm - start_x_bm; 811 offset_y = start_y_bm + start_y; 812 break; 813 case 3: 814 offset_x = start_x + size_x - size_x_bm - start_y_bm; 815 offset_y = start_y + size_y - size_y_bm - start_x_bm; 816 break; 817 } 818 return FX_RECT(offset_x, offset_y, offset_x + size_x_bm, 819 offset_y + size_y_bm); 820 } 821 822 // Get a bitmap of just the mask section defined by |mask_box| from a full page 823 // bitmap |pBitmap|. 824 RetainPtr<CFX_DIBitmap> GetMaskBitmap(CPDF_Page* pPage, 825 int start_x, 826 int start_y, 827 int size_x, 828 int size_y, 829 int rotate, 830 const RetainPtr<CFX_DIBitmap>& pSrc, 831 const CFX_FloatRect& mask_box, 832 FX_RECT* bitmap_area) { 833 ASSERT(bitmap_area); 834 *bitmap_area = GetMaskDimensionsAndOffsets(pPage, start_x, start_y, size_x, 835 size_y, rotate, mask_box); 836 if (bitmap_area->IsEmpty()) 837 return nullptr; 838 839 // Create a new bitmap to transfer part of the page bitmap to. 840 RetainPtr<CFX_DIBitmap> pDst = pdfium::MakeRetain<CFX_DIBitmap>(); 841 pDst->Create(bitmap_area->Width(), bitmap_area->Height(), FXDIB_Argb); 842 pDst->Clear(0x00ffffff); 843 pDst->TransferBitmap(0, 0, bitmap_area->Width(), bitmap_area->Height(), pSrc, 844 bitmap_area->left, bitmap_area->top); 845 return pDst; 846 } 847 848 void RenderBitmap(CFX_RenderDevice* device, 849 const RetainPtr<CFX_DIBitmap>& pSrc, 850 const FX_RECT& mask_area) { 851 int size_x_bm = mask_area.Width(); 852 int size_y_bm = mask_area.Height(); 853 if (size_x_bm == 0 || size_y_bm == 0) 854 return; 855 856 // Create a new bitmap from the old one 857 RetainPtr<CFX_DIBitmap> pDst = pdfium::MakeRetain<CFX_DIBitmap>(); 858 pDst->Create(size_x_bm, size_y_bm, FXDIB_Rgb32); 859 pDst->Clear(0xffffffff); 860 pDst->CompositeBitmap(0, 0, size_x_bm, size_y_bm, pSrc, 0, 0, 861 FXDIB_BLEND_NORMAL, nullptr, false); 862 863 if (device->GetDeviceCaps(FXDC_DEVICE_CLASS) == FXDC_PRINTER) { 864 device->StretchDIBits(pDst, mask_area.left, mask_area.top, size_x_bm, 865 size_y_bm); 866 } else { 867 device->SetDIBits(pDst, mask_area.left, mask_area.top); 868 } 869 } 870 871 } // namespace 872 873 FPDF_EXPORT void FPDF_CALLCONV FPDF_RenderPage(HDC dc, 874 FPDF_PAGE page, 875 int start_x, 876 int start_y, 877 int size_x, 878 int size_y, 879 int rotate, 880 int flags) { 881 CPDF_Page* pPage = CPDFPageFromFPDFPage(page); 882 if (!pPage) 883 return; 884 pPage->SetRenderContext(pdfium::MakeUnique<CPDF_PageRenderContext>()); 885 CPDF_PageRenderContext* pContext = pPage->GetRenderContext(); 886 887 RetainPtr<CFX_DIBitmap> pBitmap; 888 // Don't render the full page to bitmap for a mask unless there are a lot 889 // of masks. Full page bitmaps result in large spool sizes, so they should 890 // only be used when necessary. For large numbers of masks, rendering each 891 // individually is inefficient and unlikely to significantly improve spool 892 // size. TODO (rbpotter): Find out why this still breaks printing for some 893 // PDFs (see crbug.com/777837). 894 const bool bEnableImageMasks = false; 895 const bool bNewBitmap = pPage->BackgroundAlphaNeeded() || 896 (pPage->HasImageMask() && !bEnableImageMasks) || 897 pPage->GetMaskBoundingBoxes().size() > 100; 898 const bool bHasMask = pPage->HasImageMask() && !bNewBitmap; 899 if (bNewBitmap || bHasMask) { 900 pBitmap = pdfium::MakeRetain<CFX_DIBitmap>(); 901 pBitmap->Create(size_x, size_y, FXDIB_Argb); 902 pBitmap->Clear(0x00ffffff); 903 CFX_DefaultRenderDevice* pDevice = new CFX_DefaultRenderDevice; 904 pContext->m_pDevice = pdfium::WrapUnique(pDevice); 905 pDevice->Attach(pBitmap, false, nullptr, false); 906 if (bHasMask) { 907 pContext->m_pOptions = pdfium::MakeUnique<CPDF_RenderOptions>(); 908 uint32_t option_flags = pContext->m_pOptions->GetFlags(); 909 option_flags |= RENDER_BREAKFORMASKS; 910 pContext->m_pOptions->SetFlags(option_flags); 911 } 912 } else { 913 pContext->m_pDevice = pdfium::MakeUnique<CFX_WindowsRenderDevice>(dc); 914 } 915 916 FPDF_RenderPage_Retail(pContext, page, start_x, start_y, size_x, size_y, 917 rotate, flags, true, nullptr); 918 919 if (bHasMask) { 920 // Finish rendering the page to bitmap and copy the correct segments 921 // of the page to individual image mask bitmaps. 922 const std::vector<CFX_FloatRect>& mask_boxes = 923 pPage->GetMaskBoundingBoxes(); 924 std::vector<FX_RECT> bitmap_areas(mask_boxes.size()); 925 std::vector<RetainPtr<CFX_DIBitmap>> bitmaps(mask_boxes.size()); 926 for (size_t i = 0; i < mask_boxes.size(); i++) { 927 bitmaps[i] = 928 GetMaskBitmap(pPage, start_x, start_y, size_x, size_y, rotate, 929 pBitmap, mask_boxes[i], &bitmap_areas[i]); 930 pContext->m_pRenderer->Continue(nullptr); 931 } 932 933 // Reset rendering context 934 pPage->SetRenderContext(nullptr); 935 936 // Begin rendering to the printer. Add flag to indicate the renderer should 937 // pause after each image mask. 938 pPage->SetRenderContext(pdfium::MakeUnique<CPDF_PageRenderContext>()); 939 pContext = pPage->GetRenderContext(); 940 pContext->m_pDevice = pdfium::MakeUnique<CFX_WindowsRenderDevice>(dc); 941 pContext->m_pOptions = pdfium::MakeUnique<CPDF_RenderOptions>(); 942 943 uint32_t option_flags = pContext->m_pOptions->GetFlags(); 944 option_flags |= RENDER_BREAKFORMASKS; 945 pContext->m_pOptions->SetFlags(option_flags); 946 947 FPDF_RenderPage_Retail(pContext, page, start_x, start_y, size_x, size_y, 948 rotate, flags, true, nullptr); 949 950 // Render masks 951 for (size_t i = 0; i < mask_boxes.size(); i++) { 952 // Render the bitmap for the mask and free the bitmap. 953 if (bitmaps[i]) { // will be null if mask has zero area 954 RenderBitmap(pContext->m_pDevice.get(), bitmaps[i], bitmap_areas[i]); 955 } 956 // Render the next portion of page. 957 pContext->m_pRenderer->Continue(nullptr); 958 } 959 } else if (bNewBitmap) { 960 CFX_WindowsRenderDevice WinDC(dc); 961 if (WinDC.GetDeviceCaps(FXDC_DEVICE_CLASS) == FXDC_PRINTER) { 962 auto pDst = pdfium::MakeRetain<CFX_DIBitmap>(); 963 int pitch = pBitmap->GetPitch(); 964 pDst->Create(size_x, size_y, FXDIB_Rgb32); 965 memset(pDst->GetBuffer(), -1, pitch * size_y); 966 pDst->CompositeBitmap(0, 0, size_x, size_y, pBitmap, 0, 0, 967 FXDIB_BLEND_NORMAL, nullptr, false); 968 WinDC.StretchDIBits(pDst, 0, 0, size_x, size_y); 969 } else { 970 WinDC.SetDIBits(pBitmap, 0, 0); 971 } 972 } 973 974 pPage->SetRenderContext(nullptr); 975 } 976 #endif // defined(_WIN32) 977 978 FPDF_EXPORT void FPDF_CALLCONV FPDF_RenderPageBitmap(FPDF_BITMAP bitmap, 979 FPDF_PAGE page, 980 int start_x, 981 int start_y, 982 int size_x, 983 int size_y, 984 int rotate, 985 int flags) { 986 if (!bitmap) 987 return; 988 989 CPDF_Page* pPage = CPDFPageFromFPDFPage(page); 990 if (!pPage) 991 return; 992 993 CPDF_PageRenderContext* pContext = new CPDF_PageRenderContext; 994 pPage->SetRenderContext(pdfium::WrapUnique(pContext)); 995 996 CFX_DefaultRenderDevice* pDevice = new CFX_DefaultRenderDevice; 997 pContext->m_pDevice.reset(pDevice); 998 999 RetainPtr<CFX_DIBitmap> pBitmap(CFXBitmapFromFPDFBitmap(bitmap)); 1000 pDevice->Attach(pBitmap, !!(flags & FPDF_REVERSE_BYTE_ORDER), nullptr, false); 1001 FPDF_RenderPage_Retail(pContext, page, start_x, start_y, size_x, size_y, 1002 rotate, flags, true, nullptr); 1003 1004 #ifdef _SKIA_SUPPORT_PATHS_ 1005 pDevice->Flush(true); 1006 pBitmap->UnPreMultiply(); 1007 #endif 1008 pPage->SetRenderContext(nullptr); 1009 } 1010 1011 FPDF_EXPORT void FPDF_CALLCONV 1012 FPDF_RenderPageBitmapWithMatrix(FPDF_BITMAP bitmap, 1013 FPDF_PAGE page, 1014 const FS_MATRIX* matrix, 1015 const FS_RECTF* clipping, 1016 int flags) { 1017 if (!bitmap) 1018 return; 1019 1020 CPDF_Page* pPage = CPDFPageFromFPDFPage(page); 1021 if (!pPage) 1022 return; 1023 1024 CPDF_PageRenderContext* pContext = new CPDF_PageRenderContext; 1025 pPage->SetRenderContext(pdfium::WrapUnique(pContext)); 1026 1027 CFX_DefaultRenderDevice* pDevice = new CFX_DefaultRenderDevice; 1028 pContext->m_pDevice.reset(pDevice); 1029 1030 RetainPtr<CFX_DIBitmap> pBitmap(CFXBitmapFromFPDFBitmap(bitmap)); 1031 pDevice->Attach(pBitmap, !!(flags & FPDF_REVERSE_BYTE_ORDER), nullptr, false); 1032 1033 CFX_FloatRect clipping_rect; 1034 if (clipping) 1035 clipping_rect = CFXFloatRectFromFSRECTF(*clipping); 1036 FX_RECT clip_rect = clipping_rect.ToFxRect(); 1037 1038 CFX_Matrix transform_matrix = pPage->GetDisplayMatrix( 1039 0, 0, pPage->GetPageWidth(), pPage->GetPageHeight(), 0); 1040 1041 if (matrix) { 1042 transform_matrix.Concat(CFX_Matrix(matrix->a, matrix->b, matrix->c, 1043 matrix->d, matrix->e, matrix->f)); 1044 } 1045 RenderPageImpl(pContext, pPage, transform_matrix, clip_rect, flags, true, 1046 nullptr); 1047 1048 pPage->SetRenderContext(nullptr); 1049 } 1050 1051 #ifdef _SKIA_SUPPORT_ 1052 FPDF_EXPORT FPDF_RECORDER FPDF_CALLCONV FPDF_RenderPageSkp(FPDF_PAGE page, 1053 int size_x, 1054 int size_y) { 1055 CPDF_Page* pPage = CPDFPageFromFPDFPage(page); 1056 if (!pPage) 1057 return nullptr; 1058 1059 CPDF_PageRenderContext* pContext = new CPDF_PageRenderContext; 1060 pPage->SetRenderContext(pdfium::WrapUnique(pContext)); 1061 CFX_DefaultRenderDevice* skDevice = new CFX_DefaultRenderDevice; 1062 FPDF_RECORDER recorder = skDevice->CreateRecorder(size_x, size_y); 1063 pContext->m_pDevice.reset(skDevice); 1064 FPDF_RenderPage_Retail(pContext, page, 0, 0, size_x, size_y, 0, 0, true, 1065 nullptr); 1066 pPage->SetRenderContext(nullptr); 1067 return recorder; 1068 } 1069 #endif 1070 1071 FPDF_EXPORT void FPDF_CALLCONV FPDF_ClosePage(FPDF_PAGE page) { 1072 UnderlyingPageType* pPage = UnderlyingFromFPDFPage(page); 1073 if (!page) 1074 return; 1075 #ifdef PDF_ENABLE_XFA 1076 // Take it back across the API and throw it away. 1077 RetainPtr<CPDFXFA_Page>().Unleak(pPage); 1078 #else // PDF_ENABLE_XFA 1079 CPDFSDK_PageView* pPageView = 1080 static_cast<CPDFSDK_PageView*>(pPage->GetView()); 1081 if (pPageView) { 1082 // We're already destroying the pageview, so bail early. 1083 if (pPageView->IsBeingDestroyed()) 1084 return; 1085 1086 if (pPageView->IsLocked()) { 1087 pPageView->TakePageOwnership(); 1088 return; 1089 } 1090 1091 bool owned = pPageView->OwnsPage(); 1092 // This will delete the |pPageView| object. We must cleanup the PageView 1093 // first because it will attempt to reset the View on the |pPage| during 1094 // destruction. 1095 pPageView->GetFormFillEnv()->RemovePageView(pPage); 1096 // If the page was owned then the pageview will have deleted the page. 1097 if (owned) 1098 return; 1099 } 1100 delete pPage; 1101 #endif // PDF_ENABLE_XFA 1102 } 1103 1104 FPDF_EXPORT void FPDF_CALLCONV FPDF_CloseDocument(FPDF_DOCUMENT document) { 1105 delete UnderlyingFromFPDFDocument(document); 1106 } 1107 1108 FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetLastError() { 1109 return GetLastError(); 1110 } 1111 1112 FPDF_EXPORT void FPDF_CALLCONV FPDF_DeviceToPage(FPDF_PAGE page, 1113 int start_x, 1114 int start_y, 1115 int size_x, 1116 int size_y, 1117 int rotate, 1118 int device_x, 1119 int device_y, 1120 double* page_x, 1121 double* page_y) { 1122 if (!page || !page_x || !page_y) 1123 return; 1124 UnderlyingPageType* pPage = UnderlyingFromFPDFPage(page); 1125 #ifdef PDF_ENABLE_XFA 1126 pPage->DeviceToPage(start_x, start_y, size_x, size_y, rotate, device_x, 1127 device_y, page_x, page_y); 1128 #else // PDF_ENABLE_XFA 1129 CFX_Matrix page2device = 1130 pPage->GetDisplayMatrix(start_x, start_y, size_x, size_y, rotate); 1131 1132 CFX_PointF pos = page2device.GetInverse().Transform( 1133 CFX_PointF(static_cast<float>(device_x), static_cast<float>(device_y))); 1134 1135 *page_x = pos.x; 1136 *page_y = pos.y; 1137 #endif // PDF_ENABLE_XFA 1138 } 1139 1140 FPDF_EXPORT void FPDF_CALLCONV FPDF_PageToDevice(FPDF_PAGE page, 1141 int start_x, 1142 int start_y, 1143 int size_x, 1144 int size_y, 1145 int rotate, 1146 double page_x, 1147 double page_y, 1148 int* device_x, 1149 int* device_y) { 1150 if (!device_x || !device_y) 1151 return; 1152 UnderlyingPageType* pPage = UnderlyingFromFPDFPage(page); 1153 if (!pPage) 1154 return; 1155 #ifdef PDF_ENABLE_XFA 1156 pPage->PageToDevice(start_x, start_y, size_x, size_y, rotate, page_x, page_y, 1157 device_x, device_y); 1158 #else // PDF_ENABLE_XFA 1159 CFX_Matrix page2device = 1160 pPage->GetDisplayMatrix(start_x, start_y, size_x, size_y, rotate); 1161 CFX_PointF pos = page2device.Transform( 1162 CFX_PointF(static_cast<float>(page_x), static_cast<float>(page_y))); 1163 1164 *device_x = FXSYS_round(pos.x); 1165 *device_y = FXSYS_round(pos.y); 1166 #endif // PDF_ENABLE_XFA 1167 } 1168 1169 FPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV FPDFBitmap_Create(int width, 1170 int height, 1171 int alpha) { 1172 auto pBitmap = pdfium::MakeRetain<CFX_DIBitmap>(); 1173 if (!pBitmap->Create(width, height, alpha ? FXDIB_Argb : FXDIB_Rgb32)) 1174 return nullptr; 1175 1176 return pBitmap.Leak(); 1177 } 1178 1179 FPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV FPDFBitmap_CreateEx(int width, 1180 int height, 1181 int format, 1182 void* first_scan, 1183 int stride) { 1184 FXDIB_Format fx_format; 1185 switch (format) { 1186 case FPDFBitmap_Gray: 1187 fx_format = FXDIB_8bppRgb; 1188 break; 1189 case FPDFBitmap_BGR: 1190 fx_format = FXDIB_Rgb; 1191 break; 1192 case FPDFBitmap_BGRx: 1193 fx_format = FXDIB_Rgb32; 1194 break; 1195 case FPDFBitmap_BGRA: 1196 fx_format = FXDIB_Argb; 1197 break; 1198 default: 1199 return nullptr; 1200 } 1201 auto pBitmap = pdfium::MakeRetain<CFX_DIBitmap>(); 1202 pBitmap->Create(width, height, fx_format, static_cast<uint8_t*>(first_scan), 1203 stride); 1204 return pBitmap.Leak(); 1205 } 1206 1207 FPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetFormat(FPDF_BITMAP bitmap) { 1208 if (!bitmap) 1209 return FPDFBitmap_Unknown; 1210 1211 FXDIB_Format format = CFXBitmapFromFPDFBitmap(bitmap)->GetFormat(); 1212 switch (format) { 1213 case FXDIB_8bppRgb: 1214 case FXDIB_8bppMask: 1215 return FPDFBitmap_Gray; 1216 case FXDIB_Rgb: 1217 return FPDFBitmap_BGR; 1218 case FXDIB_Rgb32: 1219 return FPDFBitmap_BGRx; 1220 case FXDIB_Argb: 1221 return FPDFBitmap_BGRA; 1222 default: 1223 return FPDFBitmap_Unknown; 1224 } 1225 } 1226 1227 FPDF_EXPORT void FPDF_CALLCONV FPDFBitmap_FillRect(FPDF_BITMAP bitmap, 1228 int left, 1229 int top, 1230 int width, 1231 int height, 1232 FPDF_DWORD color) { 1233 if (!bitmap) 1234 return; 1235 1236 CFX_DefaultRenderDevice device; 1237 RetainPtr<CFX_DIBitmap> pBitmap(CFXBitmapFromFPDFBitmap(bitmap)); 1238 device.Attach(pBitmap, false, nullptr, false); 1239 if (!pBitmap->HasAlpha()) 1240 color |= 0xFF000000; 1241 FX_RECT rect(left, top, left + width, top + height); 1242 device.FillRect(&rect, color); 1243 } 1244 1245 FPDF_EXPORT void* FPDF_CALLCONV FPDFBitmap_GetBuffer(FPDF_BITMAP bitmap) { 1246 return bitmap ? CFXBitmapFromFPDFBitmap(bitmap)->GetBuffer() : nullptr; 1247 } 1248 1249 FPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetWidth(FPDF_BITMAP bitmap) { 1250 return bitmap ? CFXBitmapFromFPDFBitmap(bitmap)->GetWidth() : 0; 1251 } 1252 1253 FPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetHeight(FPDF_BITMAP bitmap) { 1254 return bitmap ? CFXBitmapFromFPDFBitmap(bitmap)->GetHeight() : 0; 1255 } 1256 1257 FPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetStride(FPDF_BITMAP bitmap) { 1258 return bitmap ? CFXBitmapFromFPDFBitmap(bitmap)->GetPitch() : 0; 1259 } 1260 1261 FPDF_EXPORT void FPDF_CALLCONV FPDFBitmap_Destroy(FPDF_BITMAP bitmap) { 1262 RetainPtr<CFX_DIBitmap> destroyer; 1263 destroyer.Unleak(CFXBitmapFromFPDFBitmap(bitmap)); 1264 } 1265 1266 void FPDF_RenderPage_Retail(CPDF_PageRenderContext* pContext, 1267 FPDF_PAGE page, 1268 int start_x, 1269 int start_y, 1270 int size_x, 1271 int size_y, 1272 int rotate, 1273 int flags, 1274 bool bNeedToRestore, 1275 IFSDK_PAUSE_Adapter* pause) { 1276 CPDF_Page* pPage = CPDFPageFromFPDFPage(page); 1277 if (!pPage) 1278 return; 1279 1280 RenderPageImpl(pContext, pPage, pPage->GetDisplayMatrix( 1281 start_x, start_y, size_x, size_y, rotate), 1282 FX_RECT(start_x, start_y, start_x + size_x, start_y + size_y), 1283 flags, bNeedToRestore, pause); 1284 } 1285 1286 FPDF_EXPORT int FPDF_CALLCONV FPDF_GetPageSizeByIndex(FPDF_DOCUMENT document, 1287 int page_index, 1288 double* width, 1289 double* height) { 1290 UnderlyingDocumentType* pDoc = UnderlyingFromFPDFDocument(document); 1291 if (!pDoc) 1292 return false; 1293 1294 #ifdef PDF_ENABLE_XFA 1295 int count = pDoc->GetPageCount(); 1296 if (page_index < 0 || page_index >= count) 1297 return false; 1298 RetainPtr<CPDFXFA_Page> pPage = pDoc->GetXFAPage(page_index); 1299 if (!pPage) 1300 return false; 1301 *width = pPage->GetPageWidth(); 1302 *height = pPage->GetPageHeight(); 1303 #else // PDF_ENABLE_XFA 1304 CPDF_Dictionary* pDict = pDoc->GetPage(page_index); 1305 if (!pDict) 1306 return false; 1307 1308 CPDF_Page page(pDoc, pDict, true); 1309 *width = page.GetPageWidth(); 1310 *height = page.GetPageHeight(); 1311 #endif // PDF_ENABLE_XFA 1312 1313 return true; 1314 } 1315 1316 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV 1317 FPDF_VIEWERREF_GetPrintScaling(FPDF_DOCUMENT document) { 1318 CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document); 1319 if (!pDoc) 1320 return true; 1321 CPDF_ViewerPreferences viewRef(pDoc); 1322 return viewRef.PrintScaling(); 1323 } 1324 1325 FPDF_EXPORT int FPDF_CALLCONV 1326 FPDF_VIEWERREF_GetNumCopies(FPDF_DOCUMENT document) { 1327 CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document); 1328 if (!pDoc) 1329 return 1; 1330 CPDF_ViewerPreferences viewRef(pDoc); 1331 return viewRef.NumCopies(); 1332 } 1333 1334 FPDF_EXPORT FPDF_PAGERANGE FPDF_CALLCONV 1335 FPDF_VIEWERREF_GetPrintPageRange(FPDF_DOCUMENT document) { 1336 CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document); 1337 if (!pDoc) 1338 return nullptr; 1339 CPDF_ViewerPreferences viewRef(pDoc); 1340 return viewRef.PrintPageRange(); 1341 } 1342 1343 FPDF_EXPORT FPDF_DUPLEXTYPE FPDF_CALLCONV 1344 FPDF_VIEWERREF_GetDuplex(FPDF_DOCUMENT document) { 1345 CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document); 1346 if (!pDoc) 1347 return DuplexUndefined; 1348 CPDF_ViewerPreferences viewRef(pDoc); 1349 ByteString duplex = viewRef.Duplex(); 1350 if ("Simplex" == duplex) 1351 return Simplex; 1352 if ("DuplexFlipShortEdge" == duplex) 1353 return DuplexFlipShortEdge; 1354 if ("DuplexFlipLongEdge" == duplex) 1355 return DuplexFlipLongEdge; 1356 return DuplexUndefined; 1357 } 1358 1359 FPDF_EXPORT unsigned long FPDF_CALLCONV 1360 FPDF_VIEWERREF_GetName(FPDF_DOCUMENT document, 1361 FPDF_BYTESTRING key, 1362 char* buffer, 1363 unsigned long length) { 1364 CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document); 1365 if (!pDoc) 1366 return 0; 1367 1368 CPDF_ViewerPreferences viewRef(pDoc); 1369 ByteString bsVal; 1370 if (!viewRef.GenericName(key, &bsVal)) 1371 return 0; 1372 1373 unsigned long dwStringLen = bsVal.GetLength() + 1; 1374 if (buffer && length >= dwStringLen) 1375 memcpy(buffer, bsVal.c_str(), dwStringLen); 1376 return dwStringLen; 1377 } 1378 1379 FPDF_EXPORT FPDF_DWORD FPDF_CALLCONV 1380 FPDF_CountNamedDests(FPDF_DOCUMENT document) { 1381 CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document); 1382 if (!pDoc) 1383 return 0; 1384 1385 const CPDF_Dictionary* pRoot = pDoc->GetRoot(); 1386 if (!pRoot) 1387 return 0; 1388 1389 CPDF_NameTree nameTree(pDoc, "Dests"); 1390 pdfium::base::CheckedNumeric<FPDF_DWORD> count = nameTree.GetCount(); 1391 CPDF_Dictionary* pDest = pRoot->GetDictFor("Dests"); 1392 if (pDest) 1393 count += pDest->GetCount(); 1394 1395 if (!count.IsValid()) 1396 return 0; 1397 1398 return count.ValueOrDie(); 1399 } 1400 1401 FPDF_EXPORT FPDF_DEST FPDF_CALLCONV 1402 FPDF_GetNamedDestByName(FPDF_DOCUMENT document, FPDF_BYTESTRING name) { 1403 if (!name || name[0] == 0) 1404 return nullptr; 1405 1406 CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document); 1407 if (!pDoc) 1408 return nullptr; 1409 1410 CPDF_NameTree name_tree(pDoc, "Dests"); 1411 return name_tree.LookupNamedDest(pDoc, PDF_DecodeText(ByteString(name))); 1412 } 1413 1414 #ifdef PDF_ENABLE_XFA 1415 FPDF_EXPORT FPDF_RESULT FPDF_CALLCONV FPDF_BStr_Init(FPDF_BSTR* str) { 1416 if (!str) 1417 return -1; 1418 1419 memset(str, 0, sizeof(FPDF_BSTR)); 1420 return 0; 1421 } 1422 1423 FPDF_EXPORT FPDF_RESULT FPDF_CALLCONV FPDF_BStr_Set(FPDF_BSTR* str, 1424 FPDF_LPCSTR bstr, 1425 int length) { 1426 if (!str || !bstr || !length) 1427 return -1; 1428 1429 if (length == -1) 1430 length = strlen(bstr); 1431 1432 if (length == 0) { 1433 FPDF_BStr_Clear(str); 1434 return 0; 1435 } 1436 1437 if (str->str && str->len < length) 1438 str->str = FX_Realloc(char, str->str, length + 1); 1439 else if (!str->str) 1440 str->str = FX_Alloc(char, length + 1); 1441 1442 str->str[length] = 0; 1443 memcpy(str->str, bstr, length); 1444 str->len = length; 1445 1446 return 0; 1447 } 1448 1449 FPDF_EXPORT FPDF_RESULT FPDF_CALLCONV FPDF_BStr_Clear(FPDF_BSTR* str) { 1450 if (!str) 1451 return -1; 1452 1453 if (str->str) { 1454 FX_Free(str->str); 1455 str->str = nullptr; 1456 } 1457 str->len = 0; 1458 return 0; 1459 } 1460 #endif // PDF_ENABLE_XFA 1461 1462 FPDF_EXPORT FPDF_DEST FPDF_CALLCONV FPDF_GetNamedDest(FPDF_DOCUMENT document, 1463 int index, 1464 void* buffer, 1465 long* buflen) { 1466 if (!buffer) 1467 *buflen = 0; 1468 1469 if (index < 0) 1470 return nullptr; 1471 1472 CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document); 1473 if (!pDoc) 1474 return nullptr; 1475 1476 const CPDF_Dictionary* pRoot = pDoc->GetRoot(); 1477 if (!pRoot) 1478 return nullptr; 1479 1480 CPDF_Object* pDestObj = nullptr; 1481 WideString wsName; 1482 CPDF_NameTree nameTree(pDoc, "Dests"); 1483 int count = nameTree.GetCount(); 1484 if (index >= count) { 1485 CPDF_Dictionary* pDest = pRoot->GetDictFor("Dests"); 1486 if (!pDest) 1487 return nullptr; 1488 1489 pdfium::base::CheckedNumeric<int> checked_count = count; 1490 checked_count += pDest->GetCount(); 1491 if (!checked_count.IsValid() || index >= checked_count.ValueOrDie()) 1492 return nullptr; 1493 1494 index -= count; 1495 int i = 0; 1496 ByteString bsName; 1497 for (const auto& it : *pDest) { 1498 bsName = it.first; 1499 pDestObj = it.second.get(); 1500 if (!pDestObj) 1501 continue; 1502 if (i == index) 1503 break; 1504 i++; 1505 } 1506 wsName = PDF_DecodeText(bsName); 1507 } else { 1508 pDestObj = nameTree.LookupValueAndName(index, &wsName); 1509 } 1510 if (!pDestObj) 1511 return nullptr; 1512 if (CPDF_Dictionary* pDict = pDestObj->AsDictionary()) { 1513 pDestObj = pDict->GetArrayFor("D"); 1514 if (!pDestObj) 1515 return nullptr; 1516 } 1517 if (!pDestObj->IsArray()) 1518 return nullptr; 1519 1520 ByteString utf16Name = wsName.UTF16LE_Encode(); 1521 int len = utf16Name.GetLength(); 1522 if (!buffer) { 1523 *buflen = len; 1524 } else if (len <= *buflen) { 1525 memcpy(buffer, utf16Name.c_str(), len); 1526 *buflen = len; 1527 } else { 1528 *buflen = -1; 1529 } 1530 return (FPDF_DEST)pDestObj; 1531 } 1532