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 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. 142PP_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. 181PDF_USED PP_EXPORT 182bool 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. 212PDF_USED PP_EXPORT 213bool 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. 245PDF_USED PP_EXPORT 246bool 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" 276