Home | History | Annotate | Download | only in fpdfsdk
      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