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