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