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