Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(229)

Side by Side Diff: chrome/browser/printing/pdf_to_emf_converter.cc

Issue 255543006: Printing on Windows via PDF (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: tidy Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/local_discovery/pwg_raster_converter.h" 5 #include "chrome/browser/printing/pdf_to_emf_converter.h"
6 6
7 #include "base/bind_helpers.h" 7 #include "base/bind_helpers.h"
8 #include "base/cancelable_callback.h" 8 #include "base/cancelable_callback.h"
9 #include "base/file_util.h" 9 #include "base/file_util.h"
10 #include "base/files/file.h" 10 #include "base/files/file.h"
11 #include "base/files/scoped_temp_dir.h" 11 #include "base/files/scoped_temp_dir.h"
12 #include "base/logging.h" 12 #include "base/logging.h"
13 #include "chrome/common/chrome_utility_messages.h" 13 #include "chrome/common/chrome_utility_messages.h"
14 #include "content/public/browser/browser_thread.h" 14 #include "content/public/browser/browser_thread.h"
15 #include "content/public/browser/child_process_data.h" 15 #include "content/public/browser/child_process_data.h"
16 #include "content/public/browser/utility_process_host.h" 16 #include "content/public/browser/utility_process_host.h"
17 #include "content/public/browser/utility_process_host_client.h" 17 #include "content/public/browser/utility_process_host_client.h"
18 18
19 namespace local_discovery { 19 namespace printing {
20 20
21 namespace { 21 namespace {
22 22
23 using content::BrowserThread; 23 using content::BrowserThread;
24 24
25 class FileHandlers { 25 class FileHandlers {
26 public: 26 public:
27 FileHandlers() {} 27 FileHandlers() {}
28 28
29 ~FileHandlers() { 29 ~FileHandlers() {
30 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 30 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
31 } 31 }
32 32
33 void Init(base::RefCountedMemory* data); 33 void Init(base::RefCountedMemory* data);
34 bool IsValid(); 34 bool IsValid();
35 35
36 base::FilePath GetPwgPath() const { 36 base::FilePath GetEmfPath() const {
37 return temp_dir_.path().AppendASCII("output.pwg"); 37 return temp_dir_.path().AppendASCII("output.emf");
38 } 38 }
39 39
40 base::FilePath GetPdfPath() const { 40 base::FilePath GetPdfPath() const {
41 return temp_dir_.path().AppendASCII("input.pdf"); 41 return temp_dir_.path().AppendASCII("input.pdf");
42 } 42 }
43 43
44 IPC::PlatformFileForTransit GetPdfForProcess(base::ProcessHandle process) { 44 IPC::PlatformFileForTransit GetPdfForProcess(base::ProcessHandle process) {
45 DCHECK(pdf_file_.IsValid()); 45 DCHECK(pdf_file_.IsValid());
46 IPC::PlatformFileForTransit transit = 46 IPC::PlatformFileForTransit transit =
47 IPC::TakeFileHandleForProcess(pdf_file_.Pass(), process); 47 IPC::TakeFileHandleForProcess(pdf_file_.Pass(), process);
48 return transit; 48 return transit;
49 } 49 }
50 50
51 IPC::PlatformFileForTransit GetPwgForProcess(base::ProcessHandle process) { 51 const base::FilePath& GetBasePath() const {
52 DCHECK(pwg_file_.IsValid()); 52 return temp_dir_.path();
53 IPC::PlatformFileForTransit transit =
54 IPC::TakeFileHandleForProcess(pwg_file_.Pass(), process);
55 return transit;
56 } 53 }
57 54
58 private: 55 private:
59 base::ScopedTempDir temp_dir_; 56 base::ScopedTempDir temp_dir_;
60 base::File pdf_file_; 57 base::File pdf_file_;
61 base::File pwg_file_;
62 }; 58 };
63 59
64 void FileHandlers::Init(base::RefCountedMemory* data) { 60 void FileHandlers::Init(base::RefCountedMemory* data) {
65 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 61 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
66 62
67 if (!temp_dir_.CreateUniqueTempDir()) { 63 if (!temp_dir_.CreateUniqueTempDir()) {
68 return; 64 return;
69 } 65 }
70 66
71 if (static_cast<int>(data->size()) != 67 if (static_cast<int>(data->size()) !=
72 base::WriteFile(GetPdfPath(), data->front_as<char>(), data->size())) { 68 base::WriteFile(GetPdfPath(), data->front_as<char>(), data->size())) {
73 return; 69 return;
74 } 70 }
75 71
76 // Reopen in read only mode. 72 // Reopen in read only mode.
77 pdf_file_.Initialize(GetPdfPath(), 73 pdf_file_.Initialize(GetPdfPath(),
78 base::File::FLAG_OPEN | base::File::FLAG_READ); 74 base::File::FLAG_OPEN | base::File::FLAG_READ);
79 pwg_file_.Initialize(
80 GetPwgPath(),
81 base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_APPEND);
82 } 75 }
83 76
84 bool FileHandlers::IsValid() { 77 bool FileHandlers::IsValid() {
85 return pdf_file_.IsValid() && pwg_file_.IsValid(); 78 return pdf_file_.IsValid();
86 } 79 }
87 80
88 // Converts PDF into PWG raster. 81 // Converts PDF into EMF.
89 // Class uses 3 threads: UI, IO and FILE. 82 // Class uses 3 threads: UI, IO and FILE.
90 // Internal workflow is following: 83 // Internal workflow is following:
91 // 1. Create instance on the UI thread. (files_, settings_,) 84 // 1. Create instance on the UI thread. (files_, settings_,)
92 // 2. Create file on the FILE thread. 85 // 2. Create file on the FILE thread.
93 // 3. Start utility process and start conversion on the IO thread. 86 // 3. Start utility process and start conversion on the IO thread.
94 // 4. Run result callback on the UI thread. 87 // 4. Run result callback on the UI thread.
95 // 5. Instance is destroyed from any thread that has the last reference. 88 // 5. Instance is destroyed from any thread that has the last reference.
96 // 6. FileHandlers destroyed on the FILE thread. 89 // 6. FileHandlers destroyed on the FILE thread.
97 // This step posts |FileHandlers| to be destroyed on the FILE thread. 90 // This step posts |FileHandlers| to be destroyed on the FILE thread.
98 // All these steps work sequentially, so no data should be accessed 91 // All these steps work sequentially, so no data should be accessed
99 // simultaneously by several threads. 92 // simultaneously by several threads.
100 class PwgUtilityProcessHostClient : public content::UtilityProcessHostClient { 93 class PdfToEmfUtilityProcessHostClient
94 : public content::UtilityProcessHostClient {
101 public: 95 public:
102 explicit PwgUtilityProcessHostClient( 96 explicit PdfToEmfUtilityProcessHostClient(
103 const printing::PdfRenderSettings& settings, 97 const printing::PdfRenderSettings& settings);
104 const printing::PwgRasterSettings& bitmap_settings);
105 98
106 void Convert(base::RefCountedMemory* data, 99 void Convert(base::RefCountedMemory* data,
107 const PWGRasterConverter::ResultCallback& callback); 100 const PdfToEmfConverter::ResultCallback& callback);
108 101
109 // UtilityProcessHostClient implementation. 102 // UtilityProcessHostClient implementation.
110 virtual void OnProcessCrashed(int exit_code) OVERRIDE; 103 virtual void OnProcessCrashed(int exit_code) OVERRIDE;
111 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; 104 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
112 105
113 private: 106 private:
114 virtual ~PwgUtilityProcessHostClient(); 107 virtual ~PdfToEmfUtilityProcessHostClient();
115 108
116 // Message handlers. 109 // Message handlers.
117 void OnProcessStarted(); 110 void OnProcessStarted();
118 void OnSucceeded(); 111 void OnSucceeded(int highest_rendered_page_number, double scale_factor);
119 void OnFailed(); 112 void OnFailed();
120 113
121 void RunCallback(bool success); 114 void RunCallback(int highest_rendered_page_number, double scale_factor);
122 115
123 void StartProcessOnIOThread(); 116 void StartProcessOnIOThread();
124 117
125 void RunCallbackOnUIThread(bool success); 118 void RunCallbackOnUIThread(int highest_rendered_page_number,
119 double scale_factor);
126 void OnFilesReadyOnUIThread(); 120 void OnFilesReadyOnUIThread();
127 121
128 scoped_ptr<FileHandlers> files_; 122 scoped_ptr<FileHandlers> files_;
129 printing::PdfRenderSettings settings_; 123 printing::PdfRenderSettings settings_;
130 printing::PwgRasterSettings bitmap_settings_; 124 PdfToEmfConverter::ResultCallback callback_;
131 PWGRasterConverter::ResultCallback callback_;
132 base::WeakPtr<content::UtilityProcessHost> utility_process_host_; 125 base::WeakPtr<content::UtilityProcessHost> utility_process_host_;
133 126
134 DISALLOW_COPY_AND_ASSIGN(PwgUtilityProcessHostClient); 127 DISALLOW_COPY_AND_ASSIGN(PdfToEmfUtilityProcessHostClient);
135 }; 128 };
136 129
137 PwgUtilityProcessHostClient::PwgUtilityProcessHostClient( 130 PdfToEmfUtilityProcessHostClient::PdfToEmfUtilityProcessHostClient(
138 const printing::PdfRenderSettings& settings, 131 const printing::PdfRenderSettings& settings)
139 const printing::PwgRasterSettings& bitmap_settings) 132 : settings_(settings) {}
140 : settings_(settings), bitmap_settings_(bitmap_settings) {} 133
141 134 PdfToEmfUtilityProcessHostClient::~PdfToEmfUtilityProcessHostClient() {
142 PwgUtilityProcessHostClient::~PwgUtilityProcessHostClient() {
143 // Delete temp directory. 135 // Delete temp directory.
144 BrowserThread::DeleteSoon(BrowserThread::FILE, FROM_HERE, files_.release()); 136 BrowserThread::DeleteSoon(BrowserThread::FILE, FROM_HERE, files_.release());
145 } 137 }
146 138
147 void PwgUtilityProcessHostClient::Convert( 139 void PdfToEmfUtilityProcessHostClient::Convert(
148 base::RefCountedMemory* data, 140 base::RefCountedMemory* data,
149 const PWGRasterConverter::ResultCallback& callback) { 141 const PdfToEmfConverter::ResultCallback& callback) {
150 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 142 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
151 callback_ = callback; 143 callback_ = callback;
152 CHECK(!files_); 144 CHECK(!files_);
153 files_.reset(new FileHandlers()); 145 files_.reset(new FileHandlers());
154 BrowserThread::PostTaskAndReply( 146 BrowserThread::PostTaskAndReply(
155 BrowserThread::FILE, FROM_HERE, 147 BrowserThread::FILE,
156 base::Bind(&FileHandlers::Init, base::Unretained(files_.get()), 148 FROM_HERE,
149 base::Bind(&FileHandlers::Init,
150 base::Unretained(files_.get()),
157 make_scoped_refptr(data)), 151 make_scoped_refptr(data)),
158 base::Bind(&PwgUtilityProcessHostClient::OnFilesReadyOnUIThread, this)); 152 base::Bind(&PdfToEmfUtilityProcessHostClient::OnFilesReadyOnUIThread,
159 } 153 this));
160 154 }
161 void PwgUtilityProcessHostClient::OnProcessCrashed(int exit_code) { 155
156 void PdfToEmfUtilityProcessHostClient::OnProcessCrashed(int exit_code) {
162 OnFailed(); 157 OnFailed();
163 } 158 }
164 159
165 bool PwgUtilityProcessHostClient::OnMessageReceived( 160 bool PdfToEmfUtilityProcessHostClient::OnMessageReceived(
166 const IPC::Message& message) { 161 const IPC::Message& message) {
167 bool handled = true; 162 bool handled = true;
168 IPC_BEGIN_MESSAGE_MAP(PwgUtilityProcessHostClient, message) 163 IPC_BEGIN_MESSAGE_MAP(PdfToEmfUtilityProcessHostClient, message)
169 IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ProcessStarted, OnProcessStarted) 164 IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ProcessStarted, OnProcessStarted)
170 IPC_MESSAGE_HANDLER( 165 IPC_MESSAGE_HANDLER(
171 ChromeUtilityHostMsg_RenderPDFPagesToPWGRaster_Succeeded, OnSucceeded) 166 ChromeUtilityHostMsg_RenderPDFPagesToMetafile_Succeeded, OnSucceeded)
172 IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_RenderPDFPagesToPWGRaster_Failed, 167 IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_RenderPDFPagesToMetafile_Failed,
173 OnFailed) 168 OnFailed)
174 IPC_MESSAGE_UNHANDLED(handled = false) 169 IPC_MESSAGE_UNHANDLED(handled = false)
175 IPC_END_MESSAGE_MAP() 170 IPC_END_MESSAGE_MAP()
176 return handled; 171 return handled;
177 } 172 }
178 173
179 void PwgUtilityProcessHostClient::OnProcessStarted() { 174 void PdfToEmfUtilityProcessHostClient::OnProcessStarted() {
180 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 175 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
181 if (!utility_process_host_) { 176 if (!utility_process_host_) {
182 RunCallbackOnUIThread(false); 177 RunCallbackOnUIThread(-1, 0.0);
183 return; 178 return;
184 } 179 }
185 180
186 base::ProcessHandle process = utility_process_host_->GetData().handle; 181 base::ProcessHandle process = utility_process_host_->GetData().handle;
187 utility_process_host_->Send(new ChromeUtilityMsg_RenderPDFPagesToPWGRaster( 182 // Only converting one page at a time.
188 files_->GetPdfForProcess(process), 183 printing::PageRange page_range;
189 settings_, 184 page_range.from = 0;
190 bitmap_settings_, 185 page_range.to = 0;
191 files_->GetPwgForProcess(process))); 186 std::vector<printing::PageRange> range;
187 range.push_back(page_range);
188 utility_process_host_->Send(
189 new ChromeUtilityMsg_RenderPDFToMetafile(
190 files_->GetPdfForProcess(process),
191 files_->GetEmfPath(),
192 settings_));
192 utility_process_host_.reset(); 193 utility_process_host_.reset();
193 } 194 }
194 195
195 void PwgUtilityProcessHostClient::OnSucceeded() { 196 void PdfToEmfUtilityProcessHostClient::OnSucceeded(
196 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 197 int highest_rendered_page_number,
197 RunCallback(true); 198 double scale_factor) {
198 } 199 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
199 200 RunCallback(highest_rendered_page_number, scale_factor);
Vitaly Buka (NO REVIEWS) 2014/05/13 23:54:33 why do you need highest_rendered_page_number if on
scottmg 2014/05/14 00:34:48 Ah, oops, that one-page code above was old/unused.
200 void PwgUtilityProcessHostClient::OnFailed() { 201 }
201 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 202
202 RunCallback(false); 203 void PdfToEmfUtilityProcessHostClient::OnFailed() {
203 } 204 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
204 205 RunCallback(-1, 0.0);
205 void PwgUtilityProcessHostClient::OnFilesReadyOnUIThread() { 206 }
207
208 void PdfToEmfUtilityProcessHostClient::OnFilesReadyOnUIThread() {
206 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 209 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
207 if (!files_->IsValid()) { 210 if (!files_->IsValid()) {
208 RunCallbackOnUIThread(false); 211 RunCallbackOnUIThread(-1, 0.0);
209 return; 212 return;
210 } 213 }
211 BrowserThread::PostTask( 214 BrowserThread::PostTask(
212 BrowserThread::IO, FROM_HERE, 215 BrowserThread::IO,
213 base::Bind(&PwgUtilityProcessHostClient::StartProcessOnIOThread, this)); 216 FROM_HERE,
214 } 217 base::Bind(&PdfToEmfUtilityProcessHostClient::StartProcessOnIOThread,
215 218 this));
216 void PwgUtilityProcessHostClient::StartProcessOnIOThread() { 219 }
220
221 void PdfToEmfUtilityProcessHostClient::StartProcessOnIOThread() {
217 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 222 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
218 utility_process_host_ = 223 utility_process_host_ =
219 content::UtilityProcessHost::Create( 224 content::UtilityProcessHost::Create(
220 this, 225 this,
221 base::MessageLoop::current()->message_loop_proxy())->AsWeakPtr(); 226 base::MessageLoop::current()->message_loop_proxy())->AsWeakPtr();
227 // NOTE: This process _must_ be sandboxed, otherwise the pdf dll will load
228 // gdiplus.dll, change how rendering happens, and not be able to correctly
Vitaly Buka (NO REVIEWS) 2014/05/13 23:54:33 so --no-sandbox will fail printing?
scottmg 2014/05/14 00:34:48 Yes! This took me far too long to figure out as I
Vitaly Buka (NO REVIEWS) 2014/05/14 03:51:18 I guess we need to check this in PDF module. We ca
229 // generate when sent to a metafile DC.
230 utility_process_host_->SetExposedDir(files_->GetBasePath());
222 utility_process_host_->Send(new ChromeUtilityMsg_StartupPing); 231 utility_process_host_->Send(new ChromeUtilityMsg_StartupPing);
223 } 232 }
224 233
225 void PwgUtilityProcessHostClient::RunCallback(bool success) { 234 void PdfToEmfUtilityProcessHostClient::RunCallback(
235 int highest_rendered_page_number,
236 double scale_factor) {
226 BrowserThread::PostTask( 237 BrowserThread::PostTask(
227 BrowserThread::UI, FROM_HERE, 238 BrowserThread::UI,
228 base::Bind(&PwgUtilityProcessHostClient::RunCallbackOnUIThread, this, 239 FROM_HERE,
229 success)); 240 base::Bind(&PdfToEmfUtilityProcessHostClient::RunCallbackOnUIThread,
230 } 241 this,
231 242 highest_rendered_page_number,
232 void PwgUtilityProcessHostClient::RunCallbackOnUIThread(bool success) { 243 scale_factor));
244 }
245
246 void PdfToEmfUtilityProcessHostClient::RunCallbackOnUIThread(
247 int highest_rendered_page_number,
248 double scale_factor) {
233 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 249 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
250 std::vector<base::FilePath> page_filenames;
251 for (int i = 0; i <= highest_rendered_page_number; ++i) {
252 page_filenames.push_back(files_->GetEmfPath().InsertBeforeExtensionASCII(
253 base::StringPrintf(".%d", i)));
254 }
234 if (!callback_.is_null()) { 255 if (!callback_.is_null()) {
235 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 256 BrowserThread::PostTask(
236 base::Bind(callback_, success, 257 BrowserThread::UI,
237 files_->GetPwgPath())); 258 FROM_HERE,
259 base::Bind(callback_, scale_factor, page_filenames));
238 callback_.Reset(); 260 callback_.Reset();
239 } 261 }
240 } 262 }
241 263
242 class PWGRasterConverterImpl : public PWGRasterConverter { 264 class PdfToEmfConverterImpl : public PdfToEmfConverter {
243 public: 265 public:
244 PWGRasterConverterImpl(); 266 PdfToEmfConverterImpl();
245 267
246 virtual ~PWGRasterConverterImpl(); 268 virtual ~PdfToEmfConverterImpl();
247 269
248 virtual void Start(base::RefCountedMemory* data, 270 virtual void Start(base::RefCountedMemory* data,
249 const printing::PdfRenderSettings& conversion_settings, 271 const printing::PdfRenderSettings& conversion_settings,
250 const printing::PwgRasterSettings& bitmap_settings,
251 const ResultCallback& callback) OVERRIDE; 272 const ResultCallback& callback) OVERRIDE;
252 273
253 private: 274 private:
254 scoped_refptr<PwgUtilityProcessHostClient> utility_client_; 275 scoped_refptr<PdfToEmfUtilityProcessHostClient> utility_client_;
255 base::CancelableCallback<ResultCallback::RunType> callback_; 276 base::CancelableCallback<ResultCallback::RunType> callback_;
256 277
257 DISALLOW_COPY_AND_ASSIGN(PWGRasterConverterImpl); 278 DISALLOW_COPY_AND_ASSIGN(PdfToEmfConverterImpl);
258 }; 279 };
259 280
260 PWGRasterConverterImpl::PWGRasterConverterImpl() { 281 PdfToEmfConverterImpl::PdfToEmfConverterImpl() {
261 } 282 }
262 283
263 PWGRasterConverterImpl::~PWGRasterConverterImpl() { 284 PdfToEmfConverterImpl::~PdfToEmfConverterImpl() {
264 } 285 }
265 286
266 void PWGRasterConverterImpl::Start( 287 void PdfToEmfConverterImpl::Start(
267 base::RefCountedMemory* data, 288 base::RefCountedMemory* data,
268 const printing::PdfRenderSettings& conversion_settings, 289 const printing::PdfRenderSettings& conversion_settings,
269 const printing::PwgRasterSettings& bitmap_settings,
270 const ResultCallback& callback) { 290 const ResultCallback& callback) {
271 // Rebind cancelable callback to avoid calling callback if 291 // Rebind cancelable callback to avoid calling callback if
272 // PWGRasterConverterImpl is destroyed. 292 // PdfToEmfConverterImpl is destroyed.
273 callback_.Reset(callback); 293 callback_.Reset(callback);
274 utility_client_ = 294 utility_client_ = new PdfToEmfUtilityProcessHostClient(conversion_settings);
275 new PwgUtilityProcessHostClient(conversion_settings, bitmap_settings);
276 utility_client_->Convert(data, callback_.callback()); 295 utility_client_->Convert(data, callback_.callback());
277 } 296 }
278 297
279 } // namespace 298 } // namespace
280 299
281 // static 300 // static
282 scoped_ptr<PWGRasterConverter> PWGRasterConverter::CreateDefault() { 301 scoped_ptr<PdfToEmfConverter> PdfToEmfConverter::CreateDefault() {
283 return scoped_ptr<PWGRasterConverter>(new PWGRasterConverterImpl()); 302 return scoped_ptr<PdfToEmfConverter>(new PdfToEmfConverterImpl());
284 } 303 }
285 304
286 } // namespace local_discovery 305 } // namespace printing
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698