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