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