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
18bool 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)
31HMODULE g_hmodule;
32
33void 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
43void HandlePureVirtualCall() {
44  // Do the same as Chrome's CHECK(false) which is undefined.
45  ::base::debug::BreakDebugger();
46  return;
47}
48
49
50BOOL 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
65namespace pp {
66
67PDF_USED Module* CreateModule() {
68  return new chrome_pdf::PDFModule();
69}
70
71}  // namespace pp
72
73namespace chrome_pdf {
74
75PDFModule::PDFModule() {
76}
77
78PDFModule::~PDFModule() {
79  if (g_sdk_initialized_via_pepper) {
80    chrome_pdf::ShutdownSDK();
81    g_sdk_initialized_via_pepper = false;
82  }
83}
84
85bool PDFModule::Init() {
86  return true;
87}
88
89pp::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
107extern "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 value
121//     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 page.
124// |fit_to_bounds| specifies whether the output should be shrunk to fit the
125//     supplied bounds if the page size is larger than the bounds in any
126//     dimension. If this is false, parts of the PDF page that lie outside the
127//     bounds will be clipped.
128// |stretch_to_bounds| specifies whether the output should be stretched to fit
129//     the supplied bounds if the page size is smaller than the bounds in any
130//     dimension.
131// If both |fit_to_bounds| and |stretch_to_bounds| are true, then
132//     |fit_to_bounds| is honored first.
133// |keep_aspect_ratio| If any scaling is to be done is true, this flag specifies
134//     whether the original aspect ratio of the page should be preserved while
135//     scaling.
136// |center_in_bounds| specifies whether the final image (after any scaling is
137//     done) should be centered within the given bounds.
138// |autorotate| specifies whether the final image should be rotated to match
139//     the output bound.
140// Returns false if the document or the page number are not valid.
141PP_EXPORT bool RenderPDFPageToDC(const void* pdf_buffer,
142                                 int buffer_size,
143                                 int page_number,
144                                 HDC dc,
145                                 int dpi_x,
146                                 int dpi_y,
147                                 int bounds_origin_x,
148                                 int bounds_origin_y,
149                                 int bounds_width,
150                                 int bounds_height,
151                                 bool fit_to_bounds,
152                                 bool stretch_to_bounds,
153                                 bool keep_aspect_ratio,
154                                 bool center_in_bounds,
155                                 bool autorotate) {
156  if (!g_sdk_initialized_via_pepper) {
157    if (!chrome_pdf::InitializeSDK(g_hmodule)) {
158      return false;
159    }
160  }
161  scoped_ptr<chrome_pdf::PDFEngineExports> engine_exports(
162      chrome_pdf::PDFEngineExports::Create());
163  chrome_pdf::PDFEngineExports::RenderingSettings settings(
164      dpi_x, dpi_y, pp::Rect(bounds_origin_x, bounds_origin_y, bounds_width,
165                             bounds_height),
166      fit_to_bounds, stretch_to_bounds, keep_aspect_ratio, center_in_bounds,
167      autorotate);
168  bool ret = engine_exports->RenderPDFPageToDC(pdf_buffer, buffer_size,
169                                               page_number, settings, dc);
170  if (!g_sdk_initialized_via_pepper) {
171    chrome_pdf::ShutdownSDK();
172  }
173  return ret;
174}
175
176#endif  // OS_WIN
177
178// |page_count| and |max_page_width| are optional and can be NULL.
179// Returns false if the document is not valid.
180PDF_USED PP_EXPORT
181bool GetPDFDocInfo(const void* pdf_buffer,
182                   int buffer_size, int* page_count,
183                   double* max_page_width) {
184  if (!g_sdk_initialized_via_pepper) {
185    void* data = NULL;
186#if defined(OS_WIN)
187    data = g_hmodule;
188#endif
189    if (!chrome_pdf::InitializeSDK(data))
190      return false;
191  }
192  scoped_ptr<chrome_pdf::PDFEngineExports> engine_exports(
193      chrome_pdf::PDFEngineExports::Create());
194  bool ret = engine_exports->GetPDFDocInfo(
195      pdf_buffer, buffer_size, page_count, max_page_width);
196  if (!g_sdk_initialized_via_pepper) {
197    chrome_pdf::ShutdownSDK();
198  }
199  return ret;
200}
201
202// Renders PDF page into 4-byte per pixel BGRA color bitmap.
203// |pdf_buffer| is the buffer that contains the entire PDF document to be
204//     rendered.
205// |pdf_buffer_size| is the size of pdf_buffer in bytes.
206// |page_number| is the 0-based index of the page to be rendered.
207// |bitmap_buffer| is the output buffer for bitmap.
208// |bitmap_width| is the width of the output bitmap.
209// |bitmap_height| is the height of the output bitmap.
210// |dpi| is the resolutions.
211// |autorotate| specifies whether the final image should be rotated to match
212//     the output bound.
213// Returns false if the document or the page number are not valid.
214PDF_USED PP_EXPORT
215bool RenderPDFPageToBitmap(const void* pdf_buffer,
216                           int pdf_buffer_size,
217                           int page_number,
218                           void* bitmap_buffer,
219                           int bitmap_width,
220                           int bitmap_height,
221                           int dpi,
222                           bool autorotate) {
223  if (!g_sdk_initialized_via_pepper) {
224    void* data = NULL;
225#if defined(OS_WIN)
226    data = g_hmodule;
227#endif
228    if (!chrome_pdf::InitializeSDK(data))
229      return false;
230  }
231  scoped_ptr<chrome_pdf::PDFEngineExports> engine_exports(
232      chrome_pdf::PDFEngineExports::Create());
233  chrome_pdf::PDFEngineExports::RenderingSettings settings(
234      dpi, dpi, pp::Rect(bitmap_width, bitmap_height), true, false, true, true,
235      autorotate);
236  bool ret = engine_exports->RenderPDFPageToBitmap(
237      pdf_buffer, pdf_buffer_size, page_number, settings, bitmap_buffer);
238  if (!g_sdk_initialized_via_pepper) {
239    chrome_pdf::ShutdownSDK();
240  }
241  return ret;
242}
243
244}  // extern "C"
245