Merge pull request #1532 from hokein/win-print
Make Print API work on Windows.
This commit is contained in:
commit
95e72c24cc
15 changed files with 1241 additions and 0 deletions
|
@ -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<brightray::ContentClient> AtomMainDelegate::CreateContentClient() {
|
||||
return scoped_ptr<brightray::ContentClient>(new AtomContentClient).Pass();
|
||||
}
|
||||
|
|
|
@ -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<brightray::ContentClient> CreateContentClient() override;
|
||||
|
@ -35,6 +36,7 @@ class AtomMainDelegate : public brightray::MainDelegate {
|
|||
brightray::ContentClient content_client_;
|
||||
scoped_ptr<content::ContentBrowserClient> browser_client_;
|
||||
scoped_ptr<content::ContentRendererClient> renderer_client_;
|
||||
scoped_ptr<content::ContentUtilityClient> utility_client_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(AtomMainDelegate);
|
||||
};
|
||||
|
|
74
atom/utility/atom_content_utility_client.cc
Normal file
74
atom/utility/atom_content_utility_client.cc
Normal file
|
@ -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
|
57
atom/utility/atom_content_utility_client.h
Normal file
57
atom/utility/atom_content_utility_client.h
Normal file
|
@ -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 <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#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<UtilityMessageHandler> Handlers;
|
||||
Handlers handlers_;
|
||||
|
||||
// Flag to enable whitelisting.
|
||||
bool filter_messages_;
|
||||
// A list of message_ids to filter.
|
||||
std::set<int> 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_
|
495
chromium_src/chrome/browser/printing/pdf_to_emf_converter.cc
Normal file
495
chromium_src/chrome/browser/printing/pdf_to_emf_converter.cc
Normal file
|
@ -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 <queue>
|
||||
|
||||
#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<RefCountedTempDir,
|
||||
BrowserThread::DeleteOnFileThread> {
|
||||
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<BrowserThread::FILE>;
|
||||
friend class base::DeleteHelper<RefCountedTempDir>;
|
||||
~RefCountedTempDir() {}
|
||||
|
||||
base::ScopedTempDir temp_dir_;
|
||||
DISALLOW_COPY_AND_ASSIGN(RefCountedTempDir);
|
||||
};
|
||||
|
||||
typedef scoped_ptr<base::File, BrowserThread::DeleteOnFileThread>
|
||||
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<RefCountedTempDir>& 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<RefCountedTempDir> 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<PdfToEmfConverterImpl> converter,
|
||||
const PdfRenderSettings& settings);
|
||||
|
||||
void Start(const scoped_refptr<base::RefCountedMemory>& 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<RefCountedTempDir> temp_dir_;
|
||||
|
||||
// Used to suppress callbacks after PdfToEmfConverterImpl is deleted.
|
||||
base::WeakPtr<PdfToEmfConverterImpl> converter_;
|
||||
PdfRenderSettings settings_;
|
||||
scoped_refptr<base::RefCountedMemory> data_;
|
||||
|
||||
// Document loaded callback.
|
||||
PdfToEmfConverter::StartCallback start_callback_;
|
||||
|
||||
// Process host for IPC.
|
||||
base::WeakPtr<content::UtilityProcessHost> 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<GetPageCallbackData> GetPageCallbacks;
|
||||
GetPageCallbacks get_page_callbacks_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(PdfToEmfUtilityProcessHostClient);
|
||||
};
|
||||
|
||||
class PdfToEmfConverterImpl : public PdfToEmfConverter {
|
||||
public:
|
||||
PdfToEmfConverterImpl();
|
||||
|
||||
virtual ~PdfToEmfConverterImpl();
|
||||
|
||||
virtual void Start(const scoped_refptr<base::RefCountedMemory>& 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<PdfToEmfUtilityProcessHostClient> utility_client_;
|
||||
base::WeakPtrFactory<PdfToEmfConverterImpl> weak_ptr_factory_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(PdfToEmfConverterImpl);
|
||||
};
|
||||
|
||||
ScopedTempFile CreateTempFile(scoped_refptr<RefCountedTempDir>* 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<base::RefCountedMemory>& data,
|
||||
scoped_refptr<RefCountedTempDir>* temp_dir) {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::FILE);
|
||||
|
||||
ScopedTempFile pdf_file = CreateTempFile(temp_dir);
|
||||
if (!pdf_file ||
|
||||
static_cast<int>(data->size()) !=
|
||||
pdf_file->WriteAtCurrentPos(data->front_as<char>(), 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<char> data(size);
|
||||
if (file_->ReadAtCurrentPos(data.data(), data.size()) != size)
|
||||
return false;
|
||||
return emf->InitFromData(data.data(), data.size());
|
||||
}
|
||||
|
||||
PdfToEmfUtilityProcessHostClient::PdfToEmfUtilityProcessHostClient(
|
||||
base::WeakPtr<PdfToEmfConverterImpl> converter,
|
||||
const PdfRenderSettings& settings)
|
||||
: converter_(converter), settings_(settings) {
|
||||
}
|
||||
|
||||
PdfToEmfUtilityProcessHostClient::~PdfToEmfUtilityProcessHostClient() {
|
||||
}
|
||||
|
||||
void PdfToEmfUtilityProcessHostClient::Start(
|
||||
const scoped_refptr<base::RefCountedMemory>& 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<base::RefCountedMemory> 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<MetafilePlayer> 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<base::RefCountedMemory>& 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> PdfToEmfConverter::CreateDefault() {
|
||||
return scoped_ptr<PdfToEmfConverter>(new PdfToEmfConverterImpl());
|
||||
}
|
||||
|
||||
} // namespace printing
|
48
chromium_src/chrome/browser/printing/pdf_to_emf_converter.h
Normal file
48
chromium_src/chrome/browser/printing/pdf_to_emf_converter.h
Normal file
|
@ -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<void(int page_count)> StartCallback;
|
||||
typedef base::Callback<void(int page_number,
|
||||
float scale_factor,
|
||||
scoped_ptr<MetafilePlayer> emf)> GetPageCallback;
|
||||
|
||||
virtual ~PdfToEmfConverter();
|
||||
|
||||
static scoped_ptr<PdfToEmfConverter> 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<base::RefCountedMemory>& 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_
|
|
@ -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<base::RefCountedMemory>& 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<PdfToEmfConverter> converter_;
|
||||
};
|
||||
|
||||
void PrintJob::StartPdfToEmfConversion(
|
||||
const scoped_refptr<base::RefCountedMemory>& 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<MetafilePlayer> 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.
|
||||
|
|
|
@ -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<base::RefCountedMemory>& 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<MetafilePlayer> 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<PdfToEmfState> ptd_to_emf_state_;
|
||||
#endif // OS_WIN
|
||||
|
||||
// Used at shutdown so that we can quit a nested message loop.
|
||||
base::WeakPtrFactory<PrintJob> quit_factory_;
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
169
chromium_src/chrome/common/chrome_utility_messages.h
Normal file
169
chromium_src/chrome/common/chrome_utility_messages.h
Normal file
|
@ -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 <Windows.h>
|
||||
#endif // defined(OS_WIN)
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#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<Tuple<base::string16, base::string16>>
|
||||
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<unsigned char> /* 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<unsigned char>) // 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<base::FilePath> /* 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)
|
|
@ -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
|
||||
|
|
144
chromium_src/chrome/utility/printing_handler.cc
Normal file
144
chromium_src/chrome/utility/printing_handler.cc
Normal file
|
@ -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<int>::max())
|
||||
return 0;
|
||||
int length = static_cast<int>(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
|
59
chromium_src/chrome/utility/printing_handler.h
Normal file
59
chromium_src/chrome/utility/printing_handler.h
Normal file
|
@ -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<char> pdf_data_;
|
||||
printing::PdfRenderSettings pdf_rendering_settings_;
|
||||
#endif
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(PrintingHandler);
|
||||
};
|
||||
|
||||
#endif // CHROME_UTILITY_PRINTING_HANDLER_H_
|
21
chromium_src/chrome/utility/utility_message_handler.h
Normal file
21
chromium_src/chrome/utility/utility_message_handler.h
Normal file
|
@ -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_
|
|
@ -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',
|
||||
|
|
Loading…
Reference in a new issue