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 11 #include "core/include/fxcodec/fx_codec.h" 12 #include "core/include/fxcrt/fx_safe_types.h" 13 #include "fpdfsdk/include/fsdk_define.h" 14 #include "fpdfsdk/include/fsdk_mgr.h" 15 #include "fpdfsdk/include/fsdk_rendercontext.h" 16 #include "fpdfsdk/include/javascript/IJavaScript.h" 17 #include "public/fpdf_ext.h" 18 #include "public/fpdf_progressive.h" 19 #include "third_party/base/numerics/safe_conversions_impl.h" 20 21 #ifdef PDF_ENABLE_XFA 22 #include "core/include/fpdfapi/fpdf_module.h" 23 #include "fpdfsdk/include/fpdfxfa/fpdfxfa_app.h" 24 #include "fpdfsdk/include/fpdfxfa/fpdfxfa_doc.h" 25 #include "fpdfsdk/include/fpdfxfa/fpdfxfa_page.h" 26 #include "fpdfsdk/include/fpdfxfa/fpdfxfa_util.h" 27 #include "public/fpdf_formfill.h" 28 #endif // PDF_ENABLE_XFA 29 30 UnderlyingDocumentType* UnderlyingFromFPDFDocument(FPDF_DOCUMENT doc) { 31 return static_cast<UnderlyingDocumentType*>(doc); 32 } 33 34 FPDF_DOCUMENT FPDFDocumentFromUnderlying(UnderlyingDocumentType* doc) { 35 return static_cast<FPDF_DOCUMENT>(doc); 36 } 37 38 UnderlyingPageType* UnderlyingFromFPDFPage(FPDF_PAGE page) { 39 return static_cast<UnderlyingPageType*>(page); 40 } 41 42 CPDF_Document* CPDFDocumentFromFPDFDocument(FPDF_DOCUMENT doc) { 43 #ifdef PDF_ENABLE_XFA 44 return doc ? UnderlyingFromFPDFDocument(doc)->GetPDFDoc() : nullptr; 45 #else // PDF_ENABLE_XFA 46 return UnderlyingFromFPDFDocument(doc); 47 #endif // PDF_ENABLE_XFA 48 } 49 50 FPDF_DOCUMENT FPDFDocumentFromCPDFDocument(CPDF_Document* doc) { 51 #ifdef PDF_ENABLE_XFA 52 return doc ? FPDFDocumentFromUnderlying( 53 new CPDFXFA_Document(doc, CPDFXFA_App::GetInstance())) 54 : nullptr; 55 #else // PDF_ENABLE_XFA 56 return FPDFDocumentFromUnderlying(doc); 57 #endif // PDF_ENABLE_XFA 58 } 59 60 CPDF_Page* CPDFPageFromFPDFPage(FPDF_PAGE page) { 61 #ifdef PDF_ENABLE_XFA 62 return page ? UnderlyingFromFPDFPage(page)->GetPDFPage() : nullptr; 63 #else // PDF_ENABLE_XFA 64 return UnderlyingFromFPDFPage(page); 65 #endif // PDF_ENABLE_XFA 66 } 67 68 #ifdef PDF_ENABLE_XFA 69 CFPDF_FileStream::CFPDF_FileStream(FPDF_FILEHANDLER* pFS) { 70 m_pFS = pFS; 71 m_nCurPos = 0; 72 } 73 74 IFX_FileStream* CFPDF_FileStream::Retain() { 75 return this; 76 } 77 78 void CFPDF_FileStream::Release() { 79 if (m_pFS && m_pFS->Release) 80 m_pFS->Release(m_pFS->clientData); 81 delete this; 82 } 83 84 FX_FILESIZE CFPDF_FileStream::GetSize() { 85 if (m_pFS && m_pFS->GetSize) 86 return (FX_FILESIZE)m_pFS->GetSize(m_pFS->clientData); 87 return 0; 88 } 89 90 FX_BOOL CFPDF_FileStream::IsEOF() { 91 return m_nCurPos >= GetSize(); 92 } 93 94 FX_BOOL CFPDF_FileStream::ReadBlock(void* buffer, 95 FX_FILESIZE offset, 96 size_t size) { 97 if (!buffer || !size || !m_pFS->ReadBlock) 98 return FALSE; 99 100 if (m_pFS->ReadBlock(m_pFS->clientData, (FPDF_DWORD)offset, buffer, 101 (FPDF_DWORD)size) == 0) { 102 m_nCurPos = offset + size; 103 return TRUE; 104 } 105 return FALSE; 106 } 107 108 size_t CFPDF_FileStream::ReadBlock(void* buffer, size_t size) { 109 if (!buffer || !size || !m_pFS->ReadBlock) 110 return 0; 111 112 FX_FILESIZE nSize = GetSize(); 113 if (m_nCurPos >= nSize) 114 return 0; 115 FX_FILESIZE dwAvail = nSize - m_nCurPos; 116 if (dwAvail < (FX_FILESIZE)size) 117 size = (size_t)dwAvail; 118 if (m_pFS->ReadBlock(m_pFS->clientData, (FPDF_DWORD)m_nCurPos, buffer, 119 (FPDF_DWORD)size) == 0) { 120 m_nCurPos += size; 121 return size; 122 } 123 124 return 0; 125 } 126 127 FX_BOOL CFPDF_FileStream::WriteBlock(const void* buffer, 128 FX_FILESIZE offset, 129 size_t size) { 130 if (!m_pFS || !m_pFS->WriteBlock) 131 return FALSE; 132 133 if (m_pFS->WriteBlock(m_pFS->clientData, (FPDF_DWORD)offset, buffer, 134 (FPDF_DWORD)size) == 0) { 135 m_nCurPos = offset + size; 136 return TRUE; 137 } 138 return FALSE; 139 } 140 141 FX_BOOL CFPDF_FileStream::Flush() { 142 if (!m_pFS || !m_pFS->Flush) 143 return TRUE; 144 145 return m_pFS->Flush(m_pFS->clientData) == 0; 146 } 147 #endif // PDF_ENABLE_XFA 148 149 CPDF_CustomAccess::CPDF_CustomAccess(FPDF_FILEACCESS* pFileAccess) { 150 m_FileAccess = *pFileAccess; 151 #ifdef PDF_ENABLE_XFA 152 m_BufferOffset = (FX_DWORD)-1; 153 #endif // PDF_ENABLE_XFA 154 } 155 156 #ifdef PDF_ENABLE_XFA 157 FX_BOOL CPDF_CustomAccess::GetByte(FX_DWORD pos, uint8_t& ch) { 158 if (pos >= m_FileAccess.m_FileLen) 159 return FALSE; 160 if (m_BufferOffset == (FX_DWORD)-1 || pos < m_BufferOffset || 161 pos >= m_BufferOffset + 512) { 162 // Need to read from file access 163 m_BufferOffset = pos; 164 int size = 512; 165 if (pos + 512 > m_FileAccess.m_FileLen) 166 size = m_FileAccess.m_FileLen - pos; 167 if (!m_FileAccess.m_GetBlock(m_FileAccess.m_Param, m_BufferOffset, m_Buffer, 168 size)) 169 return FALSE; 170 } 171 ch = m_Buffer[pos - m_BufferOffset]; 172 return TRUE; 173 } 174 175 FX_BOOL CPDF_CustomAccess::GetBlock(FX_DWORD pos, 176 uint8_t* pBuf, 177 FX_DWORD size) { 178 if (pos + size > m_FileAccess.m_FileLen) 179 return FALSE; 180 return m_FileAccess.m_GetBlock(m_FileAccess.m_Param, pos, pBuf, size); 181 } 182 #endif // PDF_ENABLE_XFA 183 184 FX_BOOL CPDF_CustomAccess::ReadBlock(void* buffer, 185 FX_FILESIZE offset, 186 size_t size) { 187 if (offset < 0) { 188 return FALSE; 189 } 190 FX_SAFE_FILESIZE newPos = 191 pdfium::base::checked_cast<FX_FILESIZE, size_t>(size); 192 newPos += offset; 193 if (!newPos.IsValid() || newPos.ValueOrDie() > m_FileAccess.m_FileLen) { 194 return FALSE; 195 } 196 return m_FileAccess.m_GetBlock(m_FileAccess.m_Param, offset, (uint8_t*)buffer, 197 size); 198 } 199 200 // 0 bit: FPDF_POLICY_MACHINETIME_ACCESS 201 static FX_DWORD foxit_sandbox_policy = 0xFFFFFFFF; 202 203 void FSDK_SetSandBoxPolicy(FPDF_DWORD policy, FPDF_BOOL enable) { 204 switch (policy) { 205 case FPDF_POLICY_MACHINETIME_ACCESS: { 206 if (enable) 207 foxit_sandbox_policy |= 0x01; 208 else 209 foxit_sandbox_policy &= 0xFFFFFFFE; 210 } break; 211 default: 212 break; 213 } 214 } 215 216 FPDF_BOOL FSDK_IsSandBoxPolicyEnabled(FPDF_DWORD policy) { 217 switch (policy) { 218 case FPDF_POLICY_MACHINETIME_ACCESS: 219 return !!(foxit_sandbox_policy & 0x01); 220 default: 221 return FALSE; 222 } 223 } 224 225 CCodec_ModuleMgr* g_pCodecModule = nullptr; 226 227 DLLEXPORT void STDCALL FPDF_InitLibrary() { 228 FPDF_InitLibraryWithConfig(nullptr); 229 } 230 231 DLLEXPORT void STDCALL FPDF_InitLibraryWithConfig( 232 const FPDF_LIBRARY_CONFIG* cfg) { 233 g_pCodecModule = new CCodec_ModuleMgr(); 234 235 CFX_GEModule::Create(cfg ? cfg->m_pUserFontPaths : nullptr); 236 CFX_GEModule::Get()->SetCodecModule(g_pCodecModule); 237 238 CPDF_ModuleMgr::Create(); 239 CPDF_ModuleMgr* pModuleMgr = CPDF_ModuleMgr::Get(); 240 pModuleMgr->SetCodecModule(g_pCodecModule); 241 pModuleMgr->InitPageModule(); 242 pModuleMgr->InitRenderModule(); 243 #ifdef PDF_ENABLE_XFA 244 CPDFXFA_App::GetInstance()->Initialize(); 245 #else // PDF_ENABLE_XFA 246 pModuleMgr->LoadEmbeddedGB1CMaps(); 247 pModuleMgr->LoadEmbeddedJapan1CMaps(); 248 pModuleMgr->LoadEmbeddedCNS1CMaps(); 249 pModuleMgr->LoadEmbeddedKorea1CMaps(); 250 #endif // PDF_ENABLE_XFA 251 if (cfg && cfg->version >= 2) 252 IJS_Runtime::Initialize(cfg->m_v8EmbedderSlot, cfg->m_pIsolate); 253 } 254 255 DLLEXPORT void STDCALL FPDF_DestroyLibrary() { 256 #ifdef PDF_ENABLE_XFA 257 CPDFXFA_App::ReleaseInstance(); 258 #endif // PDF_ENABLE_XFA 259 CPDF_ModuleMgr::Destroy(); 260 CFX_GEModule::Destroy(); 261 262 delete g_pCodecModule; 263 g_pCodecModule = nullptr; 264 } 265 266 #ifndef _WIN32 267 int g_LastError; 268 void SetLastError(int err) { 269 g_LastError = err; 270 } 271 272 int GetLastError() { 273 return g_LastError; 274 } 275 #endif // _WIN32 276 277 void ProcessParseError(FX_DWORD err_code) { 278 // Translate FPDFAPI error code to FPDFVIEW error code 279 switch (err_code) { 280 case PDFPARSE_ERROR_FILE: 281 err_code = FPDF_ERR_FILE; 282 break; 283 case PDFPARSE_ERROR_FORMAT: 284 err_code = FPDF_ERR_FORMAT; 285 break; 286 case PDFPARSE_ERROR_PASSWORD: 287 err_code = FPDF_ERR_PASSWORD; 288 break; 289 case PDFPARSE_ERROR_HANDLER: 290 err_code = FPDF_ERR_SECURITY; 291 break; 292 } 293 SetLastError(err_code); 294 } 295 296 DLLEXPORT void STDCALL FPDF_SetSandBoxPolicy(FPDF_DWORD policy, 297 FPDF_BOOL enable) { 298 return FSDK_SetSandBoxPolicy(policy, enable); 299 } 300 301 DLLEXPORT FPDF_DOCUMENT STDCALL FPDF_LoadDocument(FPDF_STRING file_path, 302 FPDF_BYTESTRING password) { 303 // NOTE: the creation of the file needs to be by the embedder on the 304 // other side of this API. 305 IFX_FileRead* pFileAccess = FX_CreateFileRead((const FX_CHAR*)file_path); 306 if (!pFileAccess) { 307 return nullptr; 308 } 309 310 CPDF_Parser* pParser = new CPDF_Parser; 311 pParser->SetPassword(password); 312 313 FX_DWORD err_code = pParser->StartParse(pFileAccess); 314 if (err_code) { 315 delete pParser; 316 ProcessParseError(err_code); 317 return NULL; 318 } 319 #ifdef PDF_ENABLE_XFA 320 CPDF_Document* pPDFDoc = pParser->GetDocument(); 321 if (!pPDFDoc) 322 return NULL; 323 324 CPDFXFA_App* pProvider = CPDFXFA_App::GetInstance(); 325 return new CPDFXFA_Document(pPDFDoc, pProvider); 326 #else // PDF_ENABLE_XFA 327 return pParser->GetDocument(); 328 #endif // PDF_ENABLE_XFA 329 } 330 331 #ifdef PDF_ENABLE_XFA 332 DLLEXPORT FPDF_BOOL STDCALL FPDF_HasXFAField(FPDF_DOCUMENT document, 333 int* docType) { 334 if (!document) 335 return FALSE; 336 337 CPDF_Document* pdfDoc = 338 (static_cast<CPDFXFA_Document*>(document))->GetPDFDoc(); 339 if (!pdfDoc) 340 return FALSE; 341 342 CPDF_Dictionary* pRoot = pdfDoc->GetRoot(); 343 if (!pRoot) 344 return FALSE; 345 346 CPDF_Dictionary* pAcroForm = pRoot->GetDict("AcroForm"); 347 if (!pAcroForm) 348 return FALSE; 349 350 CPDF_Object* pXFA = pAcroForm->GetElement("XFA"); 351 if (!pXFA) 352 return FALSE; 353 354 FX_BOOL bDynamicXFA = pRoot->GetBoolean("NeedsRendering", FALSE); 355 356 if (bDynamicXFA) 357 *docType = DOCTYPE_DYNAMIC_XFA; 358 else 359 *docType = DOCTYPE_STATIC_XFA; 360 361 return TRUE; 362 } 363 364 DLLEXPORT FPDF_BOOL STDCALL FPDF_LoadXFA(FPDF_DOCUMENT document) { 365 return document && (static_cast<CPDFXFA_Document*>(document))->LoadXFADoc(); 366 } 367 #endif // PDF_ENABLE_XFA 368 369 class CMemFile final : public IFX_FileRead { 370 public: 371 CMemFile(uint8_t* pBuf, FX_FILESIZE size) : m_pBuf(pBuf), m_size(size) {} 372 373 void Release() override { delete this; } 374 FX_FILESIZE GetSize() override { return m_size; } 375 FX_BOOL ReadBlock(void* buffer, FX_FILESIZE offset, size_t size) override { 376 if (offset < 0) { 377 return FALSE; 378 } 379 FX_SAFE_FILESIZE newPos = 380 pdfium::base::checked_cast<FX_FILESIZE, size_t>(size); 381 newPos += offset; 382 if (!newPos.IsValid() || newPos.ValueOrDie() > (FX_DWORD)m_size) { 383 return FALSE; 384 } 385 FXSYS_memcpy(buffer, m_pBuf + offset, size); 386 return TRUE; 387 } 388 389 private: 390 ~CMemFile() override {} 391 392 uint8_t* const m_pBuf; 393 const FX_FILESIZE m_size; 394 }; 395 396 DLLEXPORT FPDF_DOCUMENT STDCALL FPDF_LoadMemDocument(const void* data_buf, 397 int size, 398 FPDF_BYTESTRING password) { 399 CPDF_Parser* pParser = new CPDF_Parser; 400 pParser->SetPassword(password); 401 CMemFile* pMemFile = new CMemFile((uint8_t*)data_buf, size); 402 FX_DWORD err_code = pParser->StartParse(pMemFile); 403 if (err_code) { 404 delete pParser; 405 ProcessParseError(err_code); 406 return NULL; 407 } 408 CPDF_Document* pDoc = NULL; 409 pDoc = pParser ? pParser->GetDocument() : NULL; 410 CheckUnSupportError(pDoc, err_code); 411 return FPDFDocumentFromCPDFDocument(pParser->GetDocument()); 412 } 413 414 DLLEXPORT FPDF_DOCUMENT STDCALL 415 FPDF_LoadCustomDocument(FPDF_FILEACCESS* pFileAccess, 416 FPDF_BYTESTRING password) { 417 CPDF_Parser* pParser = new CPDF_Parser; 418 pParser->SetPassword(password); 419 CPDF_CustomAccess* pFile = new CPDF_CustomAccess(pFileAccess); 420 FX_DWORD err_code = pParser->StartParse(pFile); 421 if (err_code) { 422 delete pParser; 423 ProcessParseError(err_code); 424 return NULL; 425 } 426 CPDF_Document* pDoc = NULL; 427 pDoc = pParser ? pParser->GetDocument() : NULL; 428 CheckUnSupportError(pDoc, err_code); 429 return FPDFDocumentFromCPDFDocument(pParser->GetDocument()); 430 } 431 432 DLLEXPORT FPDF_BOOL STDCALL FPDF_GetFileVersion(FPDF_DOCUMENT doc, 433 int* fileVersion) { 434 if (!fileVersion) 435 return FALSE; 436 437 *fileVersion = 0; 438 CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(doc); 439 if (!pDoc) 440 return FALSE; 441 442 CPDF_Parser* pParser = pDoc->GetParser(); 443 if (!pParser) 444 return FALSE; 445 446 *fileVersion = pParser->GetFileVersion(); 447 return TRUE; 448 } 449 450 // jabdelmalek: changed return type from FX_DWORD to build on Linux (and match 451 // header). 452 DLLEXPORT unsigned long STDCALL FPDF_GetDocPermissions(FPDF_DOCUMENT document) { 453 CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document); 454 if (!pDoc) 455 #ifndef PDF_ENABLE_XFA 456 return 0; 457 #else // PDF_ENABLE_XFA 458 return (FX_DWORD)-1; 459 #endif // PDF_ENABLE_XFA 460 461 CPDF_Dictionary* pDict = pDoc->GetParser()->GetEncryptDict(); 462 return pDict ? pDict->GetInteger("P") : (FX_DWORD)-1; 463 } 464 465 DLLEXPORT int STDCALL FPDF_GetSecurityHandlerRevision(FPDF_DOCUMENT document) { 466 CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document); 467 if (!pDoc) 468 return -1; 469 470 CPDF_Dictionary* pDict = pDoc->GetParser()->GetEncryptDict(); 471 return pDict ? pDict->GetInteger("R") : -1; 472 } 473 474 DLLEXPORT int STDCALL FPDF_GetPageCount(FPDF_DOCUMENT document) { 475 UnderlyingDocumentType* pDoc = UnderlyingFromFPDFDocument(document); 476 return pDoc ? pDoc->GetPageCount() : 0; 477 } 478 479 DLLEXPORT FPDF_PAGE STDCALL FPDF_LoadPage(FPDF_DOCUMENT document, 480 int page_index) { 481 UnderlyingDocumentType* pDoc = UnderlyingFromFPDFDocument(document); 482 if (!pDoc) 483 return nullptr; 484 485 if (page_index < 0 || page_index >= pDoc->GetPageCount()) 486 return nullptr; 487 488 #ifdef PDF_ENABLE_XFA 489 return pDoc->GetPage(page_index); 490 #else // PDF_ENABLE_XFA 491 CPDF_Dictionary* pDict = pDoc->GetPage(page_index); 492 if (!pDict) 493 return NULL; 494 CPDF_Page* pPage = new CPDF_Page; 495 pPage->Load(pDoc, pDict); 496 pPage->ParseContent(); 497 return pPage; 498 #endif // PDF_ENABLE_XFA 499 } 500 501 DLLEXPORT double STDCALL FPDF_GetPageWidth(FPDF_PAGE page) { 502 UnderlyingPageType* pPage = UnderlyingFromFPDFPage(page); 503 return pPage ? pPage->GetPageWidth() : 0.0; 504 } 505 506 DLLEXPORT double STDCALL FPDF_GetPageHeight(FPDF_PAGE page) { 507 UnderlyingPageType* pPage = UnderlyingFromFPDFPage(page); 508 return pPage ? pPage->GetPageHeight() : 0.0; 509 } 510 511 void DropContext(void* data) { 512 delete (CRenderContext*)data; 513 } 514 515 #if defined(_DEBUG) || defined(DEBUG) 516 #define DEBUG_TRACE 517 #endif 518 519 #if defined(_WIN32) 520 DLLEXPORT void STDCALL FPDF_RenderPage(HDC dc, 521 FPDF_PAGE page, 522 int start_x, 523 int start_y, 524 int size_x, 525 int size_y, 526 int rotate, 527 int flags) { 528 CPDF_Page* pPage = CPDFPageFromFPDFPage(page); 529 if (!pPage) 530 return; 531 532 CRenderContext* pContext = new CRenderContext; 533 pPage->SetPrivateData((void*)1, pContext, DropContext); 534 535 #ifndef _WIN32_WCE 536 CFX_DIBitmap* pBitmap = nullptr; 537 FX_BOOL bBackgroundAlphaNeeded = pPage->BackgroundAlphaNeeded(); 538 FX_BOOL bHasImageMask = pPage->HasImageMask(); 539 if (bBackgroundAlphaNeeded || bHasImageMask) { 540 pBitmap = new CFX_DIBitmap; 541 pBitmap->Create(size_x, size_y, FXDIB_Argb); 542 pBitmap->Clear(0x00ffffff); 543 #ifdef _SKIA_SUPPORT_ 544 pContext->m_pDevice = new CFX_SkiaDevice; 545 ((CFX_SkiaDevice*)pContext->m_pDevice)->Attach((CFX_DIBitmap*)pBitmap); 546 #else 547 pContext->m_pDevice = new CFX_FxgeDevice; 548 ((CFX_FxgeDevice*)pContext->m_pDevice)->Attach((CFX_DIBitmap*)pBitmap); 549 #endif 550 } else { 551 pContext->m_pDevice = new CFX_WindowsDevice(dc); 552 } 553 554 FPDF_RenderPage_Retail(pContext, page, start_x, start_y, size_x, size_y, 555 rotate, flags, TRUE, NULL); 556 557 if (bBackgroundAlphaNeeded || bHasImageMask) { 558 if (pBitmap) { 559 CFX_WindowsDevice WinDC(dc); 560 561 if (WinDC.GetDeviceCaps(FXDC_DEVICE_CLASS) == FXDC_PRINTER) { 562 CFX_DIBitmap* pDst = new CFX_DIBitmap; 563 int pitch = pBitmap->GetPitch(); 564 pDst->Create(size_x, size_y, FXDIB_Rgb32); 565 FXSYS_memset(pDst->GetBuffer(), -1, pitch * size_y); 566 pDst->CompositeBitmap(0, 0, size_x, size_y, pBitmap, 0, 0, 567 FXDIB_BLEND_NORMAL, NULL, FALSE, NULL); 568 WinDC.StretchDIBits(pDst, 0, 0, size_x, size_y); 569 delete pDst; 570 } else { 571 WinDC.SetDIBits(pBitmap, 0, 0); 572 } 573 } 574 } 575 #else 576 // get clip region 577 RECT rect, cliprect; 578 rect.left = start_x; 579 rect.top = start_y; 580 rect.right = start_x + size_x; 581 rect.bottom = start_y + size_y; 582 GetClipBox(dc, &cliprect); 583 IntersectRect(&rect, &rect, &cliprect); 584 int width = rect.right - rect.left; 585 int height = rect.bottom - rect.top; 586 587 #ifdef DEBUG_TRACE 588 { 589 char str[128]; 590 memset(str, 0, sizeof(str)); 591 FXSYS_snprintf(str, sizeof(str) - 1, "Rendering DIB %d x %d", width, 592 height); 593 CPDF_ModuleMgr::Get()->ReportError(999, str); 594 } 595 #endif 596 597 // Create a DIB section 598 LPVOID pBuffer; 599 BITMAPINFOHEADER bmih; 600 FXSYS_memset(&bmih, 0, sizeof bmih); 601 bmih.biSize = sizeof bmih; 602 bmih.biBitCount = 24; 603 bmih.biHeight = -height; 604 bmih.biPlanes = 1; 605 bmih.biWidth = width; 606 pContext->m_hBitmap = CreateDIBSection(dc, (BITMAPINFO*)&bmih, DIB_RGB_COLORS, 607 &pBuffer, NULL, 0); 608 if (!pContext->m_hBitmap) { 609 #if defined(DEBUG) || defined(_DEBUG) 610 char str[128]; 611 memset(str, 0, sizeof(str)); 612 FXSYS_snprintf(str, sizeof(str) - 1, 613 "Error CreateDIBSection: %d x %d, error code = %d", width, 614 height, GetLastError()); 615 CPDF_ModuleMgr::Get()->ReportError(FPDFERR_OUT_OF_MEMORY, str); 616 #else 617 CPDF_ModuleMgr::Get()->ReportError(FPDFERR_OUT_OF_MEMORY, NULL); 618 #endif 619 } 620 FXSYS_memset(pBuffer, 0xff, height * ((width * 3 + 3) / 4 * 4)); 621 622 #ifdef DEBUG_TRACE 623 { CPDF_ModuleMgr::Get()->ReportError(999, "DIBSection created"); } 624 #endif 625 626 // Create a device with this external buffer 627 pContext->m_pBitmap = new CFX_DIBitmap; 628 pContext->m_pBitmap->Create(width, height, FXDIB_Rgb, (uint8_t*)pBuffer); 629 pContext->m_pDevice = new CPDF_FxgeDevice; 630 ((CPDF_FxgeDevice*)pContext->m_pDevice)->Attach(pContext->m_pBitmap); 631 632 #ifdef DEBUG_TRACE 633 CPDF_ModuleMgr::Get()->ReportError(999, "Ready for PDF rendering"); 634 #endif 635 636 // output to bitmap device 637 FPDF_RenderPage_Retail(pContext, page, start_x - rect.left, 638 start_y - rect.top, size_x, size_y, rotate, flags); 639 640 #ifdef DEBUG_TRACE 641 CPDF_ModuleMgr::Get()->ReportError(999, "Finished PDF rendering"); 642 #endif 643 644 // Now output to real device 645 HDC hMemDC = CreateCompatibleDC(dc); 646 if (!hMemDC) { 647 #if defined(DEBUG) || defined(_DEBUG) 648 char str[128]; 649 memset(str, 0, sizeof(str)); 650 FXSYS_snprintf(str, sizeof(str) - 1, 651 "Error CreateCompatibleDC. Error code = %d", GetLastError()); 652 CPDF_ModuleMgr::Get()->ReportError(FPDFERR_OUT_OF_MEMORY, str); 653 #else 654 CPDF_ModuleMgr::Get()->ReportError(FPDFERR_OUT_OF_MEMORY, NULL); 655 #endif 656 } 657 658 HGDIOBJ hOldBitmap = SelectObject(hMemDC, pContext->m_hBitmap); 659 660 #ifdef DEBUG_TRACE 661 CPDF_ModuleMgr::Get()->ReportError(999, "Ready for screen rendering"); 662 #endif 663 664 BitBlt(dc, rect.left, rect.top, width, height, hMemDC, 0, 0, SRCCOPY); 665 SelectObject(hMemDC, hOldBitmap); 666 DeleteDC(hMemDC); 667 668 #ifdef DEBUG_TRACE 669 CPDF_ModuleMgr::Get()->ReportError(999, "Finished screen rendering"); 670 #endif 671 672 #endif 673 if (bBackgroundAlphaNeeded || bHasImageMask) 674 delete pBitmap; 675 676 delete pContext; 677 pPage->RemovePrivateData((void*)1); 678 } 679 #endif 680 681 DLLEXPORT void STDCALL FPDF_RenderPageBitmap(FPDF_BITMAP bitmap, 682 FPDF_PAGE page, 683 int start_x, 684 int start_y, 685 int size_x, 686 int size_y, 687 int rotate, 688 int flags) { 689 if (!bitmap) 690 return; 691 CPDF_Page* pPage = CPDFPageFromFPDFPage(page); 692 if (!pPage) 693 return; 694 CRenderContext* pContext = new CRenderContext; 695 pPage->SetPrivateData((void*)1, pContext, DropContext); 696 #ifdef _SKIA_SUPPORT_ 697 pContext->m_pDevice = new CFX_SkiaDevice; 698 699 if (flags & FPDF_REVERSE_BYTE_ORDER) 700 ((CFX_SkiaDevice*)pContext->m_pDevice) 701 ->Attach((CFX_DIBitmap*)bitmap, 0, TRUE); 702 else 703 ((CFX_SkiaDevice*)pContext->m_pDevice)->Attach((CFX_DIBitmap*)bitmap); 704 #else 705 pContext->m_pDevice = new CFX_FxgeDevice; 706 707 if (flags & FPDF_REVERSE_BYTE_ORDER) 708 ((CFX_FxgeDevice*)pContext->m_pDevice) 709 ->Attach((CFX_DIBitmap*)bitmap, 0, TRUE); 710 else 711 ((CFX_FxgeDevice*)pContext->m_pDevice)->Attach((CFX_DIBitmap*)bitmap); 712 #endif 713 714 FPDF_RenderPage_Retail(pContext, page, start_x, start_y, size_x, size_y, 715 rotate, flags, TRUE, NULL); 716 717 delete pContext; 718 pPage->RemovePrivateData((void*)1); 719 } 720 721 DLLEXPORT void STDCALL FPDF_ClosePage(FPDF_PAGE page) { 722 if (!page) 723 return; 724 #ifdef PDF_ENABLE_XFA 725 CPDFXFA_Page* pPage = (CPDFXFA_Page*)page; 726 pPage->Release(); 727 #else // PDF_ENABLE_XFA 728 CPDFSDK_PageView* pPageView = 729 (CPDFSDK_PageView*)(((CPDF_Page*)page))->GetPrivateData((void*)page); 730 if (pPageView && pPageView->IsLocked()) { 731 pPageView->TakeOverPage(); 732 return; 733 } 734 delete (CPDF_Page*)page; 735 #endif // PDF_ENABLE_XFA 736 } 737 738 DLLEXPORT void STDCALL FPDF_CloseDocument(FPDF_DOCUMENT document) { 739 #ifdef PDF_ENABLE_XFA 740 delete UnderlyingFromFPDFDocument(document); 741 #else // PDF_ENABLE_XFA 742 CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document); 743 if (!pDoc) 744 return; 745 CPDF_Parser* pParser = pDoc->GetParser(); 746 if (!pParser) { 747 delete pDoc; 748 return; 749 } 750 delete pParser; 751 #endif // PDF_ENABLE_XFA 752 } 753 754 DLLEXPORT unsigned long STDCALL FPDF_GetLastError() { 755 return GetLastError(); 756 } 757 758 DLLEXPORT void STDCALL FPDF_DeviceToPage(FPDF_PAGE page, 759 int start_x, 760 int start_y, 761 int size_x, 762 int size_y, 763 int rotate, 764 int device_x, 765 int device_y, 766 double* page_x, 767 double* page_y) { 768 if (!page || !page_x || !page_y) 769 return; 770 UnderlyingPageType* pPage = UnderlyingFromFPDFPage(page); 771 #ifdef PDF_ENABLE_XFA 772 pPage->DeviceToPage(start_x, start_y, size_x, size_y, rotate, device_x, 773 device_y, page_x, page_y); 774 #else // PDF_ENABLE_XFA 775 CFX_Matrix page2device; 776 pPage->GetDisplayMatrix(page2device, start_x, start_y, size_x, size_y, 777 rotate); 778 CFX_Matrix device2page; 779 device2page.SetReverse(page2device); 780 FX_FLOAT page_x_f, page_y_f; 781 device2page.Transform((FX_FLOAT)(device_x), (FX_FLOAT)(device_y), page_x_f, 782 page_y_f); 783 *page_x = (page_x_f); 784 *page_y = (page_y_f); 785 #endif // PDF_ENABLE_XFA 786 } 787 788 DLLEXPORT void STDCALL FPDF_PageToDevice(FPDF_PAGE page, 789 int start_x, 790 int start_y, 791 int size_x, 792 int size_y, 793 int rotate, 794 double page_x, 795 double page_y, 796 int* device_x, 797 int* device_y) { 798 if (!device_x || !device_y) 799 return; 800 UnderlyingPageType* pPage = UnderlyingFromFPDFPage(page); 801 if (!pPage) 802 return; 803 #ifdef PDF_ENABLE_XFA 804 pPage->PageToDevice(start_x, start_y, size_x, size_y, rotate, page_x, page_y, 805 device_x, device_y); 806 #else // PDF_ENABLE_XFA 807 CFX_Matrix page2device; 808 pPage->GetDisplayMatrix(page2device, start_x, start_y, size_x, size_y, 809 rotate); 810 FX_FLOAT device_x_f, device_y_f; 811 page2device.Transform(((FX_FLOAT)page_x), ((FX_FLOAT)page_y), device_x_f, 812 device_y_f); 813 *device_x = FXSYS_round(device_x_f); 814 *device_y = FXSYS_round(device_y_f); 815 #endif // PDF_ENABLE_XFA 816 } 817 818 DLLEXPORT FPDF_BITMAP STDCALL FPDFBitmap_Create(int width, 819 int height, 820 int alpha) { 821 std::unique_ptr<CFX_DIBitmap> pBitmap(new CFX_DIBitmap); 822 if (!pBitmap->Create(width, height, alpha ? FXDIB_Argb : FXDIB_Rgb32)) { 823 return NULL; 824 } 825 return pBitmap.release(); 826 } 827 828 DLLEXPORT FPDF_BITMAP STDCALL FPDFBitmap_CreateEx(int width, 829 int height, 830 int format, 831 void* first_scan, 832 int stride) { 833 FXDIB_Format fx_format; 834 switch (format) { 835 case FPDFBitmap_Gray: 836 fx_format = FXDIB_8bppRgb; 837 break; 838 case FPDFBitmap_BGR: 839 fx_format = FXDIB_Rgb; 840 break; 841 case FPDFBitmap_BGRx: 842 fx_format = FXDIB_Rgb32; 843 break; 844 case FPDFBitmap_BGRA: 845 fx_format = FXDIB_Argb; 846 break; 847 default: 848 return NULL; 849 } 850 CFX_DIBitmap* pBitmap = new CFX_DIBitmap; 851 pBitmap->Create(width, height, fx_format, (uint8_t*)first_scan, stride); 852 return pBitmap; 853 } 854 855 DLLEXPORT void STDCALL FPDFBitmap_FillRect(FPDF_BITMAP bitmap, 856 int left, 857 int top, 858 int width, 859 int height, 860 FPDF_DWORD color) { 861 if (!bitmap) 862 return; 863 #ifdef _SKIA_SUPPORT_ 864 CFX_SkiaDevice device; 865 #else 866 CFX_FxgeDevice device; 867 #endif 868 device.Attach((CFX_DIBitmap*)bitmap); 869 if (!((CFX_DIBitmap*)bitmap)->HasAlpha()) 870 color |= 0xFF000000; 871 FX_RECT rect(left, top, left + width, top + height); 872 device.FillRect(&rect, color); 873 } 874 875 DLLEXPORT void* STDCALL FPDFBitmap_GetBuffer(FPDF_BITMAP bitmap) { 876 return bitmap ? ((CFX_DIBitmap*)bitmap)->GetBuffer() : nullptr; 877 } 878 879 DLLEXPORT int STDCALL FPDFBitmap_GetWidth(FPDF_BITMAP bitmap) { 880 return bitmap ? ((CFX_DIBitmap*)bitmap)->GetWidth() : 0; 881 } 882 883 DLLEXPORT int STDCALL FPDFBitmap_GetHeight(FPDF_BITMAP bitmap) { 884 return bitmap ? ((CFX_DIBitmap*)bitmap)->GetHeight() : 0; 885 } 886 887 DLLEXPORT int STDCALL FPDFBitmap_GetStride(FPDF_BITMAP bitmap) { 888 return bitmap ? ((CFX_DIBitmap*)bitmap)->GetPitch() : 0; 889 } 890 891 DLLEXPORT void STDCALL FPDFBitmap_Destroy(FPDF_BITMAP bitmap) { 892 delete (CFX_DIBitmap*)bitmap; 893 } 894 895 void FPDF_RenderPage_Retail(CRenderContext* pContext, 896 FPDF_PAGE page, 897 int start_x, 898 int start_y, 899 int size_x, 900 int size_y, 901 int rotate, 902 int flags, 903 FX_BOOL bNeedToRestore, 904 IFSDK_PAUSE_Adapter* pause) { 905 CPDF_Page* pPage = CPDFPageFromFPDFPage(page); 906 if (!pPage) 907 return; 908 909 if (!pContext->m_pOptions) 910 pContext->m_pOptions = new CPDF_RenderOptions; 911 912 if (flags & FPDF_LCD_TEXT) 913 pContext->m_pOptions->m_Flags |= RENDER_CLEARTYPE; 914 else 915 pContext->m_pOptions->m_Flags &= ~RENDER_CLEARTYPE; 916 if (flags & FPDF_NO_NATIVETEXT) 917 pContext->m_pOptions->m_Flags |= RENDER_NO_NATIVETEXT; 918 if (flags & FPDF_RENDER_LIMITEDIMAGECACHE) 919 pContext->m_pOptions->m_Flags |= RENDER_LIMITEDIMAGECACHE; 920 if (flags & FPDF_RENDER_FORCEHALFTONE) 921 pContext->m_pOptions->m_Flags |= RENDER_FORCE_HALFTONE; 922 #ifndef PDF_ENABLE_XFA 923 if (flags & FPDF_RENDER_NO_SMOOTHTEXT) 924 pContext->m_pOptions->m_Flags |= RENDER_NOTEXTSMOOTH; 925 if (flags & FPDF_RENDER_NO_SMOOTHIMAGE) 926 pContext->m_pOptions->m_Flags |= RENDER_NOIMAGESMOOTH; 927 if (flags & FPDF_RENDER_NO_SMOOTHPATH) 928 pContext->m_pOptions->m_Flags |= RENDER_NOPATHSMOOTH; 929 #endif // PDF_ENABLE_XFA 930 // Grayscale output 931 if (flags & FPDF_GRAYSCALE) { 932 pContext->m_pOptions->m_ColorMode = RENDER_COLOR_GRAY; 933 pContext->m_pOptions->m_ForeColor = 0; 934 pContext->m_pOptions->m_BackColor = 0xffffff; 935 } 936 const CPDF_OCContext::UsageType usage = 937 (flags & FPDF_PRINTING) ? CPDF_OCContext::Print : CPDF_OCContext::View; 938 pContext->m_pOptions->m_AddFlags = flags >> 8; 939 pContext->m_pOptions->m_pOCContext = 940 new CPDF_OCContext(pPage->m_pDocument, usage); 941 942 CFX_Matrix matrix; 943 pPage->GetDisplayMatrix(matrix, start_x, start_y, size_x, size_y, rotate); 944 945 FX_RECT clip; 946 clip.left = start_x; 947 clip.right = start_x + size_x; 948 clip.top = start_y; 949 clip.bottom = start_y + size_y; 950 pContext->m_pDevice->SaveState(); 951 pContext->m_pDevice->SetClip_Rect(&clip); 952 953 pContext->m_pContext = new CPDF_RenderContext(pPage); 954 pContext->m_pContext->AppendObjectList(pPage, &matrix); 955 956 if (flags & FPDF_ANNOT) { 957 pContext->m_pAnnots = new CPDF_AnnotList(pPage); 958 FX_BOOL bPrinting = pContext->m_pDevice->GetDeviceClass() != FXDC_DISPLAY; 959 pContext->m_pAnnots->DisplayAnnots(pPage, pContext->m_pContext, bPrinting, 960 &matrix, TRUE, NULL); 961 } 962 963 pContext->m_pRenderer = new CPDF_ProgressiveRenderer( 964 pContext->m_pContext, pContext->m_pDevice, pContext->m_pOptions); 965 pContext->m_pRenderer->Start(pause); 966 if (bNeedToRestore) 967 pContext->m_pDevice->RestoreState(); 968 } 969 970 DLLEXPORT int STDCALL FPDF_GetPageSizeByIndex(FPDF_DOCUMENT document, 971 int page_index, 972 double* width, 973 double* height) { 974 UnderlyingDocumentType* pDoc = UnderlyingFromFPDFDocument(document); 975 if (!pDoc) 976 return FALSE; 977 978 #ifdef PDF_ENABLE_XFA 979 int count = pDoc->GetPageCount(); 980 if (page_index < 0 || page_index >= count) 981 return FALSE; 982 CPDFXFA_Page* pPage = pDoc->GetPage(page_index); 983 if (!pPage) 984 return FALSE; 985 *width = pPage->GetPageWidth(); 986 *height = pPage->GetPageHeight(); 987 #else // PDF_ENABLE_XFA 988 CPDF_Dictionary* pDict = pDoc->GetPage(page_index); 989 if (!pDict) 990 return FALSE; 991 CPDF_Page page; 992 page.Load(pDoc, pDict); 993 *width = page.GetPageWidth(); 994 *height = page.GetPageHeight(); 995 #endif // PDF_ENABLE_XFA 996 997 return TRUE; 998 } 999 1000 DLLEXPORT FPDF_BOOL STDCALL 1001 FPDF_VIEWERREF_GetPrintScaling(FPDF_DOCUMENT document) { 1002 CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document); 1003 if (!pDoc) 1004 return TRUE; 1005 CPDF_ViewerPreferences viewRef(pDoc); 1006 return viewRef.PrintScaling(); 1007 } 1008 1009 DLLEXPORT int STDCALL FPDF_VIEWERREF_GetNumCopies(FPDF_DOCUMENT document) { 1010 CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document); 1011 if (!pDoc) 1012 return 1; 1013 CPDF_ViewerPreferences viewRef(pDoc); 1014 return viewRef.NumCopies(); 1015 } 1016 1017 DLLEXPORT FPDF_PAGERANGE STDCALL 1018 FPDF_VIEWERREF_GetPrintPageRange(FPDF_DOCUMENT document) { 1019 CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document); 1020 if (!pDoc) 1021 return NULL; 1022 CPDF_ViewerPreferences viewRef(pDoc); 1023 return viewRef.PrintPageRange(); 1024 } 1025 1026 DLLEXPORT FPDF_DUPLEXTYPE STDCALL 1027 FPDF_VIEWERREF_GetDuplex(FPDF_DOCUMENT document) { 1028 CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document); 1029 if (!pDoc) 1030 return DuplexUndefined; 1031 CPDF_ViewerPreferences viewRef(pDoc); 1032 CFX_ByteString duplex = viewRef.Duplex(); 1033 if ("Simplex" == duplex) 1034 return Simplex; 1035 if ("DuplexFlipShortEdge" == duplex) 1036 return DuplexFlipShortEdge; 1037 if ("DuplexFlipLongEdge" == duplex) 1038 return DuplexFlipLongEdge; 1039 return DuplexUndefined; 1040 } 1041 1042 DLLEXPORT FPDF_DWORD STDCALL FPDF_CountNamedDests(FPDF_DOCUMENT document) { 1043 CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document); 1044 if (!pDoc) 1045 return 0; 1046 1047 CPDF_Dictionary* pRoot = pDoc->GetRoot(); 1048 if (!pRoot) 1049 return 0; 1050 1051 CPDF_NameTree nameTree(pDoc, "Dests"); 1052 pdfium::base::CheckedNumeric<FPDF_DWORD> count = nameTree.GetCount(); 1053 CPDF_Dictionary* pDest = pRoot->GetDict("Dests"); 1054 if (pDest) 1055 count += pDest->GetCount(); 1056 1057 if (!count.IsValid()) 1058 return 0; 1059 1060 return count.ValueOrDie(); 1061 } 1062 1063 DLLEXPORT FPDF_DEST STDCALL FPDF_GetNamedDestByName(FPDF_DOCUMENT document, 1064 FPDF_BYTESTRING name) { 1065 if (!name || name[0] == 0) 1066 return nullptr; 1067 1068 CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document); 1069 if (!pDoc) 1070 return nullptr; 1071 1072 CPDF_NameTree name_tree(pDoc, "Dests"); 1073 return name_tree.LookupNamedDest(pDoc, name); 1074 } 1075 1076 #ifdef PDF_ENABLE_XFA 1077 FPDF_RESULT FPDF_BStr_Init(FPDF_BSTR* str) { 1078 if (!str) 1079 return -1; 1080 1081 FXSYS_memset(str, 0, sizeof(FPDF_BSTR)); 1082 return 0; 1083 } 1084 1085 FPDF_RESULT FPDF_BStr_Set(FPDF_BSTR* str, FPDF_LPCSTR bstr, int length) { 1086 if (!str) 1087 return -1; 1088 if (!bstr || !length) 1089 return -1; 1090 if (length == -1) 1091 length = FXSYS_strlen(bstr); 1092 1093 if (length == 0) { 1094 if (str->str) { 1095 FX_Free(str->str); 1096 str->str = NULL; 1097 } 1098 str->len = 0; 1099 return 0; 1100 } 1101 1102 if (str->str && str->len < length) 1103 str->str = FX_Realloc(char, str->str, length + 1); 1104 else if (!str->str) 1105 str->str = FX_Alloc(char, length + 1); 1106 1107 str->str[length] = 0; 1108 if (str->str == NULL) 1109 return -1; 1110 1111 FXSYS_memcpy(str->str, bstr, length); 1112 str->len = length; 1113 1114 return 0; 1115 } 1116 1117 FPDF_RESULT FPDF_BStr_Clear(FPDF_BSTR* str) { 1118 if (!str) 1119 return -1; 1120 1121 if (str->str) { 1122 FX_Free(str->str); 1123 str->str = NULL; 1124 } 1125 str->len = 0; 1126 return 0; 1127 } 1128 #endif // PDF_ENABLE_XFA 1129 1130 DLLEXPORT FPDF_DEST STDCALL FPDF_GetNamedDest(FPDF_DOCUMENT document, 1131 int index, 1132 void* buffer, 1133 long* buflen) { 1134 if (!buffer) 1135 *buflen = 0; 1136 1137 if (index < 0) 1138 return nullptr; 1139 1140 CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document); 1141 if (!pDoc) 1142 return nullptr; 1143 1144 CPDF_Dictionary* pRoot = pDoc->GetRoot(); 1145 if (!pRoot) 1146 return nullptr; 1147 1148 CPDF_Object* pDestObj = nullptr; 1149 CFX_ByteString bsName; 1150 CPDF_NameTree nameTree(pDoc, "Dests"); 1151 int count = nameTree.GetCount(); 1152 if (index >= count) { 1153 CPDF_Dictionary* pDest = pRoot->GetDict("Dests"); 1154 if (!pDest) 1155 return nullptr; 1156 1157 pdfium::base::CheckedNumeric<int> checked_count = count; 1158 checked_count += pDest->GetCount(); 1159 if (!checked_count.IsValid() || index >= checked_count.ValueOrDie()) 1160 return nullptr; 1161 1162 index -= count; 1163 int i = 0; 1164 for (const auto& it : *pDest) { 1165 bsName = it.first; 1166 pDestObj = it.second; 1167 if (!pDestObj) 1168 continue; 1169 if (i == index) 1170 break; 1171 i++; 1172 } 1173 } else { 1174 pDestObj = nameTree.LookupValue(index, bsName); 1175 } 1176 if (!pDestObj) 1177 return nullptr; 1178 if (CPDF_Dictionary* pDict = pDestObj->AsDictionary()) { 1179 pDestObj = pDict->GetArray("D"); 1180 if (!pDestObj) 1181 return nullptr; 1182 } 1183 if (!pDestObj->IsArray()) 1184 return nullptr; 1185 1186 CFX_WideString wsName = PDF_DecodeText(bsName); 1187 CFX_ByteString utf16Name = wsName.UTF16LE_Encode(); 1188 unsigned int len = utf16Name.GetLength(); 1189 if (!buffer) { 1190 *buflen = len; 1191 } else if (*buflen >= len) { 1192 memcpy(buffer, utf16Name.c_str(), len); 1193 *buflen = len; 1194 } else { 1195 *buflen = -1; 1196 } 1197 return (FPDF_DEST)pDestObj; 1198 } 1199