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" 276