XFA: merge patch from CL 826633002, fix windows printing black rectangle issue
[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                                 int pitch = pBitmap->GetPitch();
523                                 pDst->Create(size_x, size_y, FXDIB_Rgb32);
524                                 FXSYS_memset(pDst->GetBuffer(), -1, pitch*size_y);
525                                 pDst->CompositeBitmap(0, 0, size_x, size_y, pBitmap, 0, 0, FXDIB_BLEND_NORMAL, NULL, FALSE, NULL);
526                                 WinDC.StretchDIBits(pDst,0,0,size_x,size_y);
527                                 delete pDst;
528                         }
529                         else
530                                 WinDC.SetDIBits(pBitmap,0,0);
531
532                 }
533         }
534 #else
535         // get clip region
536         RECT rect, cliprect;
537         rect.left = start_x;
538         rect.top = start_y;
539         rect.right = start_x + size_x;
540         rect.bottom = start_y + size_y;
541         GetClipBox(dc, &cliprect);
542         IntersectRect(&rect, &rect, &cliprect);
543         int width = rect.right - rect.left;
544         int height = rect.bottom - rect.top;
545
546 #ifdef DEBUG_TRACE
547         {
548                 char str[128];
549                 sprintf(str, "Rendering DIB %d x %d", width, height);
550                 CPDF_ModuleMgr::Get()->ReportError(999, str);
551         }
552 #endif
553
554         // Create a DIB section
555         LPVOID pBuffer;
556         BITMAPINFOHEADER bmih;
557         FXSYS_memset(&bmih, 0, sizeof bmih);
558         bmih.biSize = sizeof bmih;
559         bmih.biBitCount = 24;
560         bmih.biHeight = -height;
561         bmih.biPlanes = 1;
562         bmih.biWidth = width;
563         pContext->m_hBitmap = CreateDIBSection(dc, (BITMAPINFO*)&bmih, DIB_RGB_COLORS, &pBuffer, NULL, 0);
564         if (pContext->m_hBitmap == NULL) {
565 #if defined(DEBUG) || defined(_DEBUG)
566                 char str[128];
567                 sprintf(str, "Error CreateDIBSection: %d x %d, error code = %d", width, height, GetLastError());
568                 CPDF_ModuleMgr::Get()->ReportError(FPDFERR_OUT_OF_MEMORY, str);
569 #else
570                 CPDF_ModuleMgr::Get()->ReportError(FPDFERR_OUT_OF_MEMORY, NULL);
571 #endif
572         }
573         FXSYS_memset(pBuffer, 0xff, height*((width*3+3)/4*4));
574
575 #ifdef DEBUG_TRACE
576         {
577                 CPDF_ModuleMgr::Get()->ReportError(999, "DIBSection created");
578         }
579 #endif
580
581         // Create a device with this external buffer
582         pContext->m_pBitmap = FX_NEW CFX_DIBitmap;
583         pContext->m_pBitmap->Create(width, height, FXDIB_Rgb, (FX_LPBYTE)pBuffer);
584         pContext->m_pDevice = FX_NEW CPDF_FxgeDevice;
585         ((CPDF_FxgeDevice*)pContext->m_pDevice)->Attach(pContext->m_pBitmap);
586         
587 #ifdef DEBUG_TRACE
588         CPDF_ModuleMgr::Get()->ReportError(999, "Ready for PDF rendering");
589 #endif
590
591         // output to bitmap device
592         Func_RenderPage(pContext, page, start_x - rect.left, start_y - rect.top, size_x, size_y, rotate, flags);
593
594 #ifdef DEBUG_TRACE
595         CPDF_ModuleMgr::Get()->ReportError(999, "Finished PDF rendering");
596 #endif
597
598         // Now output to real device
599         HDC hMemDC = CreateCompatibleDC(dc);
600         if (hMemDC == NULL) {
601 #if defined(DEBUG) || defined(_DEBUG)
602                 char str[128];
603                 sprintf(str, "Error CreateCompatibleDC. Error code = %d", GetLastError());
604                 CPDF_ModuleMgr::Get()->ReportError(FPDFERR_OUT_OF_MEMORY, str);
605 #else
606                 CPDF_ModuleMgr::Get()->ReportError(FPDFERR_OUT_OF_MEMORY, NULL);
607 #endif
608         }
609
610         HGDIOBJ hOldBitmap = SelectObject(hMemDC, pContext->m_hBitmap);
611
612 #ifdef DEBUG_TRACE
613         CPDF_ModuleMgr::Get()->ReportError(999, "Ready for screen rendering");
614 #endif
615
616         BitBlt(dc, rect.left, rect.top, width, height, hMemDC, 0, 0, SRCCOPY);
617         SelectObject(hMemDC, hOldBitmap);
618         DeleteDC(hMemDC);
619
620 #ifdef DEBUG_TRACE
621         CPDF_ModuleMgr::Get()->ReportError(999, "Finished screen rendering");
622 #endif
623
624 #endif
625         if (bBackgroundAlphaNeeded)
626         {
627                 if (pBitmap)
628                         delete pBitmap;
629                 pBitmap = NULL;
630         }
631         delete pContext;
632         pPage->RemovePrivateData((void*)1);
633 }
634 #endif
635
636 DLLEXPORT void STDCALL FPDF_RenderPageBitmap(FPDF_BITMAP bitmap, FPDF_PAGE page, int start_x, int start_y, 
637                                                 int size_x, int size_y, int rotate, int flags)
638 {
639         if (bitmap == NULL || page == NULL) return;
640         CPDF_Page* pPage = ((CPDFXFA_Page*)page)->GetPDFPage();
641         if (!pPage) return;
642
643         CRenderContext* pContext = FX_NEW CRenderContext;
644         pPage->SetPrivateData((void*)1, pContext, DropContext);
645 #ifdef _SKIA_SUPPORT_
646         pContext->m_pDevice = FX_NEW CFX_SkiaDevice;
647
648         if (flags & FPDF_REVERSE_BYTE_ORDER)
649                 ((CFX_SkiaDevice*)pContext->m_pDevice)->Attach((CFX_DIBitmap*)bitmap,0,TRUE);
650         else
651                 ((CFX_SkiaDevice*)pContext->m_pDevice)->Attach((CFX_DIBitmap*)bitmap);
652 #else
653         pContext->m_pDevice = FX_NEW CFX_FxgeDevice;
654
655         if (flags & FPDF_REVERSE_BYTE_ORDER)
656                 ((CFX_FxgeDevice*)pContext->m_pDevice)->Attach((CFX_DIBitmap*)bitmap,0,TRUE);
657         else
658                 ((CFX_FxgeDevice*)pContext->m_pDevice)->Attach((CFX_DIBitmap*)bitmap);
659 #endif
660
661         Func_RenderPage(pContext, page, start_x, start_y, size_x, size_y, rotate, flags,TRUE,NULL);
662
663         delete pContext;
664         pPage->RemovePrivateData((void*)1);
665 }
666
667 DLLEXPORT void STDCALL FPDF_ClosePage(FPDF_PAGE page)
668 {
669         if (!page) return;
670         CPDFXFA_Page* pPage = (CPDFXFA_Page*)page;
671         
672         pPage->Release();
673 //      CPDFXFA_Document* pDoc = pPage->GetDocument();
674 //      if (pDoc) {
675 //              pDoc->RemovePage(pPage);
676 //      }
677 //      delete (CPDFXFA_Page*)page;
678
679 }
680
681 DLLEXPORT void STDCALL FPDF_CloseDocument(FPDF_DOCUMENT document)
682 {
683         if (!document)
684                 return;
685         CPDFXFA_Document* pDoc = (CPDFXFA_Document*)document;   
686         delete pDoc;
687
688 //      CPDF_Parser* pParser = (CPDF_Parser*)pDoc->GetParser();
689 //      if (pParser == NULL) 
690 //      {
691 //              delete pDoc;
692 //              return;
693 //      }
694 //      delete pParser;
695 //      delete pDoc;
696 }
697
698 DLLEXPORT unsigned long STDCALL FPDF_GetLastError()
699 {
700         return GetLastError();
701 }
702
703 DLLEXPORT void STDCALL FPDF_DeviceToPage(FPDF_PAGE page, int start_x, int start_y, int size_x, int size_y,
704                                                 int rotate, int device_x, int device_y, double* page_x, double* page_y)
705 {
706         if (page == NULL || page_x == NULL || page_y == NULL) return;
707         CPDFXFA_Page* pPage = (CPDFXFA_Page*)page;
708
709         pPage->DeviceToPage(start_x, start_y, size_x, size_y, rotate, device_x, device_y, page_x, page_y);
710 }
711
712 DLLEXPORT void STDCALL FPDF_PageToDevice(FPDF_PAGE page, int start_x, int start_y, int size_x, int size_y,
713                                                 int rotate, double page_x, double page_y, int* device_x, int* device_y)
714 {
715         if (page == NULL || device_x == NULL || device_y == NULL) return;
716         CPDFXFA_Page* pPage = (CPDFXFA_Page*)page;
717         pPage->PageToDevice(start_x, start_y, size_x, size_y, rotate, page_x, page_y, device_x, device_y);
718 }
719
720 DLLEXPORT FPDF_BITMAP STDCALL FPDFBitmap_Create(int width, int height, int alpha)
721 {
722         CFX_DIBitmap* pBitmap = FX_NEW CFX_DIBitmap;
723         pBitmap->Create(width, height, alpha ? FXDIB_Argb : FXDIB_Rgb32);
724         return pBitmap;
725 }
726
727 DLLEXPORT FPDF_BITMAP STDCALL FPDFBitmap_CreateEx(int width, int height, int format, void* first_scan, int stride)
728 {
729         FXDIB_Format fx_format;
730         switch (format) {
731                 case FPDFBitmap_Gray:
732                         fx_format = FXDIB_8bppRgb;
733                         break;
734                 case FPDFBitmap_BGR:
735                         fx_format = FXDIB_Rgb;
736                         break;
737                 case FPDFBitmap_BGRx:
738                         fx_format = FXDIB_Rgb32;
739                         break;
740                 case FPDFBitmap_BGRA:
741                         fx_format = FXDIB_Argb;
742                         break;
743                 default:
744                         return NULL;
745         }
746         CFX_DIBitmap* pBitmap = FX_NEW CFX_DIBitmap;
747         pBitmap->Create(width, height, fx_format, (FX_LPBYTE)first_scan, stride);
748         return pBitmap;
749 }
750
751 DLLEXPORT void STDCALL FPDFBitmap_FillRect(FPDF_BITMAP bitmap, int left, int top, int width, int height, FPDF_DWORD color)
752 {
753         if (bitmap == NULL) return;
754 #ifdef _SKIA_SUPPORT_
755         CFX_SkiaDevice device;
756 #else
757         CFX_FxgeDevice device;
758 #endif
759         device.Attach((CFX_DIBitmap*)bitmap);
760         if (!((CFX_DIBitmap*)bitmap)->HasAlpha()) color |= 0xFF000000;
761         FX_RECT rect(left, top, left+width, top+height);
762         device.FillRect(&rect, color);
763 }
764
765 DLLEXPORT void* STDCALL FPDFBitmap_GetBuffer(FPDF_BITMAP bitmap)
766 {
767         if (bitmap == NULL) return NULL;
768         return ((CFX_DIBitmap*)bitmap)->GetBuffer();
769 }
770
771 DLLEXPORT int STDCALL FPDFBitmap_GetWidth(FPDF_BITMAP bitmap)
772 {
773         if (bitmap == NULL) return 0;
774         return ((CFX_DIBitmap*)bitmap)->GetWidth();
775 }
776
777 DLLEXPORT int STDCALL FPDFBitmap_GetHeight(FPDF_BITMAP bitmap)
778 {
779         if (bitmap == NULL) return 0;
780         return ((CFX_DIBitmap*)bitmap)->GetHeight();
781 }
782
783 DLLEXPORT int STDCALL FPDFBitmap_GetStride(FPDF_BITMAP bitmap)
784 {
785         if (bitmap == NULL) return 0;
786         return ((CFX_DIBitmap*)bitmap)->GetPitch();
787 }
788
789 DLLEXPORT void STDCALL FPDFBitmap_Destroy(FPDF_BITMAP bitmap)
790 {
791         if (bitmap == NULL) return;
792         delete (CFX_DIBitmap*)bitmap;
793 }
794
795 void FPDF_RenderPage_Retail(CRenderContext* pContext, FPDF_PAGE page, int start_x, int start_y, int size_x, int size_y,
796                                                 int rotate, int flags,FX_BOOL bNeedToRestore, IFSDK_PAUSE_Adapter * pause )
797 {
798         CPDF_Page* pPage = ((CPDFXFA_Page*)page)->GetPDFPage();
799         if (pPage == NULL) return;
800
801         if (!pContext->m_pOptions)
802                 pContext->m_pOptions = new CPDF_RenderOptions;
803 //      CPDF_RenderOptions options;
804         if (flags & FPDF_LCD_TEXT)
805                 pContext->m_pOptions->m_Flags |= RENDER_CLEARTYPE;
806         else
807                 pContext->m_pOptions->m_Flags &= ~RENDER_CLEARTYPE;
808         if (flags & FPDF_NO_NATIVETEXT)
809                 pContext->m_pOptions->m_Flags |= RENDER_NO_NATIVETEXT;
810         if (flags & FPDF_RENDER_LIMITEDIMAGECACHE)
811                 pContext->m_pOptions->m_Flags |= RENDER_LIMITEDIMAGECACHE;
812         if (flags & FPDF_RENDER_FORCEHALFTONE)
813                 pContext->m_pOptions->m_Flags |= RENDER_FORCE_HALFTONE;
814         //Grayscale output
815         if (flags & FPDF_GRAYSCALE)
816         {
817                 pContext->m_pOptions->m_ColorMode = RENDER_COLOR_GRAY;
818                 pContext->m_pOptions->m_ForeColor = 0;
819                 pContext->m_pOptions->m_BackColor = 0xffffff;
820         }
821         const CPDF_OCContext::UsageType usage = (flags & FPDF_PRINTING) ? CPDF_OCContext::Print : CPDF_OCContext::View;
822
823         pContext->m_pOptions->m_AddFlags = flags >> 8;
824
825         pContext->m_pOptions->m_pOCContext = new CPDF_OCContext(pPage->m_pDocument, usage);
826
827
828         CFX_AffineMatrix matrix;
829         pPage->GetDisplayMatrix(matrix, start_x, start_y, size_x, size_y, rotate); 
830
831         FX_RECT clip;
832         clip.left = start_x;
833         clip.right = start_x + size_x;
834         clip.top = start_y;
835         clip.bottom = start_y + size_y;
836         pContext->m_pDevice->SaveState();
837         pContext->m_pDevice->SetClip_Rect(&clip);
838
839         pContext->m_pContext = FX_NEW CPDF_RenderContext;
840         pContext->m_pContext->Create(pPage);
841         pContext->m_pContext->AppendObjectList(pPage, &matrix);
842
843         if (flags & FPDF_ANNOT) {
844                 pContext->m_pAnnots = FX_NEW CPDF_AnnotList(pPage);
845                 FX_BOOL bPrinting = pContext->m_pDevice->GetDeviceClass() != FXDC_DISPLAY;
846                 pContext->m_pAnnots->DisplayAnnots(pPage, pContext->m_pContext, bPrinting, &matrix, TRUE, NULL);
847         }
848
849         pContext->m_pRenderer = FX_NEW CPDF_ProgressiveRenderer;
850         pContext->m_pRenderer->Start(pContext->m_pContext, pContext->m_pDevice, pContext->m_pOptions, pause);
851         if (bNeedToRestore)
852         {
853           pContext->m_pDevice->RestoreState();
854         }
855         
856 //#endif
857 }
858
859 DLLEXPORT int STDCALL FPDF_GetPageSizeByIndex(FPDF_DOCUMENT document, int page_index, double* width, double* height)
860 {
861 //      CPDF_Document* pDoc = (CPDF_Document*)document;
862 //      if(pDoc == NULL)
863 //              return FALSE;
864 // 
865 //      CPDF_Dictionary* pDict = pDoc->GetPage(page_index);
866 //      if (pDict == NULL) return FALSE;
867 // 
868 //      CPDF_Page page;
869 //      page.Load(pDoc, pDict);
870 //      *width = page.GetPageWidth();
871 //      *height = page.GetPageHeight();
872
873         CPDFXFA_Document* pDoc = (CPDFXFA_Document*)document;
874         if (pDoc == NULL)
875                 return FALSE;
876
877         int count = pDoc->GetPageCount();
878         if (page_index < 0 || page_index >= count)
879                 return FALSE;
880
881         CPDFXFA_Page* pPage = pDoc->GetPage(page_index);
882         if (!pPage)
883                 return FALSE;
884
885         *width = pPage->GetPageWidth();
886         *height = pPage->GetPageHeight();
887
888         return TRUE;
889 }
890
891 DLLEXPORT FPDF_BOOL STDCALL FPDF_VIEWERREF_GetPrintScaling(FPDF_DOCUMENT document)
892 {
893         CPDFXFA_Document* pDoc = (CPDFXFA_Document*)document;
894         if (!pDoc) return TRUE;
895         CPDF_Document* pPDFDoc = pDoc->GetPDFDoc();
896         if (!pPDFDoc) return TRUE;
897         CPDF_ViewerPreferences viewRef(pPDFDoc);
898         return viewRef.PrintScaling();
899 }
900
901 DLLEXPORT int STDCALL FPDF_VIEWERREF_GetNumCopies(FPDF_DOCUMENT document)
902 {
903     CPDF_Document* pDoc = (CPDF_Document*)document;
904     if (!pDoc) return 1;
905     CPDF_ViewerPreferences viewRef(pDoc);
906     return viewRef.NumCopies();
907 }
908
909 DLLEXPORT FPDF_PAGERANGE STDCALL FPDF_VIEWERREF_GetPrintPageRange(FPDF_DOCUMENT document)
910 {
911     CPDF_Document* pDoc = (CPDF_Document*)document;
912     if (!pDoc) return NULL;
913     CPDF_ViewerPreferences viewRef(pDoc);
914     return viewRef.PrintPageRange();
915 }
916
917 DLLEXPORT FPDF_DUPLEXTYPE STDCALL FPDF_VIEWERREF_GetDuplex(FPDF_DOCUMENT document)
918 {
919     CPDF_Document* pDoc = (CPDF_Document*)document;
920     if (!pDoc) return DuplexUndefined;
921     CPDF_ViewerPreferences viewRef(pDoc);
922     CFX_ByteString duplex = viewRef.Duplex();
923     if (FX_BSTRC("Simplex") == duplex)
924         return Simplex;
925     if (FX_BSTRC("DuplexFlipShortEdge") == duplex)
926         return DuplexFlipShortEdge;
927     if (FX_BSTRC("DuplexFlipLongEdge") == duplex)
928         return DuplexFlipLongEdge;
929     return DuplexUndefined;
930 }
931
932 DLLEXPORT FPDF_DEST STDCALL FPDF_GetNamedDestByName(FPDF_DOCUMENT document,FPDF_BYTESTRING name)
933 {
934         if (document == NULL)
935                 return NULL;
936         if (name == NULL || 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 }