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