// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "pdf/pdf.h"
#if defined(OS_WIN)
#include <windows.h>
#endif
#include "base/command_line.h"
#include "base/logging.h"
#include "pdf/instance.h"
#include "pdf/out_of_process_instance.h"
#include "ppapi/c/ppp.h"
#include "ppapi/cpp/private/pdf.h"
bool g_sdk_initialized_via_pepper = false;
// The Mac release builds discard CreateModule and the entire PDFModule
// definition because they are not referenced here. This causes the Pepper
// exports (PPP_GetInterface etc) to not be exported. So we force the linker
// to include this code by using __attribute__((used)).
#if __GNUC__ >= 4
#define PDF_USED __attribute__((used))
#else
#define PDF_USED
#endif
#if defined(OS_WIN)
HMODULE g_hmodule;
void HandleInvalidParameter(const wchar_t* expression,
const wchar_t* function,
const wchar_t* file,
unsigned int line,
uintptr_t reserved) {
// Do the same as Chrome's CHECK(false) which is undefined.
::base::debug::BreakDebugger();
return;
}
void HandlePureVirtualCall() {
// Do the same as Chrome's CHECK(false) which is undefined.
::base::debug::BreakDebugger();
return;
}
BOOL APIENTRY DllMain(HMODULE module, DWORD reason_for_call, LPVOID reserved) {
g_hmodule = module;
if (reason_for_call == DLL_PROCESS_ATTACH) {
// On windows following handlers work only inside module. So breakpad in
// chrome.dll does not catch that. To avoid linking related code or
// duplication breakpad_win.cc::InitCrashReporter() just catch errors here
// and crash in a way interceptable by breakpad of parent module.
_set_invalid_parameter_handler(HandleInvalidParameter);
_set_purecall_handler(HandlePureVirtualCall);
}
return TRUE;
}
#endif
namespace pp {
PDF_USED Module* CreateModule() {
return new chrome_pdf::PDFModule();
}
} // namespace pp
namespace chrome_pdf {
PDFModule::PDFModule() {
}
PDFModule::~PDFModule() {
if (g_sdk_initialized_via_pepper) {
chrome_pdf::ShutdownSDK();
g_sdk_initialized_via_pepper = false;
}
}
bool PDFModule::Init() {
return true;
}
pp::Instance* PDFModule::CreateInstance(PP_Instance instance) {
if (!g_sdk_initialized_via_pepper) {
void* data = NULL;
#if defined(OS_WIN)
data = g_hmodule;
#endif
if (!chrome_pdf::InitializeSDK(data))
return NULL;
g_sdk_initialized_via_pepper = true;
}
if (pp::PDF::IsOutOfProcess(pp::InstanceHandle(instance)))
return new OutOfProcessInstance(instance);
return new Instance(instance);
}
} // namespace chrome_pdf
extern "C" {
// TODO(sanjeevr): It might make sense to provide more stateful wrappers over
// the internal PDF SDK (such as LoadDocument, LoadPage etc). Determine if we
// need to provide this.
// Wrapper exports over the PDF engine that can be used by an external module
// such as Chrome (since Chrome cannot directly pull in PDFium sources).
#if defined(OS_WIN)
// |pdf_buffer| is the buffer that contains the entire PDF document to be
// rendered.
// |buffer_size| is the size of pdf_buffer in bytes.
// |page_number| is the 0-based index of the page to be rendered.
// |dc| is the device context to render into.
// |dpi_x| and |dpi_y| are the x and y resolutions respectively. If either value
// is -1, the dpi from the DC will be used.
// |bounds_origin_x|, |bounds_origin_y|, |bounds_width| and |bounds_height|
// specify a bounds rectangle within the DC in which to render the PDF page.
// |fit_to_bounds| specifies whether the output should be shrunk to fit the
// supplied bounds if the page size is larger than the bounds in any
// dimension. If this is false, parts of the PDF page that lie outside the
// bounds will be clipped.
// |stretch_to_bounds| specifies whether the output should be stretched to fit
// the supplied bounds if the page size is smaller than the bounds in any
// dimension.
// If both |fit_to_bounds| and |stretch_to_bounds| are true, then
// |fit_to_bounds| is honored first.
// |keep_aspect_ratio| If any scaling is to be done is true, this flag specifies
// whether the original aspect ratio of the page should be preserved while
// scaling.
// |center_in_bounds| specifies whether the final image (after any scaling is
// done) should be centered within the given bounds.
// |autorotate| specifies whether the final image should be rotated to match
// the output bound.
// Returns false if the document or the page number are not valid.
PP_EXPORT bool RenderPDFPageToDC(const void* pdf_buffer,
int buffer_size,
int page_number,
HDC dc,
int dpi_x,
int dpi_y,
int bounds_origin_x,
int bounds_origin_y,
int bounds_width,
int bounds_height,
bool fit_to_bounds,
bool stretch_to_bounds,
bool keep_aspect_ratio,
bool center_in_bounds,
bool autorotate) {
if (!g_sdk_initialized_via_pepper) {
if (!chrome_pdf::InitializeSDK(g_hmodule)) {
return false;
}
}
scoped_ptr<chrome_pdf::PDFEngineExports> engine_exports(
chrome_pdf::PDFEngineExports::Create());
chrome_pdf::PDFEngineExports::RenderingSettings settings(
dpi_x, dpi_y, pp::Rect(bounds_origin_x, bounds_origin_y, bounds_width,
bounds_height),
fit_to_bounds, stretch_to_bounds, keep_aspect_ratio, center_in_bounds,
autorotate);
bool ret = engine_exports->RenderPDFPageToDC(pdf_buffer, buffer_size,
page_number, settings, dc);
if (!g_sdk_initialized_via_pepper) {
chrome_pdf::ShutdownSDK();
}
return ret;
}
#endif // OS_WIN
// |page_count| and |max_page_width| are optional and can be NULL.
// Returns false if the document is not valid.
PDF_USED PP_EXPORT
bool GetPDFDocInfo(const void* pdf_buffer,
int buffer_size, int* page_count,
double* max_page_width) {
if (!g_sdk_initialized_via_pepper) {
void* data = NULL;
#if defined(OS_WIN)
data = g_hmodule;
#endif
if (!chrome_pdf::InitializeSDK(data))
return false;
}
scoped_ptr<chrome_pdf::PDFEngineExports> engine_exports(
chrome_pdf::PDFEngineExports::Create());
bool ret = engine_exports->GetPDFDocInfo(
pdf_buffer, buffer_size, page_count, max_page_width);
if (!g_sdk_initialized_via_pepper) {
chrome_pdf::ShutdownSDK();
}
return ret;
}
// Renders PDF page into 4-byte per pixel BGRA color bitmap.
// |pdf_buffer| is the buffer that contains the entire PDF document to be
// rendered.
// |pdf_buffer_size| is the size of pdf_buffer in bytes.
// |page_number| is the 0-based index of the page to be rendered.
// |bitmap_buffer| is the output buffer for bitmap.
// |bitmap_width| is the width of the output bitmap.
// |bitmap_height| is the height of the output bitmap.
// |dpi| is the resolutions.
// |autorotate| specifies whether the final image should be rotated to match
// the output bound.
// Returns false if the document or the page number are not valid.
PDF_USED PP_EXPORT
bool RenderPDFPageToBitmap(const void* pdf_buffer,
int pdf_buffer_size,
int page_number,
void* bitmap_buffer,
int bitmap_width,
int bitmap_height,
int dpi,
bool autorotate) {
if (!g_sdk_initialized_via_pepper) {
void* data = NULL;
#if defined(OS_WIN)
data = g_hmodule;
#endif
if (!chrome_pdf::InitializeSDK(data))
return false;
}
scoped_ptr<chrome_pdf::PDFEngineExports> engine_exports(
chrome_pdf::PDFEngineExports::Create());
chrome_pdf::PDFEngineExports::RenderingSettings settings(
dpi, dpi, pp::Rect(bitmap_width, bitmap_height), true, false, true, true,
autorotate);
bool ret = engine_exports->RenderPDFPageToBitmap(
pdf_buffer, pdf_buffer_size, page_number, settings, bitmap_buffer);
if (!g_sdk_initialized_via_pepper) {
chrome_pdf::ShutdownSDK();
}
return ret;
}
} // extern "C"