Chromium Code Reviews| Index: chrome/utility/chrome_content_utility_client.cc |
| diff --git a/chrome/utility/chrome_content_utility_client.cc b/chrome/utility/chrome_content_utility_client.cc |
| index 3cc0d30c792ce8bd9297edf6b23b1412c8eecf5d..fb0c09441141c8e4fe599bc35e971fe2e16f0476 100644 |
| --- a/chrome/utility/chrome_content_utility_client.cc |
| +++ b/chrome/utility/chrome_content_utility_client.cc |
| @@ -7,12 +7,15 @@ |
| #include "base/base64.h" |
| #include "base/bind.h" |
| #include "base/command_line.h" |
| +#include "base/file_util.h" |
| #include "base/files/file_path.h" |
| #include "base/json/json_reader.h" |
| #include "base/memory/ref_counted.h" |
| #include "base/memory/scoped_ptr.h" |
| #include "base/path_service.h" |
| +#include "base/scoped_native_library.h" |
| #include "base/time/time.h" |
| +#include "chrome/common/chrome_paths.h" |
| #include "chrome/common/chrome_utility_messages.h" |
| #include "chrome/common/extensions/chrome_extensions_client.h" |
| #include "chrome/common/extensions/extension.h" |
| @@ -37,11 +40,8 @@ |
| #include "ui/gfx/size.h" |
| #if defined(OS_WIN) |
| -#include "base/file_util.h" |
| -#include "base/path_service.h" |
| #include "base/win/iat_patch_function.h" |
| #include "base/win/scoped_handle.h" |
| -#include "chrome/common/chrome_paths.h" |
| #include "chrome/utility/media_galleries/itunes_pref_parser_win.h" |
| #include "printing/emf_win.h" |
| #include "ui/gfx/gdi_util.h" |
| @@ -80,6 +80,208 @@ void ReleaseProcessIfNeeded() { |
| content::UtilityThread::Get()->ReleaseProcessIfNeeded(); |
| } |
| +class PdfFunctionsBase { |
| + public: |
| + PdfFunctionsBase() : render_pdf_to_bitmap_(NULL) {} |
| + |
| + bool Init() { |
| + base::FilePath pdf_module_path; |
| + if (!PathService::Get(chrome::FILE_PDF_PLUGIN, &pdf_module_path) && |
|
Lei Zhang
2013/11/14 21:56:54
Shouldn't this be:
if (!PathService::Get() || !Pa
Vitaly Buka (NO REVIEWS)
2013/11/14 22:10:20
Done.
|
| + base::PathExists(pdf_module_path)) { |
| + return false; |
| + } |
| + |
| + pdf_lib_.Reset(base::LoadNativeLibrary(pdf_module_path, NULL)); |
| + if (!pdf_lib_.is_valid()) { |
| + LOG(WARNING) << "Couldn't load PDF plugin"; |
| + return false; |
| + } |
| + |
| + render_pdf_to_bitmap_ = |
| + reinterpret_cast<RenderPDFPageToBitmapProc>( |
| + pdf_lib_.GetFunctionPointer("RenderPDFPageToBitmap")); |
| + LOG_IF(WARNING, !render_pdf_to_bitmap_) << "Missing RenderPDFPageToBitmap"; |
| + |
| + if (!render_pdf_to_bitmap_ || !PlatformInit(pdf_module_path, pdf_lib_)) |
| + Reset(); |
| + |
| + return IsValid(); |
| + } |
| + |
| + bool IsValid() const { |
| + return pdf_lib_.is_valid(); |
| + } |
| + |
| + void Reset() { |
| + pdf_lib_.Reset(NULL); |
| + } |
| + |
| + bool RenderPDFPageToBitmap(const unsigned char* pdf_buffer, |
| + int buffer_size, |
| + int page_number, |
| + unsigned char* bitmap_buffer, |
| + int bitmap_height, |
| + int bitmap_width, |
| + int dpi_x, |
| + int dpi_y, |
| + bool autorotate) { |
| + if (!render_pdf_to_bitmap_) |
| + return false; |
| + return render_pdf_to_bitmap_(pdf_buffer, buffer_size, page_number, |
| + bitmap_buffer, bitmap_height, bitmap_width, |
| + dpi_x, dpi_y, autorotate); |
| + } |
| + |
| + protected: |
| + virtual bool PlatformInit( |
| + const base::FilePath& pdf_module_path, |
| + const base::ScopedNativeLibrary& pdf_lib) { |
| + return true; |
| + }; |
| + |
| + private: |
| + // Exported by pdf.dll |
|
Lei Zhang
2013/11/14 21:56:54
nit: "PDF plugin", since this is non-Windows as we
Vitaly Buka (NO REVIEWS)
2013/11/14 22:10:20
Done.
|
| + typedef bool (*RenderPDFPageToBitmapProc)(const unsigned char* pdf_buffer, |
| + int buffer_size, |
| + int page_number, |
| + unsigned char* bitmap_buffer, |
| + int bitmap_height, |
| + int bitmap_width, |
| + int dpi_x, |
| + int dpi_y, |
| + bool autorotate); |
| + RenderPDFPageToBitmapProc render_pdf_to_bitmap_; |
|
Lei Zhang
2013/11/14 21:56:54
render_pdf_to_bitmap_func_ ?
"render_pdf_to_bitmap
Vitaly Buka (NO REVIEWS)
2013/11/14 22:10:20
Done.
|
| + |
| + base::ScopedNativeLibrary pdf_lib_; |
| + DISALLOW_COPY_AND_ASSIGN(PdfFunctionsBase); |
| +}; |
| + |
| +#if defined(OS_WIN) |
| +// The 2 below IAT patch functions are almost identical to the code in |
| +// render_process_impl.cc. This is needed to work around specific Windows APIs |
| +// used by the Chrome PDF plugin that will fail in the sandbox. |
| +static base::win::IATPatchFunction g_iat_patch_createdca; |
| +HDC WINAPI UtilityProcess_CreateDCAPatch(LPCSTR driver_name, |
| + LPCSTR device_name, |
| + LPCSTR output, |
| + const DEVMODEA* init_data) { |
| + if (driver_name && (std::string("DISPLAY") == driver_name)) { |
| + // CreateDC fails behind the sandbox, but not CreateCompatibleDC. |
| + return CreateCompatibleDC(NULL); |
| + } |
| + |
| + NOTREACHED(); |
| + return CreateDCA(driver_name, device_name, output, init_data); |
| +} |
| + |
| +static base::win::IATPatchFunction g_iat_patch_get_font_data; |
| +DWORD WINAPI UtilityProcess_GetFontDataPatch( |
| + HDC hdc, DWORD table, DWORD offset, LPVOID buffer, DWORD length) { |
| + int rv = GetFontData(hdc, table, offset, buffer, length); |
| + if (rv == GDI_ERROR && hdc) { |
| + HFONT font = static_cast<HFONT>(GetCurrentObject(hdc, OBJ_FONT)); |
| + |
| + LOGFONT logfont; |
| + if (GetObject(font, sizeof(LOGFONT), &logfont)) { |
| + content::UtilityThread::Get()->PreCacheFont(logfont); |
| + rv = GetFontData(hdc, table, offset, buffer, length); |
| + content::UtilityThread::Get()->ReleaseCachedFonts(); |
| + } |
| + } |
| + return rv; |
| +} |
| + |
| +class PdfFunctionsWin : public PdfFunctionsBase { |
| + public: |
| + PdfFunctionsWin() : render_pdf_to_dc_(NULL), |
| + get_pdf_doc_info_(NULL) { |
| + } |
| + |
| + bool PlatformInit( |
| + const base::FilePath& pdf_module_path, |
| + const base::ScopedNativeLibrary& pdf_lib) OVERRIDE { |
| + // Patch the IAT for handling specific APIs known to fail in the sandbox. |
| + if (!g_iat_patch_createdca.is_patched()) { |
| + g_iat_patch_createdca.Patch(pdf_module_path.value().c_str(), |
| + "gdi32.dll", "CreateDCA", |
| + UtilityProcess_CreateDCAPatch); |
| + } |
| + |
| + if (!g_iat_patch_get_font_data.is_patched()) { |
| + g_iat_patch_get_font_data.Patch(pdf_module_path.value().c_str(), |
| + "gdi32.dll", "GetFontData", |
| + UtilityProcess_GetFontDataPatch); |
| + } |
| + render_pdf_to_dc_ = |
| + reinterpret_cast<RenderPDFPageToDCProc>( |
| + pdf_lib.GetFunctionPointer("RenderPDFPageToDC")); |
| + LOG_IF(WARNING, !render_pdf_to_dc_) << "Missing RenderPDFPageToDC"; |
| + |
| + get_pdf_doc_info_ = |
| + reinterpret_cast<GetPDFDocInfoProc>( |
| + pdf_lib.GetFunctionPointer("GetPDFDocInfo")); |
| + LOG_IF(WARNING, !get_pdf_doc_info_) << "Missing GetPDFDocInfo"; |
| + return render_pdf_to_dc_ && get_pdf_doc_info_; |
| + } |
| + |
| + bool RenderPDFPageToDC(const unsigned char* 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 (!render_pdf_to_dc_) |
| + return false; |
| + return render_pdf_to_dc_(pdf_buffer, buffer_size, page_number, |
| + dc, dpi_x, dpi_y, bounds_origin_x, bounds_origin_y, |
| + bounds_width, bounds_height, fit_to_bounds, |
| + stretch_to_bounds, keep_aspect_ratio, |
| + center_in_bounds, autorotate); |
| + } |
| + |
| + bool GetPDFDocInfo(const unsigned char* pdf_buffer, |
| + int buffer_size, |
| + int* page_count, |
| + double* max_page_width) { |
| + if (!get_pdf_doc_info_) |
| + return false; |
| + return get_pdf_doc_info_(pdf_buffer, buffer_size, page_count, |
| + max_page_width); |
| + } |
| + |
| + private: |
| + // Exported by pdf.dll |
| + typedef bool (*RenderPDFPageToDCProc)( |
| + const unsigned char* 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); |
| + typedef bool (*GetPDFDocInfoProc)(const unsigned char* pdf_buffer, |
| + int buffer_size, int* page_count, |
| + double* max_page_width); |
| + RenderPDFPageToDCProc render_pdf_to_dc_; |
| + GetPDFDocInfoProc get_pdf_doc_info_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(PdfFunctionsWin); |
| +}; |
| + |
| +typedef PdfFunctionsWin PdfFunctions; |
| +#else // OS_WIN |
| +typedef PdfFunctionsBase PdfFunctions; |
| +#endif // OS_WIN |
| + |
| +static base::LazyInstance<PdfFunctions> g_pdf_lib = LAZY_INSTANCE_INITIALIZER; |
| + |
| } // namespace |
| ChromeContentUtilityClient::ChromeContentUtilityClient() { |
| @@ -99,17 +301,6 @@ ChromeContentUtilityClient::~ChromeContentUtilityClient() { |
| } |
| void ChromeContentUtilityClient::UtilityThreadStarted() { |
| -#if defined(OS_WIN) |
| - // Load the pdf plugin before the sandbox is turned on. This is for Windows |
| - // only because we need this DLL only on Windows. |
| - base::FilePath pdf; |
| - if (PathService::Get(chrome::FILE_PDF_PLUGIN, &pdf) && |
| - base::PathExists(pdf)) { |
| - bool rv = !!LoadLibrary(pdf.value().c_str()); |
| - DCHECK(rv) << "Couldn't load PDF plugin"; |
| - } |
| -#endif |
| - |
| CommandLine* command_line = CommandLine::ForCurrentProcess(); |
| std::string lang = command_line->GetSwitchValueASCII(switches::kLang); |
| if (!lang.empty()) |
| @@ -182,6 +373,8 @@ void ChromeContentUtilityClient::PreSandboxStartup() { |
| local_discovery::ServiceDiscoveryMessageHandler::PreSandboxStartup(); |
| #endif // ENABLE_MDNS |
| + g_pdf_lib.Get().Init(); |
| + |
| // Load media libraries for media file validation. |
| base::FilePath media_path; |
| PathService::Get(content::DIR_MEDIA_LIBS, &media_path); |
| @@ -332,51 +525,6 @@ void ChromeContentUtilityClient::OnRenderPDFPagesToMetafile( |
| } |
| #if defined(OS_WIN) |
| -// Exported by pdf.dll |
| -typedef bool (*RenderPDFPageToDCProc)( |
| - const unsigned char* 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); |
| - |
| -typedef bool (*GetPDFDocInfoProc)(const unsigned char* pdf_buffer, |
| - int buffer_size, int* page_count, |
| - double* max_page_width); |
| - |
| -// The 2 below IAT patch functions are almost identical to the code in |
| -// render_process_impl.cc. This is needed to work around specific Windows APIs |
| -// used by the Chrome PDF plugin that will fail in the sandbox. |
| -static base::win::IATPatchFunction g_iat_patch_createdca; |
| -HDC WINAPI UtilityProcess_CreateDCAPatch(LPCSTR driver_name, |
| - LPCSTR device_name, |
| - LPCSTR output, |
| - const DEVMODEA* init_data) { |
| - if (driver_name && |
| - (std::string("DISPLAY") == std::string(driver_name))) |
| - // CreateDC fails behind the sandbox, but not CreateCompatibleDC. |
| - return CreateCompatibleDC(NULL); |
| - |
| - NOTREACHED(); |
| - return CreateDCA(driver_name, device_name, output, init_data); |
| -} |
| - |
| -static base::win::IATPatchFunction g_iat_patch_get_font_data; |
| -DWORD WINAPI UtilityProcess_GetFontDataPatch( |
| - HDC hdc, DWORD table, DWORD offset, LPVOID buffer, DWORD length) { |
| - int rv = GetFontData(hdc, table, offset, buffer, length); |
| - if (rv == GDI_ERROR && hdc) { |
| - HFONT font = static_cast<HFONT>(GetCurrentObject(hdc, OBJ_FONT)); |
| - |
| - LOGFONT logfont; |
| - if (GetObject(font, sizeof(LOGFONT), &logfont)) { |
| - content::UtilityThread::Get()->PreCacheFont(logfont); |
| - rv = GetFontData(hdc, table, offset, buffer, length); |
| - content::UtilityThread::Get()->ReleaseCachedFonts(); |
| - } |
| - } |
| - return rv; |
| -} |
| bool ChromeContentUtilityClient::RenderPDFToWinMetafile( |
| base::PlatformFile pdf_file, |
| @@ -390,34 +538,10 @@ bool ChromeContentUtilityClient::RenderPDFToWinMetafile( |
| *highest_rendered_page_number = -1; |
| *scale_factor = 1.0; |
| base::win::ScopedHandle file(pdf_file); |
| - base::FilePath pdf_module_path; |
| - PathService::Get(chrome::FILE_PDF_PLUGIN, &pdf_module_path); |
| - HMODULE pdf_module = GetModuleHandle(pdf_module_path.value().c_str()); |
| - if (!pdf_module) |
| - return false; |
| - RenderPDFPageToDCProc render_proc = |
| - reinterpret_cast<RenderPDFPageToDCProc>( |
| - GetProcAddress(pdf_module, "RenderPDFPageToDC")); |
| - if (!render_proc) |
| + if (!g_pdf_lib.Get().IsValid()) |
| return false; |
| - GetPDFDocInfoProc get_info_proc = reinterpret_cast<GetPDFDocInfoProc>( |
| - GetProcAddress(pdf_module, "GetPDFDocInfo")); |
| - if (!get_info_proc) |
| - return false; |
| - |
| - // Patch the IAT for handling specific APIs known to fail in the sandbox. |
| - if (!g_iat_patch_createdca.is_patched()) |
| - g_iat_patch_createdca.Patch(pdf_module_path.value().c_str(), |
| - "gdi32.dll", "CreateDCA", |
| - UtilityProcess_CreateDCAPatch); |
| - |
| - if (!g_iat_patch_get_font_data.is_patched()) |
| - g_iat_patch_get_font_data.Patch(pdf_module_path.value().c_str(), |
| - "gdi32.dll", "GetFontData", |
| - UtilityProcess_GetFontDataPatch); |
| - |
| // TODO(sanjeevr): Add a method to the PDF DLL that takes in a file handle |
| // and a page range array. That way we don't need to read the entire PDF into |
| // memory. |
| @@ -429,12 +553,15 @@ bool ChromeContentUtilityClient::RenderPDFToWinMetafile( |
| buffer.resize(length); |
| DWORD bytes_read = 0; |
| if (!ReadFile(pdf_file, &buffer.front(), length, &bytes_read, NULL) || |
| - (bytes_read != length)) |
| + (bytes_read != length)) { |
| return false; |
| + } |
| int total_page_count = 0; |
| - if (!get_info_proc(&buffer.front(), buffer.size(), &total_page_count, NULL)) |
| + if (!g_pdf_lib.Get().GetPDFDocInfo(&buffer.front(), buffer.size(), |
| + &total_page_count, NULL)) { |
| return false; |
| + } |
| printing::Emf metafile; |
| metafile.InitToFile(metafile_path); |
| @@ -459,14 +586,15 @@ bool ChromeContentUtilityClient::RenderPDFToWinMetafile( |
| // The underlying metafile is of type Emf and ignores the arguments passed |
| // to StartPage. |
| metafile.StartPage(gfx::Size(), gfx::Rect(), 1); |
| - if (render_proc(&buffer.front(), buffer.size(), page_number, |
| - metafile.context(), render_dpi, render_dpi, |
| - render_area.x(), render_area.y(), render_area.width(), |
| - render_area.height(), true, false, true, true, |
| - autorotate)) |
| + if (g_pdf_lib.Get().RenderPDFPageToDC( |
| + &buffer.front(), buffer.size(), page_number, metafile.context(), |
| + render_dpi, render_dpi, render_area.x(), render_area.y(), |
| + render_area.width(), render_area.height(), true, false, true, |
| + true, autorotate)) { |
| if (*highest_rendered_page_number < page_number) |
| *highest_rendered_page_number = page_number; |
| ret = true; |
| + } |
| metafile.FinishPage(); |
| } |
| } |