summaryrefslogtreecommitdiffstats
path: root/chrome/utility
diff options
context:
space:
mode:
authorsanjeevr@chromium.org <sanjeevr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-07-20 00:15:43 +0000
committersanjeevr@chromium.org <sanjeevr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-07-20 00:15:43 +0000
commit130954003bdd03f9c3ae563a2ed67466528e71c5 (patch)
treec59200233fd6fdaeec0c6279efa5fdba2493f402 /chrome/utility
parent8a871374acb440a7d35a7b6c10840c7a2f712b65 (diff)
downloadchromium_src-130954003bdd03f9c3ae563a2ed67466528e71c5.zip
chromium_src-130954003bdd03f9c3ae563a2ed67466528e71c5.tar.gz
chromium_src-130954003bdd03f9c3ae563a2ed67466528e71c5.tar.bz2
Created a host for running the utility process as a child of the service process. This is used for rendering PDFs to a metafile in a sandbox for the Cloud Print proxy on Windows.
BUG=None TEST=Test Windows Cloud Print proxy Review URL: http://codereview.chromium.org/2917013 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@52970 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/utility')
-rw-r--r--chrome/utility/utility_main.cc14
-rw-r--r--chrome/utility/utility_thread.cc171
-rw-r--r--chrome/utility/utility_thread.h29
3 files changed, 213 insertions, 1 deletions
diff --git a/chrome/utility/utility_main.cc b/chrome/utility/utility_main.cc
index a568566..09d0156 100644
--- a/chrome/utility/utility_main.cc
+++ b/chrome/utility/utility_main.cc
@@ -6,10 +6,13 @@
#include "app/hi_res_timer_manager.h"
#include "app/system_monitor.h"
#include "base/command_line.h"
+#include "base/file_util.h"
#include "base/message_loop.h"
+#include "base/path_service.h"
#include "base/string_util.h"
#include "chrome/common/child_process.h"
#include "chrome/common/chrome_constants.h"
+#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/extensions/extension_l10n_util.h"
#include "chrome/common/logging_chrome.h"
@@ -19,7 +22,7 @@
#if defined(OS_WIN)
#include "chrome/common/sandbox_init_wrapper.h"
#include "sandbox/src/sandbox.h"
-#endif
+#endif // defined(OS_WIN)
// Mainline routine for running as the utility process.
int UtilityMain(const MainFunctionParams& parameters) {
@@ -33,6 +36,15 @@ int UtilityMain(const MainFunctionParams& parameters) {
ChildProcess utility_process;
utility_process.set_main_thread(new UtilityThread());
#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.
+ FilePath pdf;
+ if (PathService::Get(chrome::FILE_PDF_PLUGIN, &pdf) &&
+ file_util::PathExists(pdf)) {
+ bool rv = !!LoadLibrary(pdf.value().c_str());
+ DCHECK(rv) << "Couldn't load PDF plugin";
+ }
+
sandbox::TargetServices* target_services =
parameters.sandbox_info_.TargetServices();
if (!target_services)
diff --git a/chrome/utility/utility_thread.cc b/chrome/utility/utility_thread.cc
index 259b185..eccda40 100644
--- a/chrome/utility/utility_thread.cc
+++ b/chrome/utility/utility_thread.cc
@@ -7,15 +7,25 @@
#include <vector>
#include "base/file_util.h"
+#if defined(OS_WIN)
+#include "base/iat_patch.h"
+#endif
+#include "base/path_service.h"
#include "base/values.h"
#include "chrome/common/child_process.h"
+#include "chrome/common/chrome_paths.h"
#include "chrome/common/extensions/extension_unpacker.h"
#include "chrome/common/extensions/update_manifest.h"
#include "chrome/common/utility_messages.h"
#include "chrome/common/web_resource/web_resource_unpacker.h"
+#include "gfx/rect.h"
+#include "printing/native_metafile.h"
+#include "printing/page_range.h"
+#include "printing/units.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "webkit/glue/image_decoder.h"
+
UtilityThread::UtilityThread() {
ChildProcess::current()->AddRefProcess();
}
@@ -29,6 +39,8 @@ void UtilityThread::OnControlMessageReceived(const IPC::Message& msg) {
IPC_MESSAGE_HANDLER(UtilityMsg_UnpackWebResource, OnUnpackWebResource)
IPC_MESSAGE_HANDLER(UtilityMsg_ParseUpdateManifest, OnParseUpdateManifest)
IPC_MESSAGE_HANDLER(UtilityMsg_DecodeImage, OnDecodeImage)
+ IPC_MESSAGE_HANDLER(UtilityMsg_RenderPDFPagesToMetafile,
+ OnRenderPDFPagesToMetafile)
IPC_END_MESSAGE_MAP()
}
@@ -84,3 +96,162 @@ void UtilityThread::OnDecodeImage(
ChildProcess::current()->ReleaseProcess();
}
+
+void UtilityThread::OnRenderPDFPagesToMetafile(
+ base::PlatformFile pdf_file,
+ const gfx::Rect& render_area,
+ int render_dpi,
+ const std::vector<printing::PageRange>& page_ranges) {
+ bool succeeded = false;
+#if defined(OS_WIN)
+ printing::NativeMetafile metafile;
+ int highest_rendered_page_number = 0;
+ succeeded = RenderPDFToWinMetafile(pdf_file, render_area, render_dpi,
+ page_ranges, &metafile,
+ &highest_rendered_page_number);
+ if (succeeded) {
+ Send(new UtilityHostMsg_RenderPDFPagesToMetafile_Succeeded(metafile,
+ highest_rendered_page_number));
+ }
+#endif // defined(OS_WIN)
+ if (!succeeded) {
+ Send(new UtilityHostMsg_RenderPDFPagesToMetafile_Failed());
+ }
+ ChildProcess::current()->ReleaseProcess();
+}
+
+#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);
+
+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 iat_patch::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 iat_patch::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)) {
+ std::vector<char> font_data;
+ if (UtilityThread::current()->Send(
+ new UtilityHostMsg_PreCacheFont(logfont)))
+ rv = GetFontData(hdc, table, offset, buffer, length);
+ }
+ }
+ return rv;
+}
+
+bool UtilityThread::RenderPDFToWinMetafile(
+ base::PlatformFile pdf_file,
+ const gfx::Rect& render_area,
+ int render_dpi,
+ const std::vector<printing::PageRange>& page_ranges,
+ printing::NativeMetafile* metafile,
+ int* highest_rendered_page_number) {
+ *highest_rendered_page_number = -1;
+ ScopedHandle file(pdf_file);
+ 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)
+ 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.
+ DWORD length = ::GetFileSize(file, NULL);
+ if (length == INVALID_FILE_SIZE)
+ return false;
+
+ std::vector<uint8> buffer;
+ buffer.resize(length);
+ DWORD bytes_read = 0;
+ if (!ReadFile(pdf_file, &buffer.front(), length, &bytes_read, NULL) ||
+ (bytes_read != length))
+ return false;
+
+ int total_page_count = 0;
+ if (!get_info_proc(&buffer.front(), buffer.size(), &total_page_count, NULL))
+ return false;
+
+ metafile->CreateDc(NULL, NULL);
+ // Since we created the metafile using the screen DPI (but we actually want
+ // the PDF DLL to print using the passed in render_dpi, we apply the following
+ // transformation.
+ SetGraphicsMode(metafile->hdc(), GM_ADVANCED);
+ XFORM xform = {0};
+ int screen_dpi = GetDeviceCaps(GetDC(NULL), LOGPIXELSX);
+ xform.eM11 = xform.eM22 =
+ static_cast<float>(screen_dpi) / static_cast<float>(render_dpi);
+ ModifyWorldTransform(metafile->hdc(), &xform, MWT_LEFTMULTIPLY);
+
+ bool ret = false;
+ std::vector<printing::PageRange>::const_iterator iter;
+ for (iter = page_ranges.begin(); iter != page_ranges.end(); ++iter) {
+ for (int page_number = iter->from; page_number <= iter->to; ++page_number) {
+ if (page_number >= total_page_count)
+ break;
+ metafile->StartPage();
+ if (render_proc(&buffer.front(), buffer.size(), page_number,
+ metafile->hdc(), render_dpi, render_dpi,
+ render_area.x(), render_area.y(), render_area.width(),
+ render_area.height(), true, false, true, true))
+ if (*highest_rendered_page_number < page_number)
+ *highest_rendered_page_number = page_number;
+ ret = true;
+ metafile->EndPage();
+ }
+ }
+ metafile->CloseDc();
+ return ret;
+}
+#endif // defined(OS_WIN)
+
diff --git a/chrome/utility/utility_thread.h b/chrome/utility/utility_thread.h
index 9b88bc2..4954cf3 100644
--- a/chrome/utility/utility_thread.h
+++ b/chrome/utility/utility_thread.h
@@ -8,11 +8,21 @@
#include <string>
#include <vector>
+#include "base/platform_file.h"
#include "chrome/common/child_thread.h"
+#include "printing/native_metafile.h"
class GURL;
class SkBitmap;
+namespace gfx {
+class Rect;
+} // namespace gfx
+
+namespace printing {
+struct PageRange;
+} // namespace printing
+
// This class represents the background thread where the utility task runs.
class UtilityThread : public ChildThread {
public:
@@ -38,6 +48,25 @@ class UtilityThread : public ChildThread {
// IPC for decoding an image.
void OnDecodeImage(const std::vector<unsigned char>& encoded_data);
+ // IPC to render a PDF into a platform metafile.
+ void OnRenderPDFPagesToMetafile(
+ base::PlatformFile pdf_file,
+ const gfx::Rect& render_area,
+ int render_dpi,
+ const std::vector<printing::PageRange>& page_ranges);
+
+#if defined(OS_WIN)
+ // Helper method for Windows.
+ // |highest_rendered_page_number| is set to -1 on failure to render any page.
+ bool RenderPDFToWinMetafile(
+ base::PlatformFile pdf_file,
+ const gfx::Rect& render_area,
+ int render_dpi,
+ const std::vector<printing::PageRange>& page_ranges,
+ printing::NativeMetafile* metafile,
+ int* highest_rendered_page_number);
+#endif // defined(OS_WIN)
+
DISALLOW_COPY_AND_ASSIGN(UtilityThread);
};