diff --git a/atom/app/atom_main_delegate.cc b/atom/app/atom_main_delegate.cc index c7ad0e11a0ca..c9cdc77e1173 100644 --- a/atom/app/atom_main_delegate.cc +++ b/atom/app/atom_main_delegate.cc @@ -10,6 +10,7 @@ #include "atom/browser/atom_browser_client.h" #include "atom/common/google_api_key.h" #include "atom/renderer/atom_renderer_client.h" +#include "atom/utility/atom_content_utility_client.h" #include "base/command_line.h" #include "base/debug/stack_trace.h" #include "base/environment.h" @@ -94,6 +95,11 @@ content::ContentRendererClient* return renderer_client_.get(); } +content::ContentUtilityClient* AtomMainDelegate::CreateContentUtilityClient() { + utility_client_.reset(new AtomContentUtilityClient); + return utility_client_.get(); +} + scoped_ptr AtomMainDelegate::CreateContentClient() { return scoped_ptr(new AtomContentClient).Pass(); } diff --git a/atom/app/atom_main_delegate.h b/atom/app/atom_main_delegate.h index 8cd4a28ee1c0..7bcde8125c8e 100644 --- a/atom/app/atom_main_delegate.h +++ b/atom/app/atom_main_delegate.h @@ -21,6 +21,7 @@ class AtomMainDelegate : public brightray::MainDelegate { void PreSandboxStartup() override; content::ContentBrowserClient* CreateContentBrowserClient() override; content::ContentRendererClient* CreateContentRendererClient() override; + content::ContentUtilityClient* CreateContentUtilityClient() override; // brightray::MainDelegate: scoped_ptr CreateContentClient() override; @@ -35,6 +36,7 @@ class AtomMainDelegate : public brightray::MainDelegate { brightray::ContentClient content_client_; scoped_ptr browser_client_; scoped_ptr renderer_client_; + scoped_ptr utility_client_; DISALLOW_COPY_AND_ASSIGN(AtomMainDelegate); }; diff --git a/atom/utility/atom_content_utility_client.cc b/atom/utility/atom_content_utility_client.cc new file mode 100644 index 000000000000..cc739227aad8 --- /dev/null +++ b/atom/utility/atom_content_utility_client.cc @@ -0,0 +1,74 @@ +// Copyright (c) 2015 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#include "atom/utility/atom_content_utility_client.h" + +#include "base/command_line.h" +#include "base/files/file_path.h" +#include "base/memory/ref_counted.h" +#include "base/time/time.h" +#include "chrome/common/chrome_utility_messages.h" +#include "chrome/utility/utility_message_handler.h" +#include "content/public/common/content_switches.h" +#include "content/public/utility/utility_thread.h" +#include "ipc/ipc_channel.h" +#include "ipc/ipc_message_macros.h" + + +#if defined(OS_WIN) +#include "chrome/utility/printing_handler.h" +#endif + + +namespace { + +bool Send(IPC::Message* message) { + return content::UtilityThread::Get()->Send(message); +} + +} // namespace + +namespace atom { + +int64_t AtomContentUtilityClient::max_ipc_message_size_ = + IPC::Channel::kMaximumMessageSize; + +AtomContentUtilityClient::AtomContentUtilityClient() + : filter_messages_(false) { +#if defined(OS_WIN) + handlers_.push_back(new PrintingHandler()); +#endif +} + +AtomContentUtilityClient::~AtomContentUtilityClient() { +} + +void AtomContentUtilityClient::UtilityThreadStarted() { +} + +bool AtomContentUtilityClient::OnMessageReceived( + const IPC::Message& message) { + if (filter_messages_ && !ContainsKey(message_id_whitelist_, message.type())) + return false; + + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(AtomContentUtilityClient, message) + IPC_MESSAGE_HANDLER(ChromeUtilityMsg_StartupPing, OnStartupPing) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + + for (Handlers::iterator it = handlers_.begin(); + !handled && it != handlers_.end(); ++it) { + handled = (*it)->OnMessageReceived(message); + } + + return handled; +} + +void AtomContentUtilityClient::OnStartupPing() { + Send(new ChromeUtilityHostMsg_ProcessStarted); + // Don't release the process, we assume further messages are on the way. +} + +} // namespace atom diff --git a/atom/utility/atom_content_utility_client.h b/atom/utility/atom_content_utility_client.h new file mode 100644 index 000000000000..2c245b62f61e --- /dev/null +++ b/atom/utility/atom_content_utility_client.h @@ -0,0 +1,57 @@ +// Copyright (c) 2015 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#ifndef ATOM_UTILITY_ATOM_CONTENT_UTILITY_CLIENT_H_ +#define ATOM_UTILITY_ATOM_CONTENT_UTILITY_CLIENT_H_ + +#include +#include +#include + +#include "base/compiler_specific.h" +#include "base/memory/scoped_vector.h" +#include "content/public/utility/content_utility_client.h" +#include "ipc/ipc_platform_file.h" + +namespace base { +class FilePath; +struct FileDescriptor; +} + +class UtilityMessageHandler; + +namespace atom { + +class AtomContentUtilityClient : public content::ContentUtilityClient { + public: + AtomContentUtilityClient(); + ~AtomContentUtilityClient() override; + + void UtilityThreadStarted() override; + bool OnMessageReceived(const IPC::Message& message) override; + + + static void set_max_ipc_message_size_for_test(int64_t max_message_size) { + max_ipc_message_size_ = max_message_size; + } + + private: + void OnStartupPing(); + + typedef ScopedVector Handlers; + Handlers handlers_; + + // Flag to enable whitelisting. + bool filter_messages_; + // A list of message_ids to filter. + std::set message_id_whitelist_; + // Maximum IPC msg size (default to kMaximumMessageSize; override for testing) + static int64_t max_ipc_message_size_; + + DISALLOW_COPY_AND_ASSIGN(AtomContentUtilityClient); +}; + +} // namespace atom + +#endif // ATOM_UTILITY_ATOM_CONTENT_UTILITY_CLIENT_H_ diff --git a/chromium_src/chrome/browser/printing/pdf_to_emf_converter.cc b/chromium_src/chrome/browser/printing/pdf_to_emf_converter.cc new file mode 100644 index 000000000000..89bac3b68dca --- /dev/null +++ b/chromium_src/chrome/browser/printing/pdf_to_emf_converter.cc @@ -0,0 +1,495 @@ +// Copyright 2014 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 "chrome/browser/printing/pdf_to_emf_converter.h" + +#include + +#include "base/files/file.h" +#include "base/files/file_util.h" +#include "base/files/scoped_temp_dir.h" +#include "base/logging.h" +#include "chrome/common/chrome_utility_messages.h" +#include "chrome/common/print_messages.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/child_process_data.h" +#include "content/public/browser/utility_process_host.h" +#include "content/public/browser/utility_process_host_client.h" +#include "printing/emf_win.h" +#include "printing/pdf_render_settings.h" + +namespace printing { + +namespace { + +using content::BrowserThread; + +class PdfToEmfConverterImpl; + +// Allows to delete temporary directory after all temporary files created inside +// are closed. Windows cannot delete directory with opened files. Directory is +// used to store PDF and metafiles. PDF should be gone by the time utility +// process exits. Metafiles should be gone when all LazyEmf destroyed. +class RefCountedTempDir + : public base::RefCountedThreadSafe { + public: + RefCountedTempDir() { ignore_result(temp_dir_.CreateUniqueTempDir()); } + bool IsValid() const { return temp_dir_.IsValid(); } + const base::FilePath& GetPath() const { return temp_dir_.path(); } + + private: + friend struct BrowserThread::DeleteOnThread; + friend class base::DeleteHelper; + ~RefCountedTempDir() {} + + base::ScopedTempDir temp_dir_; + DISALLOW_COPY_AND_ASSIGN(RefCountedTempDir); +}; + +typedef scoped_ptr + ScopedTempFile; + +// Wrapper for Emf to keep only file handle in memory, and load actual data only +// on playback. Emf::InitFromFile() can play metafile directly from disk, but it +// can't open file handles. We need file handles to reliably delete temporary +// files, and to efficiently interact with utility process. +class LazyEmf : public MetafilePlayer { + public: + LazyEmf(const scoped_refptr& temp_dir, ScopedTempFile file) + : temp_dir_(temp_dir), file_(file.Pass()) {} + virtual ~LazyEmf() { Close(); } + + virtual bool SafePlayback(HDC hdc) const override; + virtual bool SaveTo(base::File* file) const override; + + private: + void Close() const; + bool LoadEmf(Emf* emf) const; + + mutable scoped_refptr temp_dir_; + mutable ScopedTempFile file_; // Mutable because of consts in base class. + + DISALLOW_COPY_AND_ASSIGN(LazyEmf); +}; + +// Converts PDF into EMF. +// Class uses 3 threads: UI, IO and FILE. +// Internal workflow is following: +// 1. Create instance on the UI thread. (files_, settings_,) +// 2. Create pdf file on the FILE thread. +// 3. Start utility process and start conversion on the IO thread. +// 4. Utility process returns page count. +// 5. For each page: +// 1. Clients requests page with file handle to a temp file. +// 2. Utility converts the page, save it to the file and reply. +// +// All these steps work sequentially, so no data should be accessed +// simultaneously by several threads. +class PdfToEmfUtilityProcessHostClient + : public content::UtilityProcessHostClient { + public: + PdfToEmfUtilityProcessHostClient( + base::WeakPtr converter, + const PdfRenderSettings& settings); + + void Start(const scoped_refptr& data, + const PdfToEmfConverter::StartCallback& start_callback); + + void GetPage(int page_number, + const PdfToEmfConverter::GetPageCallback& get_page_callback); + + void Stop(); + + // UtilityProcessHostClient implementation. + virtual void OnProcessCrashed(int exit_code) override; + virtual void OnProcessLaunchFailed() override; + virtual bool OnMessageReceived(const IPC::Message& message) override; + + private: + class GetPageCallbackData { + MOVE_ONLY_TYPE_FOR_CPP_03(GetPageCallbackData, RValue); + + public: + GetPageCallbackData(int page_number, + PdfToEmfConverter::GetPageCallback callback) + : page_number_(page_number), callback_(callback) {} + + // Move constructor for STL. + GetPageCallbackData(RValue other) { this->operator=(other); } + + // Move assignment for STL. + GetPageCallbackData& operator=(RValue rhs) { + page_number_ = rhs.object->page_number_; + callback_ = rhs.object->callback_; + emf_ = rhs.object->emf_.Pass(); + return *this; + } + + int page_number() const { return page_number_; } + const PdfToEmfConverter::GetPageCallback& callback() const { + return callback_; + } + ScopedTempFile emf() { return emf_.Pass(); } + void set_emf(ScopedTempFile emf) { emf_ = emf.Pass(); } + + private: + int page_number_; + PdfToEmfConverter::GetPageCallback callback_; + ScopedTempFile emf_; + }; + + virtual ~PdfToEmfUtilityProcessHostClient(); + + bool Send(IPC::Message* msg); + + // Message handlers. + void OnProcessStarted(); + void OnPageCount(int page_count); + void OnPageDone(bool success, float scale_factor); + + void OnFailed(); + void OnTempPdfReady(ScopedTempFile pdf); + void OnTempEmfReady(GetPageCallbackData* callback_data, ScopedTempFile emf); + + scoped_refptr temp_dir_; + + // Used to suppress callbacks after PdfToEmfConverterImpl is deleted. + base::WeakPtr converter_; + PdfRenderSettings settings_; + scoped_refptr data_; + + // Document loaded callback. + PdfToEmfConverter::StartCallback start_callback_; + + // Process host for IPC. + base::WeakPtr utility_process_host_; + + // Queue of callbacks for GetPage() requests. Utility process should reply + // with PageDone in the same order as requests were received. + // Use containers that keeps element pointers valid after push() and pop(). + typedef std::queue GetPageCallbacks; + GetPageCallbacks get_page_callbacks_; + + DISALLOW_COPY_AND_ASSIGN(PdfToEmfUtilityProcessHostClient); +}; + +class PdfToEmfConverterImpl : public PdfToEmfConverter { + public: + PdfToEmfConverterImpl(); + + virtual ~PdfToEmfConverterImpl(); + + virtual void Start(const scoped_refptr& data, + const PdfRenderSettings& conversion_settings, + const StartCallback& start_callback) override; + + virtual void GetPage(int page_number, + const GetPageCallback& get_page_callback) override; + + // Helps to cancel callbacks if this object is destroyed. + void RunCallback(const base::Closure& callback); + + private: + scoped_refptr utility_client_; + base::WeakPtrFactory weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(PdfToEmfConverterImpl); +}; + +ScopedTempFile CreateTempFile(scoped_refptr* temp_dir) { + if (!temp_dir->get()) + *temp_dir = new RefCountedTempDir(); + ScopedTempFile file; + if (!(*temp_dir)->IsValid()) + return file.Pass(); + base::FilePath path; + if (!base::CreateTemporaryFileInDir((*temp_dir)->GetPath(), &path)) + return file.Pass(); + file.reset(new base::File(path, + base::File::FLAG_CREATE_ALWAYS | + base::File::FLAG_WRITE | + base::File::FLAG_READ | + base::File::FLAG_DELETE_ON_CLOSE | + base::File::FLAG_TEMPORARY)); + if (!file->IsValid()) + file.reset(); + return file.Pass(); +} + +ScopedTempFile CreateTempPdfFile( + const scoped_refptr& data, + scoped_refptr* temp_dir) { + DCHECK_CURRENTLY_ON(BrowserThread::FILE); + + ScopedTempFile pdf_file = CreateTempFile(temp_dir); + if (!pdf_file || + static_cast(data->size()) != + pdf_file->WriteAtCurrentPos(data->front_as(), data->size())) { + pdf_file.reset(); + } + pdf_file->Seek(base::File::FROM_BEGIN, 0); + return pdf_file.Pass(); +} + +bool LazyEmf::SafePlayback(HDC hdc) const { + Emf emf; + bool result = LoadEmf(&emf) && emf.SafePlayback(hdc); + // TODO(vitalybuka): Fix destruction of metafiles. For some reasons + // instances of Emf are not deleted. crbug.com/411683 + // It's known that the Emf going to be played just once to a printer. So just + // release file here. + Close(); + return result; +} + +bool LazyEmf::SaveTo(base::File* file) const { + Emf emf; + return LoadEmf(&emf) && emf.SaveTo(file); +} + +void LazyEmf::Close() const { + file_.reset(); + temp_dir_ = NULL; +} + +bool LazyEmf::LoadEmf(Emf* emf) const { + file_->Seek(base::File::FROM_BEGIN, 0); + int64 size = file_->GetLength(); + if (size <= 0) + return false; + std::vector data(size); + if (file_->ReadAtCurrentPos(data.data(), data.size()) != size) + return false; + return emf->InitFromData(data.data(), data.size()); +} + +PdfToEmfUtilityProcessHostClient::PdfToEmfUtilityProcessHostClient( + base::WeakPtr converter, + const PdfRenderSettings& settings) + : converter_(converter), settings_(settings) { +} + +PdfToEmfUtilityProcessHostClient::~PdfToEmfUtilityProcessHostClient() { +} + +void PdfToEmfUtilityProcessHostClient::Start( + const scoped_refptr& data, + const PdfToEmfConverter::StartCallback& start_callback) { + if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { + BrowserThread::PostTask(BrowserThread::IO, + FROM_HERE, + base::Bind(&PdfToEmfUtilityProcessHostClient::Start, + this, + data, + start_callback)); + return; + } + data_ = data; + + // Store callback before any OnFailed() call to make it called on failure. + start_callback_ = start_callback; + + // NOTE: This process _must_ be sandboxed, otherwise the pdf dll will load + // gdiplus.dll, change how rendering happens, and not be able to correctly + // generate when sent to a metafile DC. + utility_process_host_ = + content::UtilityProcessHost::Create( + this, base::MessageLoop::current()->message_loop_proxy()) + ->AsWeakPtr(); + if (!utility_process_host_) + return OnFailed(); + // Should reply with OnProcessStarted(). + Send(new ChromeUtilityMsg_StartupPing); +} + +void PdfToEmfUtilityProcessHostClient::OnProcessStarted() { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + if (!utility_process_host_) + return OnFailed(); + + scoped_refptr data = data_; + data_ = NULL; + BrowserThread::PostTaskAndReplyWithResult( + BrowserThread::FILE, + FROM_HERE, + base::Bind(&CreateTempPdfFile, data, &temp_dir_), + base::Bind(&PdfToEmfUtilityProcessHostClient::OnTempPdfReady, this)); +} + +void PdfToEmfUtilityProcessHostClient::OnTempPdfReady(ScopedTempFile pdf) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + if (!utility_process_host_) + return OnFailed(); + base::ProcessHandle process = utility_process_host_->GetData().handle; + // Should reply with OnPageCount(). + Send(new ChromeUtilityMsg_RenderPDFPagesToMetafiles( + IPC::GetFileHandleForProcess(pdf->GetPlatformFile(), process, false), + settings_)); +} + +void PdfToEmfUtilityProcessHostClient::OnPageCount(int page_count) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + if (start_callback_.is_null()) + return OnFailed(); + BrowserThread::PostTask(BrowserThread::UI, + FROM_HERE, + base::Bind(&PdfToEmfConverterImpl::RunCallback, + converter_, + base::Bind(start_callback_, page_count))); + start_callback_.Reset(); +} + +void PdfToEmfUtilityProcessHostClient::GetPage( + int page_number, + const PdfToEmfConverter::GetPageCallback& get_page_callback) { + if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { + BrowserThread::PostTask( + BrowserThread::IO, + FROM_HERE, + base::Bind(&PdfToEmfUtilityProcessHostClient::GetPage, + this, + page_number, + get_page_callback)); + return; + } + + // Store callback before any OnFailed() call to make it called on failure. + get_page_callbacks_.push(GetPageCallbackData(page_number, get_page_callback)); + + if (!utility_process_host_) + return OnFailed(); + + BrowserThread::PostTaskAndReplyWithResult( + BrowserThread::FILE, + FROM_HERE, + base::Bind(&CreateTempFile, &temp_dir_), + base::Bind(&PdfToEmfUtilityProcessHostClient::OnTempEmfReady, + this, + &get_page_callbacks_.back())); +} + +void PdfToEmfUtilityProcessHostClient::OnTempEmfReady( + GetPageCallbackData* callback_data, + ScopedTempFile emf) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + if (!utility_process_host_) + return OnFailed(); + base::ProcessHandle process = utility_process_host_->GetData().handle; + IPC::PlatformFileForTransit transit = + IPC::GetFileHandleForProcess(emf->GetPlatformFile(), process, false); + callback_data->set_emf(emf.Pass()); + // Should reply with OnPageDone(). + Send(new ChromeUtilityMsg_RenderPDFPagesToMetafiles_GetPage( + callback_data->page_number(), transit)); +} + +void PdfToEmfUtilityProcessHostClient::OnPageDone(bool success, + float scale_factor) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + if (get_page_callbacks_.empty()) + return OnFailed(); + scoped_ptr emf; + GetPageCallbackData& data = get_page_callbacks_.front(); + if (success) + emf.reset(new LazyEmf(temp_dir_, data.emf().Pass())); + BrowserThread::PostTask(BrowserThread::UI, + FROM_HERE, + base::Bind(&PdfToEmfConverterImpl::RunCallback, + converter_, + base::Bind(data.callback(), + data.page_number(), + scale_factor, + base::Passed(&emf)))); + get_page_callbacks_.pop(); +} + +void PdfToEmfUtilityProcessHostClient::Stop() { + if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { + BrowserThread::PostTask( + BrowserThread::IO, + FROM_HERE, + base::Bind(&PdfToEmfUtilityProcessHostClient::Stop, this)); + return; + } + Send(new ChromeUtilityMsg_RenderPDFPagesToMetafiles_Stop()); +} + +void PdfToEmfUtilityProcessHostClient::OnProcessCrashed(int exit_code) { + OnFailed(); +} + +void PdfToEmfUtilityProcessHostClient::OnProcessLaunchFailed() { + OnFailed(); +} + +bool PdfToEmfUtilityProcessHostClient::OnMessageReceived( + const IPC::Message& message) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(PdfToEmfUtilityProcessHostClient, message) + IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ProcessStarted, OnProcessStarted) + IPC_MESSAGE_HANDLER( + ChromeUtilityHostMsg_RenderPDFPagesToMetafiles_PageCount, OnPageCount) + IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_RenderPDFPagesToMetafiles_PageDone, + OnPageDone) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +bool PdfToEmfUtilityProcessHostClient::Send(IPC::Message* msg) { + if (utility_process_host_) + return utility_process_host_->Send(msg); + delete msg; + return false; +} + +void PdfToEmfUtilityProcessHostClient::OnFailed() { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + if (!start_callback_.is_null()) + OnPageCount(0); + while (!get_page_callbacks_.empty()) + OnPageDone(false, 0.0f); + utility_process_host_.reset(); +} + +PdfToEmfConverterImpl::PdfToEmfConverterImpl() : weak_ptr_factory_(this) { +} + +PdfToEmfConverterImpl::~PdfToEmfConverterImpl() { + if (utility_client_.get()) + utility_client_->Stop(); +} + +void PdfToEmfConverterImpl::Start( + const scoped_refptr& data, + const PdfRenderSettings& conversion_settings, + const StartCallback& start_callback) { + DCHECK(!utility_client_.get()); + utility_client_ = new PdfToEmfUtilityProcessHostClient( + weak_ptr_factory_.GetWeakPtr(), conversion_settings); + utility_client_->Start(data, start_callback); +} + +void PdfToEmfConverterImpl::GetPage(int page_number, + const GetPageCallback& get_page_callback) { + utility_client_->GetPage(page_number, get_page_callback); +} + +void PdfToEmfConverterImpl::RunCallback(const base::Closure& callback) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + callback.Run(); +} + +} // namespace + +PdfToEmfConverter::~PdfToEmfConverter() { +} + +// static +scoped_ptr PdfToEmfConverter::CreateDefault() { + return scoped_ptr(new PdfToEmfConverterImpl()); +} + +} // namespace printing diff --git a/chromium_src/chrome/browser/printing/pdf_to_emf_converter.h b/chromium_src/chrome/browser/printing/pdf_to_emf_converter.h new file mode 100644 index 000000000000..60fdbc4b7e4e --- /dev/null +++ b/chromium_src/chrome/browser/printing/pdf_to_emf_converter.h @@ -0,0 +1,48 @@ +// Copyright 2014 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. + +#ifndef CHROME_BROWSER_PRINTING_PDF_TO_EMF_CONVERTER_H_ +#define CHROME_BROWSER_PRINTING_PDF_TO_EMF_CONVERTER_H_ + +#include "base/callback.h" +#include "base/memory/ref_counted_memory.h" +#include "base/memory/scoped_ptr.h" + +namespace base { +class FilePath; +} + +namespace printing { + +class MetafilePlayer; +class PdfRenderSettings; + +class PdfToEmfConverter { + public: + typedef base::Callback StartCallback; + typedef base::Callback emf)> GetPageCallback; + + virtual ~PdfToEmfConverter(); + + static scoped_ptr CreateDefault(); + + // Starts conversion of PDF provided as |data|. Calls |start_callback| + // with positive |page_count|. |page_count| is 0 if initialization failed. + virtual void Start(const scoped_refptr& data, + const PdfRenderSettings& conversion_settings, + const StartCallback& start_callback) = 0; + + // Requests conversion of the page. |page_number| is 0-base page number in + // PDF provided in Start() call. + // Calls |get_page_callback| after conversion. |emf| of callback in not NULL + // if conversion succeeded. + virtual void GetPage(int page_number, + const GetPageCallback& get_page_callback) = 0; +}; + +} // namespace printing + +#endif // CHROME_BROWSER_PRINTING_PDF_TO_EMF_CONVERTER_H_ diff --git a/chromium_src/chrome/browser/printing/print_job.cc b/chromium_src/chrome/browser/printing/print_job.cc index 25cf0ad79033..6bcc58322124 100644 --- a/chromium_src/chrome/browser/printing/print_job.cc +++ b/chromium_src/chrome/browser/printing/print_job.cc @@ -17,6 +17,12 @@ #include "printing/printed_document.h" #include "printing/printed_page.h" +#if defined(OS_WIN) +#include "chrome/browser/printing/pdf_to_emf_converter.h" +#include "printing/pdf_render_settings.h" +#endif + + using base::TimeDelta; namespace { @@ -272,6 +278,103 @@ void PrintJob::OnNotifyPrintJobEvent(const JobEventDetails& event_details) { } } +#if defined(OS_WIN) + +class PrintJob::PdfToEmfState { + public: + PdfToEmfState(const gfx::Size& page_size, const gfx::Rect& content_area) + : page_count_(0), + current_page_(0), + pages_in_progress_(0), + page_size_(page_size), + content_area_(content_area), + converter_(PdfToEmfConverter::CreateDefault()) {} + + void Start(const scoped_refptr& data, + const PdfRenderSettings& conversion_settings, + const PdfToEmfConverter::StartCallback& start_callback) { + converter_->Start(data, conversion_settings, start_callback); + } + + void GetMorePages( + const PdfToEmfConverter::GetPageCallback& get_page_callback) { + const int kMaxNumberOfTempFilesPerDocument = 3; + while (pages_in_progress_ < kMaxNumberOfTempFilesPerDocument && + current_page_ < page_count_) { + ++pages_in_progress_; + converter_->GetPage(current_page_++, get_page_callback); + } + } + + void OnPageProcessed( + const PdfToEmfConverter::GetPageCallback& get_page_callback) { + --pages_in_progress_; + GetMorePages(get_page_callback); + // Release converter if we don't need this any more. + if (!pages_in_progress_ && current_page_ >= page_count_) + converter_.reset(); + } + + void set_page_count(int page_count) { page_count_ = page_count; } + gfx::Size page_size() const { return page_size_; } + gfx::Rect content_area() const { return content_area_; } + + private: + int page_count_; + int current_page_; + int pages_in_progress_; + gfx::Size page_size_; + gfx::Rect content_area_; + scoped_ptr converter_; +}; + +void PrintJob::StartPdfToEmfConversion( + const scoped_refptr& bytes, + const gfx::Size& page_size, + const gfx::Rect& content_area) { + DCHECK(!ptd_to_emf_state_.get()); + ptd_to_emf_state_.reset(new PdfToEmfState(page_size, content_area)); + const int kPrinterDpi = settings().dpi(); + ptd_to_emf_state_->Start( + bytes, + printing::PdfRenderSettings(content_area, kPrinterDpi, true), + base::Bind(&PrintJob::OnPdfToEmfStarted, this)); +} + +void PrintJob::OnPdfToEmfStarted(int page_count) { + if (page_count <= 0) { + ptd_to_emf_state_.reset(); + Cancel(); + return; + } + ptd_to_emf_state_->set_page_count(page_count); + ptd_to_emf_state_->GetMorePages( + base::Bind(&PrintJob::OnPdfToEmfPageConverted, this)); +} + +void PrintJob::OnPdfToEmfPageConverted(int page_number, + float scale_factor, + scoped_ptr emf) { + DCHECK(ptd_to_emf_state_); + if (!document_.get() || !emf) { + ptd_to_emf_state_.reset(); + Cancel(); + return; + } + + // Update the rendered document. It will send notifications to the listener. + document_->SetPage(page_number, + emf.Pass(), + scale_factor, + ptd_to_emf_state_->page_size(), + ptd_to_emf_state_->content_area()); + + ptd_to_emf_state_->GetMorePages( + base::Bind(&PrintJob::OnPdfToEmfPageConverted, this)); +} + +#endif // OS_WIN + void PrintJob::OnDocumentDone() { // Be sure to live long enough. The instance could be destroyed by the // JOB_DONE broadcast. diff --git a/chromium_src/chrome/browser/printing/print_job.h b/chromium_src/chrome/browser/printing/print_job.h index a0f844a27c2d..48daaa6cb971 100644 --- a/chromium_src/chrome/browser/printing/print_job.h +++ b/chromium_src/chrome/browser/printing/print_job.h @@ -90,6 +90,19 @@ class PrintJob : public PrintJobWorkerOwner, // Access the current printed document. Warning: may be NULL. PrintedDocument* document() const; +#if defined(OS_WIN) + void StartPdfToEmfConversion( + const scoped_refptr& bytes, + const gfx::Size& page_size, + const gfx::Rect& content_area); + + void OnPdfToEmfStarted(int page_count); + void OnPdfToEmfPageConverted(int page_number, + float scale_factor, + scoped_ptr emf); + +#endif // OS_WIN + protected: virtual ~PrintJob(); @@ -137,6 +150,11 @@ class PrintJob : public PrintJobWorkerOwner, // the notified calls Cancel() again. bool is_canceling_; +#if defined(OS_WIN) + class PdfToEmfState; + scoped_ptr ptd_to_emf_state_; +#endif // OS_WIN + // Used at shutdown so that we can quit a nested message loop. base::WeakPtrFactory quit_factory_; diff --git a/chromium_src/chrome/browser/printing/print_view_manager_base.cc b/chromium_src/chrome/browser/printing/print_view_manager_base.cc index 3aec7a14d546..35c62fbc5327 100644 --- a/chromium_src/chrome/browser/printing/print_view_manager_base.cc +++ b/chromium_src/chrome/browser/printing/print_view_manager_base.cc @@ -156,6 +156,8 @@ void PrintViewManagerBase::OnDidPrintPage( params.data_size); document->DebugDumpData(bytes.get(), FILE_PATH_LITERAL(".pdf")); + print_job_->StartPdfToEmfConversion( + bytes, params.page_size, params.content_area); } #endif // !OS_WIN } diff --git a/chromium_src/chrome/common/chrome_utility_messages.h b/chromium_src/chrome/common/chrome_utility_messages.h new file mode 100644 index 000000000000..1de0756c0d58 --- /dev/null +++ b/chromium_src/chrome/common/chrome_utility_messages.h @@ -0,0 +1,169 @@ +// Copyright (c) 2012 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. + +// Multiply-included message file, so no include guard. + +#if defined(OS_WIN) +#include +#endif // defined(OS_WIN) + +#include +#include + +#include "base/files/file_path.h" +#include "base/strings/string16.h" +#include "base/tuple.h" +#include "base/values.h" +#include "ipc/ipc_message_macros.h" +#include "ipc/ipc_platform_file.h" +#include "third_party/skia/include/core/SkBitmap.h" +#include "ui/gfx/ipc/gfx_param_traits.h" + +// Singly-included section for typedefs. +#ifndef CHROME_COMMON_CHROME_UTILITY_MESSAGES_H_ +#define CHROME_COMMON_CHROME_UTILITY_MESSAGES_H_ + +#if defined(OS_WIN) +// A vector of filters, each being a Tuple containing a display string (i.e. +// "Text Files") and a filter pattern (i.e. "*.txt"). +typedef std::vector> + GetOpenFileNameFilter; +#endif // OS_WIN + +#endif // CHROME_COMMON_CHROME_UTILITY_MESSAGES_H_ + +#define IPC_MESSAGE_START ChromeUtilityMsgStart + + +#if defined(OS_WIN) +IPC_STRUCT_BEGIN(ChromeUtilityMsg_GetSaveFileName_Params) + IPC_STRUCT_MEMBER(HWND, owner) + IPC_STRUCT_MEMBER(DWORD, flags) + IPC_STRUCT_MEMBER(GetOpenFileNameFilter, filters) + IPC_STRUCT_MEMBER(int, one_based_filter_index) + IPC_STRUCT_MEMBER(base::FilePath, suggested_filename) + IPC_STRUCT_MEMBER(base::FilePath, initial_directory) + IPC_STRUCT_MEMBER(base::string16, default_extension) +IPC_STRUCT_END() +#endif // OS_WIN + +//------------------------------------------------------------------------------ +// Utility process messages: +// These are messages from the browser to the utility process. + +// Tell the utility process to parse a JSON string into a Value object. +IPC_MESSAGE_CONTROL1(ChromeUtilityMsg_ParseJSON, + std::string /* JSON to parse */) + +// Tell the utility process to decode the given image data. +IPC_MESSAGE_CONTROL2(ChromeUtilityMsg_DecodeImage, + std::vector /* encoded image contents */, + bool /* shrink image if needed for IPC msg limit */) + +// Tell the utility process to decode the given JPEG image data with a robust +// libjpeg codec. +IPC_MESSAGE_CONTROL1(ChromeUtilityMsg_RobustJPEGDecodeImage, + std::vector) // encoded image contents + +// Tell the utility process to patch the given |input_file| using |patch_file| +// and place the output in |output_file|. The patch should use the bsdiff +// algorithm (Courgette's version). +IPC_MESSAGE_CONTROL3(ChromeUtilityMsg_PatchFileBsdiff, + base::FilePath /* input_file */, + base::FilePath /* patch_file */, + base::FilePath /* output_file */) + +// Tell the utility process to patch the given |input_file| using |patch_file| +// and place the output in |output_file|. The patch should use the Courgette +// algorithm. +IPC_MESSAGE_CONTROL3(ChromeUtilityMsg_PatchFileCourgette, + base::FilePath /* input_file */, + base::FilePath /* patch_file */, + base::FilePath /* output_file */) + + +// Requests the utility process to respond with a +// ChromeUtilityHostMsg_ProcessStarted message once it has started. This may +// be used if the host process needs a handle to the running utility process. +IPC_MESSAGE_CONTROL0(ChromeUtilityMsg_StartupPing) + + +#if defined(OS_WIN) +// Invokes ui::base::win::OpenFileViaShell from the utility process. +IPC_MESSAGE_CONTROL1(ChromeUtilityMsg_OpenFileViaShell, + base::FilePath /* full_path */) + +// Invokes ui::base::win::OpenFolderViaShell from the utility process. +IPC_MESSAGE_CONTROL1(ChromeUtilityMsg_OpenFolderViaShell, + base::FilePath /* full_path */) + +// Instructs the utility process to invoke GetOpenFileName. |owner| is the +// parent of the modal dialog, |flags| are OFN_* flags. |filter| constrains the +// user's file choices. |initial_directory| and |filename| select the directory +// to be displayed and the file to be initially selected. +// +// Either ChromeUtilityHostMsg_GetOpenFileName_Failed or +// ChromeUtilityHostMsg_GetOpenFileName_Result will be returned when the +// operation completes whether due to error or user action. +IPC_MESSAGE_CONTROL5(ChromeUtilityMsg_GetOpenFileName, + HWND /* owner */, + DWORD /* flags */, + GetOpenFileNameFilter /* filter */, + base::FilePath /* initial_directory */, + base::FilePath /* filename */) +IPC_MESSAGE_CONTROL1(ChromeUtilityMsg_GetSaveFileName, + ChromeUtilityMsg_GetSaveFileName_Params /* params */) +#endif // defined(OS_WIN) + + +//------------------------------------------------------------------------------ +// Utility process host messages: +// These are messages from the utility process to the browser. + +// Reply when the utility process successfully parsed a JSON string. +// +// WARNING: The result can be of any Value subclass type, but we can't easily +// pass indeterminate value types by const object reference with our IPC macros, +// so we put the result Value into a ListValue. Handlers should examine the +// first (and only) element of the ListValue for the actual result. +IPC_MESSAGE_CONTROL1(ChromeUtilityHostMsg_ParseJSON_Succeeded, + base::ListValue) + +// Reply when the utility process failed in parsing a JSON string. +IPC_MESSAGE_CONTROL1(ChromeUtilityHostMsg_ParseJSON_Failed, + std::string /* error message, if any*/) + +// Reply when the utility process has failed while unpacking and parsing a +// web resource. |error_message| is a user-readable explanation of what +// went wrong. +IPC_MESSAGE_CONTROL1(ChromeUtilityHostMsg_UnpackWebResource_Failed, + std::string /* error_message, if any */) + +// Reply when the utility process has succeeded in decoding the image. +IPC_MESSAGE_CONTROL1(ChromeUtilityHostMsg_DecodeImage_Succeeded, + SkBitmap) // decoded image + +// Reply when an error occurred decoding the image. +IPC_MESSAGE_CONTROL0(ChromeUtilityHostMsg_DecodeImage_Failed) + +// Reply when a file has been patched. +IPC_MESSAGE_CONTROL1(ChromeUtilityHostMsg_PatchFile_Finished, int /* result */) + + +// Reply when the utility process has started. +IPC_MESSAGE_CONTROL0(ChromeUtilityHostMsg_ProcessStarted) + + +#if defined(OS_WIN) +IPC_MESSAGE_CONTROL0(ChromeUtilityHostMsg_GetOpenFileName_Failed) +IPC_MESSAGE_CONTROL2(ChromeUtilityHostMsg_GetOpenFileName_Result, + base::FilePath /* directory */, + std::vector /* filenames */) +IPC_MESSAGE_CONTROL0(ChromeUtilityHostMsg_GetSaveFileName_Failed) +IPC_MESSAGE_CONTROL2(ChromeUtilityHostMsg_GetSaveFileName_Result, + base::FilePath /* path */, + int /* one_based_filter_index */) +IPC_MESSAGE_CONTROL1(ChromeUtilityHostMsg_BuildDirectWriteFontCache, + base::FilePath /* cache file path */) +#endif // defined(OS_WIN) diff --git a/chromium_src/chrome/common/print_messages.h b/chromium_src/chrome/common/print_messages.h index 4ca8db82ae3d..4a54546b69d7 100644 --- a/chromium_src/chrome/common/print_messages.h +++ b/chromium_src/chrome/common/print_messages.h @@ -17,6 +17,13 @@ #include "ui/gfx/native_widget_types.h" #include "ui/gfx/geometry/rect.h" +#if defined(OS_WIN) +#include "ipc/ipc_platform_file.h" +#include "printing/backend/print_backend.h" +#include "printing/page_range.h" +#include "printing/pdf_render_settings.h" +#endif + #ifndef CHROME_COMMON_PRINT_MESSAGES_H_ #define CHROME_COMMON_PRINT_MESSAGES_H_ @@ -239,3 +246,31 @@ IPC_MESSAGE_ROUTED0(PrintHostMsg_ShowInvalidPrinterSettingsError) // Tell the browser printing failed. IPC_MESSAGE_ROUTED1(PrintHostMsg_PrintingFailed, int /* document cookie */) + + +#if defined(OS_WIN) +// Tell the utility process to start rendering the given PDF into a metafile. +// Utility process would be alive until +// ChromeUtilityMsg_RenderPDFPagesToMetafiles_Stop message. +IPC_MESSAGE_CONTROL2(ChromeUtilityMsg_RenderPDFPagesToMetafiles, + IPC::PlatformFileForTransit, /* input_file */ + printing::PdfRenderSettings /* settings */) + +// Requests conversion of the next page. +IPC_MESSAGE_CONTROL2(ChromeUtilityMsg_RenderPDFPagesToMetafiles_GetPage, + int /* page_number */, + IPC::PlatformFileForTransit /* output_file */) + +// Requests utility process to stop conversion and exit. +IPC_MESSAGE_CONTROL0(ChromeUtilityMsg_RenderPDFPagesToMetafiles_Stop) + +// Reply when the utility process loaded PDF. |page_count| is 0, if loading +// failed. +IPC_MESSAGE_CONTROL1(ChromeUtilityHostMsg_RenderPDFPagesToMetafiles_PageCount, + int /* page_count */) + +// Reply when the utility process rendered the PDF page. +IPC_MESSAGE_CONTROL2(ChromeUtilityHostMsg_RenderPDFPagesToMetafiles_PageDone, + bool /* success */, + float /* scale_factor */) +#endif diff --git a/chromium_src/chrome/utility/printing_handler.cc b/chromium_src/chrome/utility/printing_handler.cc new file mode 100644 index 000000000000..db6d9533cf51 --- /dev/null +++ b/chromium_src/chrome/utility/printing_handler.cc @@ -0,0 +1,144 @@ +// Copyright 2014 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 "chrome/utility/printing_handler.h" + +#include "base/files/file_util.h" +#include "base/lazy_instance.h" +#include "base/path_service.h" +#include "base/scoped_native_library.h" +#include "chrome/common/print_messages.h" +#include "content/public/utility/utility_thread.h" +#include "pdf/pdf.h" +#include "printing/page_range.h" +#include "printing/pdf_render_settings.h" + +#if defined(OS_WIN) +#include "printing/emf_win.h" +#include "ui/gfx/gdi_util.h" +#endif + + +namespace { + +bool Send(IPC::Message* message) { + return content::UtilityThread::Get()->Send(message); +} + +void ReleaseProcessIfNeeded() { + content::UtilityThread::Get()->ReleaseProcessIfNeeded(); +} + +} // namespace + +PrintingHandler::PrintingHandler() {} + +PrintingHandler::~PrintingHandler() {} + +bool PrintingHandler::OnMessageReceived(const IPC::Message& message) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(PrintingHandler, message) +#if defined(OS_WIN) + IPC_MESSAGE_HANDLER(ChromeUtilityMsg_RenderPDFPagesToMetafiles, + OnRenderPDFPagesToMetafile) + IPC_MESSAGE_HANDLER(ChromeUtilityMsg_RenderPDFPagesToMetafiles_GetPage, + OnRenderPDFPagesToMetafileGetPage) + IPC_MESSAGE_HANDLER(ChromeUtilityMsg_RenderPDFPagesToMetafiles_Stop, + OnRenderPDFPagesToMetafileStop) +#endif // OS_WIN + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +#if defined(OS_WIN) +void PrintingHandler::OnRenderPDFPagesToMetafile( + IPC::PlatformFileForTransit pdf_transit, + const printing::PdfRenderSettings& settings) { + pdf_rendering_settings_ = settings; + base::File pdf_file = IPC::PlatformFileForTransitToFile(pdf_transit); + int page_count = LoadPDF(pdf_file.Pass()); + //int page_count = 1; + Send( + new ChromeUtilityHostMsg_RenderPDFPagesToMetafiles_PageCount(page_count)); +} + +void PrintingHandler::OnRenderPDFPagesToMetafileGetPage( + int page_number, + IPC::PlatformFileForTransit output_file) { + base::File emf_file = IPC::PlatformFileForTransitToFile(output_file); + float scale_factor = 1.0f; + bool success = + RenderPdfPageToMetafile(page_number, emf_file.Pass(), &scale_factor); + Send(new ChromeUtilityHostMsg_RenderPDFPagesToMetafiles_PageDone( + success, scale_factor)); +} + +void PrintingHandler::OnRenderPDFPagesToMetafileStop() { + ReleaseProcessIfNeeded(); +} + +int PrintingHandler::LoadPDF(base::File pdf_file) { + int64 length64 = pdf_file.GetLength(); + if (length64 <= 0 || length64 > std::numeric_limits::max()) + return 0; + int length = static_cast(length64); + + pdf_data_.resize(length); + if (length != pdf_file.Read(0, pdf_data_.data(), pdf_data_.size())) + return 0; + + int total_page_count = 0; + if (!chrome_pdf::GetPDFDocInfo( + &pdf_data_.front(), pdf_data_.size(), &total_page_count, NULL)) { + return 0; + } + return total_page_count; +} + +bool PrintingHandler::RenderPdfPageToMetafile(int page_number, + base::File output_file, + float* scale_factor) { + printing::Emf metafile; + metafile.Init(); + + // We need to scale down DC to fit an entire page into DC available area. + // Current metafile is based on screen DC and have current screen size. + // Writing outside of those boundaries will result in the cut-off output. + // On metafiles (this is the case here), scaling down will still record + // original coordinates and we'll be able to print in full resolution. + // Before playback we'll need to counter the scaling up that will happen + // in the service (print_system_win.cc). + *scale_factor = + gfx::CalculatePageScale(metafile.context(), + pdf_rendering_settings_.area().right(), + pdf_rendering_settings_.area().bottom()); + gfx::ScaleDC(metafile.context(), *scale_factor); + + // The underlying metafile is of type Emf and ignores the arguments passed + // to StartPage. + metafile.StartPage(gfx::Size(), gfx::Rect(), 1); + if (!chrome_pdf::RenderPDFPageToDC( + &pdf_data_.front(), + pdf_data_.size(), + page_number, + metafile.context(), + pdf_rendering_settings_.dpi(), + pdf_rendering_settings_.area().x(), + pdf_rendering_settings_.area().y(), + pdf_rendering_settings_.area().width(), + pdf_rendering_settings_.area().height(), + true, + false, + true, + true, + pdf_rendering_settings_.autorotate())) { + return false; + } + metafile.FinishPage(); + metafile.FinishDocument(); + return metafile.SaveTo(&output_file); +} + +#endif // OS_WIN diff --git a/chromium_src/chrome/utility/printing_handler.h b/chromium_src/chrome/utility/printing_handler.h new file mode 100644 index 000000000000..b1f09acb9cc9 --- /dev/null +++ b/chromium_src/chrome/utility/printing_handler.h @@ -0,0 +1,59 @@ +// Copyright 2014 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. + +#ifndef CHROME_UTILITY_PRINTING_HANDLER_H_ +#define CHROME_UTILITY_PRINTING_HANDLER_H_ + +#include "base/compiler_specific.h" +#include "base/macros.h" +#include "chrome/utility/utility_message_handler.h" +#include "ipc/ipc_platform_file.h" +#include "printing/pdf_render_settings.h" + +#if !defined(ENABLE_PRINT_PREVIEW) && !defined(OS_WIN) +#error "Windows or full printing must be enabled" +#endif + +namespace printing { +class PdfRenderSettings; +struct PwgRasterSettings; +struct PageRange; +} + +// Dispatches IPCs for printing. +class PrintingHandler : public UtilityMessageHandler { + public: + PrintingHandler(); + ~PrintingHandler() override; + + // IPC::Listener: + bool OnMessageReceived(const IPC::Message& message) override; + + private: + // IPC message handlers. +#if defined(OS_WIN) + void OnRenderPDFPagesToMetafile(IPC::PlatformFileForTransit pdf_transit, + const printing::PdfRenderSettings& settings); + void OnRenderPDFPagesToMetafileGetPage( + int page_number, + IPC::PlatformFileForTransit output_file); + void OnRenderPDFPagesToMetafileStop(); +#endif // OS_WIN + +#if defined(OS_WIN) + int LoadPDF(base::File pdf_file); + bool RenderPdfPageToMetafile(int page_number, + base::File output_file, + float* scale_factor); +#endif // OS_WIN + +#if defined(OS_WIN) + std::vector pdf_data_; + printing::PdfRenderSettings pdf_rendering_settings_; +#endif + + DISALLOW_COPY_AND_ASSIGN(PrintingHandler); +}; + +#endif // CHROME_UTILITY_PRINTING_HANDLER_H_ diff --git a/chromium_src/chrome/utility/utility_message_handler.h b/chromium_src/chrome/utility/utility_message_handler.h new file mode 100644 index 000000000000..3ccff1a0fbed --- /dev/null +++ b/chromium_src/chrome/utility/utility_message_handler.h @@ -0,0 +1,21 @@ +// Copyright 2013 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. + +#ifndef CHROME_UTILITY_UTILITY_MESSAGE_HANDLER_H_ +#define CHROME_UTILITY_UTILITY_MESSAGE_HANDLER_H_ + +namespace IPC { +class Message; +} + +class UtilityMessageHandler { + public: + virtual ~UtilityMessageHandler() {} + + // Called when a message is received. Returns true iff the message was + // handled. + virtual bool OnMessageReceived(const IPC::Message& message) = 0; +}; + +#endif // CHROME_UTILITY_UTILITY_MESSAGE_HANDLER_H_ diff --git a/filenames.gypi b/filenames.gypi index 093136805b24..bb1e7e54cf9b 100644 --- a/filenames.gypi +++ b/filenames.gypi @@ -281,6 +281,8 @@ 'atom/renderer/atom_renderer_client.h', 'atom/renderer/guest_view_container.cc', 'atom/renderer/guest_view_container.h', + 'atom/utility/atom_content_utility_client.cc', + 'atom/utility/atom_content_utility_client.h', 'chromium_src/chrome/browser/browser_process.cc', 'chromium_src/chrome/browser/browser_process.h', 'chromium_src/chrome/browser/chrome_notification_types.h', @@ -325,6 +327,7 @@ 'chromium_src/chrome/browser/ui/views/color_chooser_aura.h', 'chromium_src/chrome/browser/ui/views/frame/global_menu_bar_registrar_x11.cc', 'chromium_src/chrome/browser/ui/views/frame/global_menu_bar_registrar_x11.h', + 'chromium_src/chrome/common/chrome_utility_messages.h', 'chromium_src/chrome/common/print_messages.cc', 'chromium_src/chrome/common/print_messages.h', 'chromium_src/chrome/common/tts_messages.h', @@ -339,6 +342,7 @@ 'chromium_src/chrome/renderer/spellchecker/spellcheck_worditerator.h', 'chromium_src/chrome/renderer/tts_dispatcher.cc', 'chromium_src/chrome/renderer/tts_dispatcher.h', + 'chromium_src/chrome/utility/utility_message_handler.h', 'chromium_src/library_loaders/libspeechd_loader.cc', 'chromium_src/library_loaders/libspeechd.h', '<@(native_mate_files)', @@ -348,6 +352,10 @@ 'chromium_src/chrome/browser/ui/views/color_chooser_dialog.cc', 'chromium_src/chrome/browser/ui/views/color_chooser_dialog.h', 'chromium_src/chrome/browser/ui/views/color_chooser_win.cc', + 'chromium_src/chrome/browser/printing/pdf_to_emf_converter.cc', + 'chromium_src/chrome/browser/printing/pdf_to_emf_converter.h', + 'chromium_src/chrome/utility/printing_handler.cc', + 'chromium_src/chrome/utility/printing_handler.h', ], 'framework_sources': [ 'atom/app/atom_library_main.h',