Home | History | Annotate | Download | only in pdf
      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