Merge XFA to PDFium master at 4dc95e7 on 10/28/2014
[pdfium.git] / xfa_test / pdf / pdf.cc
1 // Copyright (c) 2010 The Chromium 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 #include "pdf/pdf.h"
6
7 #if defined(OS_WIN)
8 #include <windows.h>
9 #endif
10
11 #include "base/command_line.h"
12 #include "base/logging.h"
13 #include "pdf/instance.h"
14 #include "pdf/out_of_process_instance.h"
15 #include "ppapi/c/ppp.h"
16 #include "ppapi/cpp/private/pdf.h"
17
18 bool g_sdk_initialized_via_pepper = false;
19
20 // The Mac release builds discard CreateModule and the entire PDFModule
21 // definition because they are not referenced here. This causes the Pepper
22 // exports (PPP_GetInterface etc) to not be exported. So we force the linker
23 // to include this code by using __attribute__((used)).
24 #if __GNUC__ >= 4
25 #define PDF_USED __attribute__((used))
26 #else
27 #define PDF_USED
28 #endif
29
30 #if defined(OS_WIN)
31 HMODULE g_hmodule;
32
33 void HandleInvalidParameter(const wchar_t* expression,
34                             const wchar_t* function,
35                             const wchar_t* file,
36                             unsigned int line,
37                             uintptr_t reserved) {
38   // Do the same as Chrome's CHECK(false) which is undefined.
39   ::base::debug::BreakDebugger();
40   return;
41 }
42
43 void HandlePureVirtualCall() {
44   // Do the same as Chrome's CHECK(false) which is undefined.
45   ::base::debug::BreakDebugger();
46   return;
47 }
48
49
50 BOOL APIENTRY DllMain(HMODULE module, DWORD reason_for_call, LPVOID reserved) {
51   g_hmodule = module;
52   if (reason_for_call == DLL_PROCESS_ATTACH) {
53     // On windows following handlers work only inside module. So breakpad in
54     // chrome.dll does not catch that. To avoid linking related code or
55     // duplication breakpad_win.cc::InitCrashReporter() just catch errors here
56     // and crash in a way interceptable by breakpad of parent module.
57     _set_invalid_parameter_handler(HandleInvalidParameter);
58     _set_purecall_handler(HandlePureVirtualCall);
59   }
60   return TRUE;
61 }
62
63 #endif
64
65 namespace pp {
66
67 PDF_USED Module* CreateModule() {
68   return new chrome_pdf::PDFModule();
69 }
70
71 }  // namespace pp
72
73 namespace chrome_pdf {
74
75 PDFModule::PDFModule() {
76 }
77
78 PDFModule::~PDFModule() {
79   if (g_sdk_initialized_via_pepper) {
80     chrome_pdf::ShutdownSDK();
81     g_sdk_initialized_via_pepper = false;
82   }
83 }
84
85 bool PDFModule::Init() {
86   return true;
87 }
88
89 pp::Instance* PDFModule::CreateInstance(PP_Instance instance) {
90   if (!g_sdk_initialized_via_pepper) {
91     void* data = NULL;
92 #if defined(OS_WIN)
93     data = g_hmodule;
94 #endif
95     if (!chrome_pdf::InitializeSDK(data))
96       return NULL;
97     g_sdk_initialized_via_pepper = true;
98   }
99
100   if (pp::PDF::IsOutOfProcess(pp::InstanceHandle(instance)))
101     return new OutOfProcessInstance(instance);
102   return new Instance(instance);
103 }
104
105 }  // namespace chrome_pdf
106
107 extern "C" {
108
109 // TODO(sanjeevr): It might make sense to provide more stateful wrappers over
110 // the internal PDF SDK (such as LoadDocument, LoadPage etc). Determine if we
111 // need to provide this.
112 // Wrapper exports over the PDF engine that can be used by an external module
113 // such as Chrome (since Chrome cannot directly pull in PDFium sources).
114 #if defined(OS_WIN)
115 // |pdf_buffer| is the buffer that contains the entire PDF document to be
116 //     rendered.
117 // |buffer_size| is the size of |pdf_buffer| in bytes.
118 // |page_number| is the 0-based index of the page to be rendered.
119 // |dc| is the device context to render into.
120 // |dpi_x| and |dpi_y| are the x and y resolutions respectively. If either
121 //     value is -1, the dpi from the DC will be used.
122 // |bounds_origin_x|, |bounds_origin_y|, |bounds_width| and |bounds_height|
123 //     specify a bounds rectangle within the DC in which to render the PDF
124 //     page.
125 // |fit_to_bounds| specifies whether the output should be shrunk to fit the
126 //     supplied bounds if the page size is larger than the bounds in any
127 //     dimension. If this is false, parts of the PDF page that lie outside
128 //     the bounds will be clipped.
129 // |stretch_to_bounds| specifies whether the output should be stretched to fit
130 //     the supplied bounds if the page size is smaller than the bounds in any
131 //     dimension.
132 // If both |fit_to_bounds| and |stretch_to_bounds| are true, then
133 //     |fit_to_bounds| is honored first.
134 // |keep_aspect_ratio| If any scaling is to be done is true, this flag
135 //     specifies whether the original aspect ratio of the page should be
136 //     preserved while scaling.
137 // |center_in_bounds| specifies whether the final image (after any scaling is
138 //     done) should be centered within the given bounds.
139 // |autorotate| specifies whether the final image should be rotated to match
140 //     the output bound.
141 // Returns false if the document or the page number are not valid.
142 PP_EXPORT bool RenderPDFPageToDC(const void* pdf_buffer,
143                                  int buffer_size,
144                                  int page_number,
145                                  HDC dc,
146                                  int dpi_x,
147                                  int dpi_y,
148                                  int bounds_origin_x,
149                                  int bounds_origin_y,
150                                  int bounds_width,
151                                  int bounds_height,
152                                  bool fit_to_bounds,
153                                  bool stretch_to_bounds,
154                                  bool keep_aspect_ratio,
155                                  bool center_in_bounds,
156                                  bool autorotate) {
157   if (!g_sdk_initialized_via_pepper) {
158     if (!chrome_pdf::InitializeSDK(g_hmodule)) {
159       return false;
160     }
161   }
162   scoped_ptr<chrome_pdf::PDFEngineExports> engine_exports(
163       chrome_pdf::PDFEngineExports::Create());
164   chrome_pdf::PDFEngineExports::RenderingSettings settings(
165       dpi_x, dpi_y, pp::Rect(bounds_origin_x, bounds_origin_y, bounds_width,
166                              bounds_height),
167       fit_to_bounds, stretch_to_bounds, keep_aspect_ratio, center_in_bounds,
168       autorotate);
169   bool ret = engine_exports->RenderPDFPageToDC(pdf_buffer, buffer_size,
170                                                page_number, settings, dc);
171   if (!g_sdk_initialized_via_pepper) {
172     chrome_pdf::ShutdownSDK();
173   }
174   return ret;
175 }
176
177 #endif  // OS_WIN
178
179 // |page_count| and |max_page_width| are optional and can be NULL.
180 // Returns false if the document is not valid.
181 PDF_USED PP_EXPORT
182 bool GetPDFDocInfo(const void* pdf_buffer,
183                    int buffer_size, int* page_count,
184                    double* max_page_width) {
185   if (!g_sdk_initialized_via_pepper) {
186     void* data = NULL;
187 #if defined(OS_WIN)
188     data = g_hmodule;
189 #endif
190     if (!chrome_pdf::InitializeSDK(data))
191       return false;
192   }
193   scoped_ptr<chrome_pdf::PDFEngineExports> engine_exports(
194       chrome_pdf::PDFEngineExports::Create());
195   bool ret = engine_exports->GetPDFDocInfo(
196       pdf_buffer, buffer_size, page_count, max_page_width);
197   if (!g_sdk_initialized_via_pepper) {
198     chrome_pdf::ShutdownSDK();
199   }
200   return ret;
201 }
202
203 // Gets the dimensions of a specific page in a document.
204 // |pdf_buffer| is the buffer that contains the entire PDF document to be
205 //     rendered.
206 // |pdf_buffer_size| is the size of |pdf_buffer| in bytes.
207 // |page_number| is the page number that the function will get the dimensions
208 //     of.
209 // |width| is the output for the width of the page in points.
210 // |height| is the output for the height of the page in points.
211 // Returns false if the document or the page number are not valid.
212 PDF_USED PP_EXPORT
213 bool GetPDFPageSizeByIndex(const void* pdf_buffer,
214                            int pdf_buffer_size, int page_number,
215                            double* width, double* height) {
216   if (!g_sdk_initialized_via_pepper) {
217     void* data = NULL;
218 #if defined(OS_WIN)
219     data = g_hmodule;
220 #endif
221     if (!chrome_pdf::InitializeSDK(data))
222       return false;
223   }
224   scoped_ptr<chrome_pdf::PDFEngineExports> engine_exports(
225       chrome_pdf::PDFEngineExports::Create());
226   bool ret = engine_exports->GetPDFPageSizeByIndex(
227       pdf_buffer, pdf_buffer_size, page_number, width, height);
228   if (!g_sdk_initialized_via_pepper)
229     chrome_pdf::ShutdownSDK();
230   return ret;
231 }
232
233 // Renders PDF page into 4-byte per pixel BGRA color bitmap.
234 // |pdf_buffer| is the buffer that contains the entire PDF document to be
235 //     rendered.
236 // |pdf_buffer_size| is the size of |pdf_buffer| in bytes.
237 // |page_number| is the 0-based index of the page to be rendered.
238 // |bitmap_buffer| is the output buffer for bitmap.
239 // |bitmap_width| is the width of the output bitmap.
240 // |bitmap_height| is the height of the output bitmap.
241 // |dpi| is the resolutions.
242 // |autorotate| specifies whether the final image should be rotated to match
243 //     the output bound.
244 // Returns false if the document or the page number are not valid.
245 PDF_USED PP_EXPORT
246 bool RenderPDFPageToBitmap(const void* pdf_buffer,
247                            int pdf_buffer_size,
248                            int page_number,
249                            void* bitmap_buffer,
250                            int bitmap_width,
251                            int bitmap_height,
252                            int dpi,
253                            bool autorotate) {
254   if (!g_sdk_initialized_via_pepper) {
255     void* data = NULL;
256 #if defined(OS_WIN)
257     data = g_hmodule;
258 #endif
259     if (!chrome_pdf::InitializeSDK(data))
260       return false;
261   }
262   scoped_ptr<chrome_pdf::PDFEngineExports> engine_exports(
263       chrome_pdf::PDFEngineExports::Create());
264   chrome_pdf::PDFEngineExports::RenderingSettings settings(
265       dpi, dpi, pp::Rect(bitmap_width, bitmap_height), true, false, true, true,
266       autorotate);
267   bool ret = engine_exports->RenderPDFPageToBitmap(
268       pdf_buffer, pdf_buffer_size, page_number, settings, bitmap_buffer);
269   if (!g_sdk_initialized_via_pepper) {
270     chrome_pdf::ShutdownSDK();
271   }
272   return ret;
273 }
274
275 }  // extern "C"