blob: c2ace8eb0e254b76940d8487cd894803bfb18cbf [file] [log] [blame]
[email protected]128bec3c2011-01-20 22:57:351// Copyright (c) 2011 The Chromium Authors. All rights reserved.
license.botbf09a502008-08-24 00:55:552// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
initial.commit09911bf2008-07-26 23:55:294
[email protected]51e8d9352010-10-06 22:21:175#include "printing/printing_context_win.h"
initial.commit09911bf2008-07-26 23:55:296
7#include <winspool.h>
8
[email protected]19f09a62011-05-04 23:37:479#include <algorithm>
10
[email protected]d0767cb542009-10-08 17:38:3011#include "base/i18n/file_util_icu.h"
[email protected]260d1572009-10-09 18:50:3512#include "base/i18n/time_formatting.h"
[email protected]dcccb942009-02-01 18:23:0013#include "base/message_loop.h"
14#include "base/time.h"
[email protected]d9d42992010-09-13 19:39:1915#include "base/utf_string_conversions.h"
[email protected]89f5aa8c2011-03-21 20:58:4416#include "base/values.h"
[email protected]c97e5e82011-04-05 18:50:2317#include "printing/print_job_constants.h"
[email protected]4993f342010-10-26 17:57:5218#include "printing/print_settings_initializer_win.h"
[email protected]8ff1d422009-07-07 21:31:3919#include "printing/printed_document.h"
[email protected]62f2e802011-05-26 14:28:3520#include "skia/ext/platform_device.h"
initial.commit09911bf2008-07-26 23:55:2921
[email protected]e1acf6f2008-10-27 20:43:3322using base::Time;
23
[email protected]bd5baaf2011-04-21 20:48:3324namespace {
25
26// Retrieves the printer's PRINTER_INFO_* structure.
27// Output |level| can be 9 (user-default), 8 (admin-default), or 2
28// (printer-default).
29// |devmode| is a pointer points to the start of DEVMODE structure in
30// |buffer|.
31bool GetPrinterInfo(HANDLE printer,
32 const std::wstring &device_name,
33 int* level,
34 scoped_array<uint8>* buffer,
35 DEVMODE** dev_mode) {
36 DCHECK(buffer);
37
38 // A PRINTER_INFO_9 structure specifying the per-user default printer
39 // settings.
40 printing::PrintingContextWin::GetPrinterHelper(printer, 9, buffer);
41 if (buffer->get()) {
42 PRINTER_INFO_9* info_9 = reinterpret_cast<PRINTER_INFO_9*>(buffer->get());
43 if (info_9->pDevMode != NULL) {
44 *level = 9;
45 *dev_mode = info_9->pDevMode;
46 return true;
47 }
48 buffer->reset();
49 }
50
51 // A PRINTER_INFO_8 structure specifying the global default printer settings.
52 printing::PrintingContextWin::GetPrinterHelper(printer, 8, buffer);
53 if (buffer->get()) {
54 PRINTER_INFO_8* info_8 = reinterpret_cast<PRINTER_INFO_8*>(buffer->get());
55 if (info_8->pDevMode != NULL) {
56 *level = 8;
57 *dev_mode = info_8->pDevMode;
58 return true;
59 }
60 buffer->reset();
61 }
62
63 // A PRINTER_INFO_2 structure specifying the driver's default printer
64 // settings.
65 printing::PrintingContextWin::GetPrinterHelper(printer, 2, buffer);
66 if (buffer->get()) {
67 PRINTER_INFO_2* info_2 = reinterpret_cast<PRINTER_INFO_2*>(buffer->get());
68 if (info_2->pDevMode != NULL) {
69 *level = 2;
70 *dev_mode = info_2->pDevMode;
71 return true;
72 }
73 buffer->reset();
74 }
75
76 return false;
77}
78
79} // anonymous namespace
80
initial.commit09911bf2008-07-26 23:55:2981namespace printing {
82
[email protected]51e8d9352010-10-06 22:21:1783class PrintingContextWin::CallbackHandler : public IPrintDialogCallback,
84 public IObjectWithSite {
initial.commit09911bf2008-07-26 23:55:2985 public:
[email protected]51e8d9352010-10-06 22:21:1786 CallbackHandler(PrintingContextWin& owner, HWND owner_hwnd)
initial.commit09911bf2008-07-26 23:55:2987 : owner_(owner),
88 owner_hwnd_(owner_hwnd),
89 services_(NULL) {
90 }
91
92 ~CallbackHandler() {
93 if (services_)
94 services_->Release();
95 }
96
97 IUnknown* ToIUnknown() {
98 return static_cast<IUnknown*>(static_cast<IPrintDialogCallback*>(this));
99 }
100
101 // IUnknown
102 virtual HRESULT WINAPI QueryInterface(REFIID riid, void**object) {
103 if (riid == IID_IUnknown) {
104 *object = ToIUnknown();
105 } else if (riid == IID_IPrintDialogCallback) {
106 *object = static_cast<IPrintDialogCallback*>(this);
107 } else if (riid == IID_IObjectWithSite) {
108 *object = static_cast<IObjectWithSite*>(this);
109 } else {
110 return E_NOINTERFACE;
111 }
112 return S_OK;
113 }
114
115 // No real ref counting.
116 virtual ULONG WINAPI AddRef() {
117 return 1;
118 }
119 virtual ULONG WINAPI Release() {
120 return 1;
121 }
122
123 // IPrintDialogCallback methods
124 virtual HRESULT WINAPI InitDone() {
125 return S_OK;
126 }
127
128 virtual HRESULT WINAPI SelectionChange() {
129 if (services_) {
130 // TODO(maruel): Get the devmode for the new printer with
131 // services_->GetCurrentDevMode(&devmode, &size), send that information
132 // back to our client and continue. The client needs to recalculate the
133 // number of rendered pages and send back this information here.
134 }
135 return S_OK;
136 }
137
138 virtual HRESULT WINAPI HandleMessage(HWND dialog,
139 UINT message,
140 WPARAM wparam,
141 LPARAM lparam,
142 LRESULT* result) {
143 // Cheap way to retrieve the window handle.
144 if (!owner_.dialog_box_) {
145 // The handle we receive is the one of the groupbox in the General tab. We
146 // need to get the grand-father to get the dialog box handle.
147 owner_.dialog_box_ = GetAncestor(dialog, GA_ROOT);
148 // Trick to enable the owner window. This can cause issues with navigation
149 // events so it may have to be disabled if we don't fix the side-effects.
150 EnableWindow(owner_hwnd_, TRUE);
151 }
152 return S_FALSE;
153 }
154
155 virtual HRESULT WINAPI SetSite(IUnknown* site) {
156 if (!site) {
157 DCHECK(services_);
158 services_->Release();
159 services_ = NULL;
160 // The dialog box is destroying, PrintJob::Worker don't need the handle
161 // anymore.
162 owner_.dialog_box_ = NULL;
163 } else {
164 DCHECK(services_ == NULL);
165 HRESULT hr = site->QueryInterface(IID_IPrintDialogServices,
166 reinterpret_cast<void**>(&services_));
167 DCHECK(SUCCEEDED(hr));
168 }
169 return S_OK;
170 }
171
172 virtual HRESULT WINAPI GetSite(REFIID riid, void** site) {
173 return E_NOTIMPL;
174 }
175
176 private:
[email protected]51e8d9352010-10-06 22:21:17177 PrintingContextWin& owner_;
initial.commit09911bf2008-07-26 23:55:29178 HWND owner_hwnd_;
179 IPrintDialogServices* services_;
180
[email protected]5930cb62009-12-08 02:04:22181 DISALLOW_COPY_AND_ASSIGN(CallbackHandler);
initial.commit09911bf2008-07-26 23:55:29182};
183
[email protected]51e8d9352010-10-06 22:21:17184// static
[email protected]ee5f36e42010-12-03 22:40:37185PrintingContext* PrintingContext::Create(const std::string& app_locale) {
186 return static_cast<PrintingContext*>(new PrintingContextWin(app_locale));
[email protected]51e8d9352010-10-06 22:21:17187}
188
[email protected]ee5f36e42010-12-03 22:40:37189PrintingContextWin::PrintingContextWin(const std::string& app_locale)
190 : PrintingContext(app_locale),
[email protected]51e8d9352010-10-06 22:21:17191 context_(NULL),
initial.commit09911bf2008-07-26 23:55:29192 dialog_box_(NULL),
[email protected]d8254622010-08-13 19:15:46193 print_dialog_func_(&PrintDlgEx) {
initial.commit09911bf2008-07-26 23:55:29194}
195
[email protected]51e8d9352010-10-06 22:21:17196PrintingContextWin::~PrintingContextWin() {
197 ReleaseContext();
initial.commit09911bf2008-07-26 23:55:29198}
199
[email protected]51e8d9352010-10-06 22:21:17200void PrintingContextWin::AskUserForSettings(HWND view,
201 int max_pages,
202 bool has_selection,
203 PrintSettingsCallback* callback) {
initial.commit09911bf2008-07-26 23:55:29204 DCHECK(!in_print_job_);
205 dialog_box_dismissed_ = false;
[email protected]fc7904622010-05-12 19:26:40206
207 HWND window;
208 if (!view || !IsWindow(view)) {
209 // TODO(maruel): bug 1214347 Get the right browser window instead.
210 window = GetDesktopWindow();
211 } else {
212 window = GetAncestor(view, GA_ROOTOWNER);
213 }
214 DCHECK(window);
215
initial.commit09911bf2008-07-26 23:55:29216 // Show the OS-dependent dialog box.
217 // If the user press
218 // - OK, the settings are reset and reinitialized with the new settings. OK is
219 // returned.
220 // - Apply then Cancel, the settings are reset and reinitialized with the new
221 // settings. CANCEL is returned.
222 // - Cancel, the settings are not changed, the previous setting, if it was
223 // initialized before, are kept. CANCEL is returned.
224 // On failure, the settings are reset and FAILED is returned.
225 PRINTDLGEX dialog_options = { sizeof(PRINTDLGEX) };
226 dialog_options.hwndOwner = window;
[email protected]c8ad40c2009-06-08 17:05:21227 // Disable options we don't support currently.
initial.commit09911bf2008-07-26 23:55:29228 // TODO(maruel): Reuse the previously loaded settings!
229 dialog_options.Flags = PD_RETURNDC | PD_USEDEVMODECOPIESANDCOLLATE |
[email protected]c8ad40c2009-06-08 17:05:21230 PD_NOCURRENTPAGE | PD_HIDEPRINTTOFILE;
231 if (!has_selection)
232 dialog_options.Flags |= PD_NOSELECTION;
233
initial.commit09911bf2008-07-26 23:55:29234 PRINTPAGERANGE ranges[32];
235 dialog_options.nStartPage = START_PAGE_GENERAL;
236 if (max_pages) {
237 // Default initialize to print all the pages.
238 memset(ranges, 0, sizeof(ranges));
239 ranges[0].nFromPage = 1;
240 ranges[0].nToPage = max_pages;
241 dialog_options.nPageRanges = 1;
242 dialog_options.nMaxPageRanges = arraysize(ranges);
[email protected]3a0e4a32009-06-09 19:07:05243 dialog_options.nMinPage = 1;
initial.commit09911bf2008-07-26 23:55:29244 dialog_options.nMaxPage = max_pages;
245 dialog_options.lpPageRanges = ranges;
246 } else {
247 // No need to bother, we don't know how many pages are available.
248 dialog_options.Flags |= PD_NOPAGENUMS;
249 }
250
[email protected]128bec3c2011-01-20 22:57:35251 if ((*print_dialog_func_)(&dialog_options) != S_OK) {
252 ResetSettings();
253 callback->Run(FAILED);
initial.commit09911bf2008-07-26 23:55:29254 }
[email protected]128bec3c2011-01-20 22:57:35255
initial.commit09911bf2008-07-26 23:55:29256 // TODO(maruel): Support PD_PRINTTOFILE.
[email protected]b7191422010-09-21 19:18:05257 callback->Run(ParseDialogResultEx(dialog_options));
initial.commit09911bf2008-07-26 23:55:29258}
259
[email protected]51e8d9352010-10-06 22:21:17260PrintingContext::Result PrintingContextWin::UseDefaultSettings() {
initial.commit09911bf2008-07-26 23:55:29261 DCHECK(!in_print_job_);
262
263 PRINTDLG dialog_options = { sizeof(PRINTDLG) };
264 dialog_options.Flags = PD_RETURNDC | PD_RETURNDEFAULT;
[email protected]ff3ccc22011-04-18 21:35:48265 if (PrintDlg(&dialog_options))
266 return ParseDialogResult(dialog_options);
267
268 // No default printer configured, do we have any printers at all?
269 DWORD bytes_needed = 0;
270 DWORD count_returned = 0;
271 (void)::EnumPrinters(PRINTER_ENUM_LOCAL|PRINTER_ENUM_CONNECTIONS,
272 NULL, 2, NULL, 0, &bytes_needed, &count_returned);
273 if (bytes_needed) {
274 DCHECK(bytes_needed >= count_returned * sizeof(PRINTER_INFO_2));
275 scoped_array<BYTE> printer_info_buffer(new BYTE[bytes_needed]);
276 BOOL ret = ::EnumPrinters(PRINTER_ENUM_LOCAL|PRINTER_ENUM_CONNECTIONS,
277 NULL, 2, printer_info_buffer.get(),
278 bytes_needed, &bytes_needed,
279 &count_returned);
280 if (ret && count_returned) { // have printers
281 // Open the first successfully found printer.
[email protected]a5e0ef572011-04-21 18:38:54282 for (DWORD count = 0; count < count_returned; ++count) {
283 PRINTER_INFO_2* info_2 = reinterpret_cast<PRINTER_INFO_2*>(
[email protected]ff3ccc22011-04-18 21:35:48284 printer_info_buffer.get() + count * sizeof(PRINTER_INFO_2));
285 std::wstring printer_name = info_2->pPrinterName;
286 if (info_2->pDevMode == NULL || printer_name.length() == 0)
287 continue;
288 if (!AllocateContext(printer_name, info_2->pDevMode, &context_))
289 break;
290 if (InitializeSettings(*info_2->pDevMode, printer_name,
[email protected]a5e0ef572011-04-21 18:38:54291 NULL, 0, false)) {
[email protected]ff3ccc22011-04-18 21:35:48292 break;
[email protected]ff3ccc22011-04-18 21:35:48293 }
[email protected]a5e0ef572011-04-21 18:38:54294 ReleaseContext();
[email protected]ff3ccc22011-04-18 21:35:48295 }
296 if (context_)
297 return OK;
298 }
initial.commit09911bf2008-07-26 23:55:29299 }
[email protected]ff3ccc22011-04-18 21:35:48300
301 ResetSettings();
302 return FAILED;
initial.commit09911bf2008-07-26 23:55:29303}
304
[email protected]55b23a02011-08-17 23:09:36305PrintingContext::Result PrintingContextWin::UpdatePrinterSettings(
[email protected]bd5baaf2011-04-21 20:48:33306 const DictionaryValue& job_settings,
307 const PageRanges& ranges) {
[email protected]7868ecab2011-03-05 00:12:53308 DCHECK(!in_print_job_);
309
[email protected]19f09a62011-05-04 23:37:47310 bool collate;
[email protected]f3256b0d82011-09-04 23:36:29311 int color;
[email protected]19f09a62011-05-04 23:37:47312 bool landscape;
313 bool print_to_pdf;
314 int copies;
315 int duplex_mode;
[email protected]9f47bbf2011-05-06 19:03:17316 string16 device_name;
[email protected]19f09a62011-05-04 23:37:47317
318 if (!job_settings.GetBoolean(kSettingLandscape, &landscape) ||
319 !job_settings.GetBoolean(kSettingCollate, &collate) ||
[email protected]f3256b0d82011-09-04 23:36:29320 !job_settings.GetInteger(kSettingColor, &color) ||
[email protected]19f09a62011-05-04 23:37:47321 !job_settings.GetBoolean(kSettingPrintToPDF, &print_to_pdf) ||
[email protected]bd5baaf2011-04-21 20:48:33322 !job_settings.GetInteger(kSettingDuplexMode, &duplex_mode) ||
[email protected]19f09a62011-05-04 23:37:47323 !job_settings.GetInteger(kSettingCopies, &copies) ||
[email protected]9f47bbf2011-05-06 19:03:17324 !job_settings.GetString(kSettingDeviceName, &device_name)) {
[email protected]c48bee22011-03-29 02:36:26325 return OnError();
[email protected]bd5baaf2011-04-21 20:48:33326 }
[email protected]37a401bf2011-03-31 16:12:36327
[email protected]71dfff72011-07-23 01:27:27328 bool print_to_cloud = job_settings.HasKey(printing::kSettingCloudPrintId);
329
330 if (print_to_pdf || print_to_cloud) {
[email protected]30aaa81a2011-05-03 21:08:39331 // Pseudo printer: handle orientation and ranges only.
[email protected]19f09a62011-05-04 23:37:47332 settings_.SetOrientation(landscape);
[email protected]30aaa81a2011-05-03 21:08:39333 settings_.ranges = ranges;
334 return OK;
335 }
336
[email protected]bd5baaf2011-04-21 20:48:33337 // Underlying |settings_| do not have these attributes, so we need to
338 // operate on printer directly, which involves reloading settings.
339 // Therefore, reset the settings anyway.
340 ResetSettings();
[email protected]c48bee22011-03-29 02:36:26341
[email protected]bd5baaf2011-04-21 20:48:33342 HANDLE printer;
[email protected]9f47bbf2011-05-06 19:03:17343 LPWSTR device_name_wide = const_cast<wchar_t*>(device_name.c_str());
344 if (!OpenPrinter(device_name_wide, &printer, NULL))
[email protected]bd5baaf2011-04-21 20:48:33345 return OnError();
[email protected]afbdbf112011-03-28 22:09:37346
[email protected]30aaa81a2011-05-03 21:08:39347 // Make printer changes local to Chrome.
348 // See MSDN documentation regarding DocumentProperties.
[email protected]bd5baaf2011-04-21 20:48:33349 scoped_array<uint8> buffer;
[email protected]bd5baaf2011-04-21 20:48:33350 DEVMODE* dev_mode = NULL;
[email protected]9f47bbf2011-05-06 19:03:17351 LONG buffer_size = DocumentProperties(NULL, printer, device_name_wide,
[email protected]30aaa81a2011-05-03 21:08:39352 NULL, NULL, 0);
[email protected]bcf63422011-06-14 18:57:39353 if (buffer_size > 0) {
[email protected]30aaa81a2011-05-03 21:08:39354 buffer.reset(new uint8[buffer_size]);
355 memset(buffer.get(), 0, buffer_size);
[email protected]9f47bbf2011-05-06 19:03:17356 if (DocumentProperties(NULL, printer, device_name_wide,
[email protected]30aaa81a2011-05-03 21:08:39357 reinterpret_cast<PDEVMODE>(buffer.get()), NULL,
358 DM_OUT_BUFFER) == IDOK) {
359 dev_mode = reinterpret_cast<PDEVMODE>(buffer.get());
360 }
361 }
362 if (dev_mode == NULL) {
363 buffer.reset();
[email protected]bd5baaf2011-04-21 20:48:33364 ClosePrinter(printer);
365 return OnError();
366 }
[email protected]7868ecab2011-03-05 00:12:53367
[email protected]f3256b0d82011-09-04 23:36:29368 if (color == printing::GRAY)
369 dev_mode->dmColor = DMCOLOR_MONOCHROME;
370 else
371 dev_mode->dmColor = DMCOLOR_COLOR;
372
[email protected]bd5baaf2011-04-21 20:48:33373 dev_mode->dmCopies = std::max(copies, 1);
374 if (dev_mode->dmCopies > 1) // do not change collate unless multiple copies
[email protected]19f09a62011-05-04 23:37:47375 dev_mode->dmCollate = collate ? DMCOLLATE_TRUE : DMCOLLATE_FALSE;
[email protected]bd5baaf2011-04-21 20:48:33376 switch (duplex_mode) {
377 case LONG_EDGE:
378 dev_mode->dmDuplex = DMDUP_VERTICAL;
379 break;
380 case SHORT_EDGE:
381 dev_mode->dmDuplex = DMDUP_HORIZONTAL;
382 break;
383 default: // simplex
384 dev_mode->dmDuplex = DMDUP_SIMPLEX;
385 break;
386 }
[email protected]19f09a62011-05-04 23:37:47387 dev_mode->dmOrientation = landscape ? DMORIENT_LANDSCAPE : DMORIENT_PORTRAIT;
[email protected]bd5baaf2011-04-21 20:48:33388
[email protected]30aaa81a2011-05-03 21:08:39389 // Update data using DocumentProperties.
[email protected]9f47bbf2011-05-06 19:03:17390 if (DocumentProperties(NULL, printer, device_name_wide, dev_mode, dev_mode,
[email protected]30aaa81a2011-05-03 21:08:39391 DM_IN_BUFFER | DM_OUT_BUFFER) != IDOK) {
392 ClosePrinter(printer);
393 return OnError();
394 }
395
[email protected]bd5baaf2011-04-21 20:48:33396 // Set printer then refresh printer settings.
[email protected]9f47bbf2011-05-06 19:03:17397 if (!AllocateContext(device_name, dev_mode, &context_)) {
[email protected]bd5baaf2011-04-21 20:48:33398 ClosePrinter(printer);
399 return OnError();
400 }
401 PrintSettingsInitializerWin::InitPrintSettings(context_, *dev_mode,
[email protected]9f47bbf2011-05-06 19:03:17402 ranges, device_name,
[email protected]bd5baaf2011-04-21 20:48:33403 false, &settings_);
404 ClosePrinter(printer);
[email protected]afbdbf112011-03-28 22:09:37405 return OK;
[email protected]7868ecab2011-03-05 00:12:53406}
407
[email protected]51e8d9352010-10-06 22:21:17408PrintingContext::Result PrintingContextWin::InitWithSettings(
initial.commit09911bf2008-07-26 23:55:29409 const PrintSettings& settings) {
410 DCHECK(!in_print_job_);
[email protected]4993f342010-10-26 17:57:52411
initial.commit09911bf2008-07-26 23:55:29412 settings_ = settings;
[email protected]4993f342010-10-26 17:57:52413
414 // TODO(maruel): settings_.ToDEVMODE()
initial.commit09911bf2008-07-26 23:55:29415 HANDLE printer;
416 if (!OpenPrinter(const_cast<wchar_t*>(settings_.device_name().c_str()),
417 &printer,
418 NULL))
419 return FAILED;
420
421 Result status = OK;
422
423 if (!GetPrinterSettings(printer, settings_.device_name()))
424 status = FAILED;
425
426 // Close the printer after retrieving the context.
427 ClosePrinter(printer);
428
429 if (status != OK)
430 ResetSettings();
431 return status;
432}
433
[email protected]51e8d9352010-10-06 22:21:17434PrintingContext::Result PrintingContextWin::NewDocument(
[email protected]d9d42992010-09-13 19:39:19435 const string16& document_name) {
initial.commit09911bf2008-07-26 23:55:29436 DCHECK(!in_print_job_);
[email protected]b75dca82009-10-13 18:46:21437 if (!context_)
[email protected]c8ad40c2009-06-08 17:05:21438 return OnError();
initial.commit09911bf2008-07-26 23:55:29439
440 // Set the flag used by the AbortPrintJob dialog procedure.
441 abort_printing_ = false;
442
443 in_print_job_ = true;
444
445 // Register the application's AbortProc function with GDI.
[email protected]b75dca82009-10-13 18:46:21446 if (SP_ERROR == SetAbortProc(context_, &AbortProc))
[email protected]c8ad40c2009-06-08 17:05:21447 return OnError();
initial.commit09911bf2008-07-26 23:55:29448
449 DOCINFO di = { sizeof(DOCINFO) };
[email protected]ea6f72a97c2010-09-28 00:34:47450 const std::wstring& document_name_wide = UTF16ToWide(document_name);
451 di.lpszDocName = document_name_wide.c_str();
initial.commit09911bf2008-07-26 23:55:29452
453 // Is there a debug dump directory specified? If so, force to print to a file.
[email protected]d9d42992010-09-13 19:39:19454 FilePath debug_dump_path = PrintedDocument::debug_dump_path();
initial.commit09911bf2008-07-26 23:55:29455 if (!debug_dump_path.empty()) {
456 // Create a filename.
457 std::wstring filename;
458 Time now(Time::Now());
[email protected]5cca3a52008-08-19 22:35:29459 filename = base::TimeFormatShortDateNumeric(now);
initial.commit09911bf2008-07-26 23:55:29460 filename += L"_";
[email protected]5cca3a52008-08-19 22:35:29461 filename += base::TimeFormatTimeOfDay(now);
initial.commit09911bf2008-07-26 23:55:29462 filename += L"_";
[email protected]d9d42992010-09-13 19:39:19463 filename += UTF16ToWide(document_name);
initial.commit09911bf2008-07-26 23:55:29464 filename += L"_";
465 filename += L"buffer.prn";
[email protected]de2943352009-10-22 23:06:12466 file_util::ReplaceIllegalCharactersInPath(&filename, '_');
[email protected]d9d42992010-09-13 19:39:19467 debug_dump_path.Append(filename);
468 di.lpszOutput = debug_dump_path.value().c_str();
initial.commit09911bf2008-07-26 23:55:29469 }
470
[email protected]daee4972009-07-09 14:28:24471 // No message loop running in unit tests.
472 DCHECK(!MessageLoop::current() ? true :
473 !MessageLoop::current()->NestableTasksAllowed());
474
initial.commit09911bf2008-07-26 23:55:29475 // Begin a print job by calling the StartDoc function.
476 // NOTE: StartDoc() starts a message loop. That causes a lot of problems with
477 // IPC. Make sure recursive task processing is disabled.
[email protected]b75dca82009-10-13 18:46:21478 if (StartDoc(context_, &di) <= 0)
[email protected]c8ad40c2009-06-08 17:05:21479 return OnError();
initial.commit09911bf2008-07-26 23:55:29480
initial.commit09911bf2008-07-26 23:55:29481 return OK;
482}
483
[email protected]51e8d9352010-10-06 22:21:17484PrintingContext::Result PrintingContextWin::NewPage() {
initial.commit09911bf2008-07-26 23:55:29485 if (abort_printing_)
486 return CANCEL;
[email protected]3b52c982010-09-27 20:40:36487 DCHECK(context_);
initial.commit09911bf2008-07-26 23:55:29488 DCHECK(in_print_job_);
489
[email protected]b10c54d2011-03-16 18:22:35490 // Intentional No-op. NativeMetafile::SafePlayback takes care of calling
491 // ::StartPage().
initial.commit09911bf2008-07-26 23:55:29492
initial.commit09911bf2008-07-26 23:55:29493 return OK;
494}
495
[email protected]51e8d9352010-10-06 22:21:17496PrintingContext::Result PrintingContextWin::PageDone() {
initial.commit09911bf2008-07-26 23:55:29497 if (abort_printing_)
498 return CANCEL;
499 DCHECK(in_print_job_);
500
[email protected]b10c54d2011-03-16 18:22:35501 // Intentional No-op. NativeMetafile::SafePlayback takes care of calling
502 // ::EndPage().
503
initial.commit09911bf2008-07-26 23:55:29504 return OK;
505}
506
[email protected]51e8d9352010-10-06 22:21:17507PrintingContext::Result PrintingContextWin::DocumentDone() {
initial.commit09911bf2008-07-26 23:55:29508 if (abort_printing_)
509 return CANCEL;
510 DCHECK(in_print_job_);
[email protected]60745412010-09-27 23:46:07511 DCHECK(context_);
initial.commit09911bf2008-07-26 23:55:29512
513 // Inform the driver that document has ended.
[email protected]b75dca82009-10-13 18:46:21514 if (EndDoc(context_) <= 0)
[email protected]c8ad40c2009-06-08 17:05:21515 return OnError();
initial.commit09911bf2008-07-26 23:55:29516
517 ResetSettings();
518 return OK;
519}
520
[email protected]51e8d9352010-10-06 22:21:17521void PrintingContextWin::Cancel() {
initial.commit09911bf2008-07-26 23:55:29522 abort_printing_ = true;
523 in_print_job_ = false;
[email protected]b75dca82009-10-13 18:46:21524 if (context_)
525 CancelDC(context_);
initial.commit09911bf2008-07-26 23:55:29526 if (dialog_box_) {
527 DestroyWindow(dialog_box_);
528 dialog_box_dismissed_ = true;
529 }
530}
531
[email protected]51e8d9352010-10-06 22:21:17532void PrintingContextWin::ReleaseContext() {
533 if (context_) {
534 DeleteDC(context_);
535 context_ = NULL;
536 }
537}
538
539gfx::NativeDrawingContext PrintingContextWin::context() const {
540 return context_;
initial.commit09911bf2008-07-26 23:55:29541}
542
543// static
[email protected]51e8d9352010-10-06 22:21:17544BOOL PrintingContextWin::AbortProc(HDC hdc, int nCode) {
initial.commit09911bf2008-07-26 23:55:29545 if (nCode) {
546 // TODO(maruel): Need a way to find the right instance to set. Should
547 // leverage PrintJobManager here?
548 // abort_printing_ = true;
549 }
550 return true;
551}
552
[email protected]51e8d9352010-10-06 22:21:17553bool PrintingContextWin::InitializeSettings(const DEVMODE& dev_mode,
554 const std::wstring& new_device_name,
555 const PRINTPAGERANGE* ranges,
556 int number_ranges,
557 bool selection_only) {
[email protected]62f2e802011-05-26 14:28:35558 skia::InitializeDC(context_);
[email protected]b75dca82009-10-13 18:46:21559 DCHECK(GetDeviceCaps(context_, CLIPCAPS));
560 DCHECK(GetDeviceCaps(context_, RASTERCAPS) & RC_STRETCHDIB);
561 DCHECK(GetDeviceCaps(context_, RASTERCAPS) & RC_BITMAP64);
initial.commit09911bf2008-07-26 23:55:29562 // Some printers don't advertise these.
[email protected]b75dca82009-10-13 18:46:21563 // DCHECK(GetDeviceCaps(context_, RASTERCAPS) & RC_SCALING);
564 // DCHECK(GetDeviceCaps(context_, SHADEBLENDCAPS) & SB_CONST_ALPHA);
565 // DCHECK(GetDeviceCaps(context_, SHADEBLENDCAPS) & SB_PIXEL_ALPHA);
initial.commit09911bf2008-07-26 23:55:29566
567 // StretchDIBits() support is needed for printing.
[email protected]b75dca82009-10-13 18:46:21568 if (!(GetDeviceCaps(context_, RASTERCAPS) & RC_STRETCHDIB) ||
569 !(GetDeviceCaps(context_, RASTERCAPS) & RC_BITMAP64)) {
initial.commit09911bf2008-07-26 23:55:29570 NOTREACHED();
571 ResetSettings();
572 return false;
573 }
574
575 DCHECK(!in_print_job_);
[email protected]b75dca82009-10-13 18:46:21576 DCHECK(context_);
initial.commit09911bf2008-07-26 23:55:29577 PageRanges ranges_vector;
[email protected]82270452009-06-19 15:58:01578 if (!selection_only) {
579 // Convert the PRINTPAGERANGE array to a PrintSettings::PageRanges vector.
580 ranges_vector.reserve(number_ranges);
581 for (int i = 0; i < number_ranges; ++i) {
582 PageRange range;
583 // Transfer from 1-based to 0-based.
584 range.from = ranges[i].nFromPage - 1;
585 range.to = ranges[i].nToPage - 1;
586 ranges_vector.push_back(range);
587 }
initial.commit09911bf2008-07-26 23:55:29588 }
[email protected]4993f342010-10-26 17:57:52589
590 PrintSettingsInitializerWin::InitPrintSettings(context_,
591 dev_mode,
592 ranges_vector,
593 new_device_name,
594 selection_only,
595 &settings_);
596
initial.commit09911bf2008-07-26 23:55:29597 return true;
598}
599
[email protected]51e8d9352010-10-06 22:21:17600bool PrintingContextWin::GetPrinterSettings(HANDLE printer,
601 const std::wstring& device_name) {
initial.commit09911bf2008-07-26 23:55:29602 DCHECK(!in_print_job_);
603 scoped_array<uint8> buffer;
[email protected]bd5baaf2011-04-21 20:48:33604 int level = 0;
605 DEVMODE* dev_mode = NULL;
initial.commit09911bf2008-07-26 23:55:29606
[email protected]bd5baaf2011-04-21 20:48:33607 if (GetPrinterInfo(printer, device_name, &level, &buffer, &dev_mode) &&
608 AllocateContext(device_name, dev_mode, &context_)) {
609 return InitializeSettings(*dev_mode, device_name, NULL, 0, false);
initial.commit09911bf2008-07-26 23:55:29610 }
611
[email protected]bd5baaf2011-04-21 20:48:33612 buffer.reset();
initial.commit09911bf2008-07-26 23:55:29613 ResetSettings();
614 return false;
615}
616
[email protected]d8254622010-08-13 19:15:46617// static
[email protected]9f47bbf2011-05-06 19:03:17618bool PrintingContextWin::AllocateContext(const std::wstring& device_name,
[email protected]51e8d9352010-10-06 22:21:17619 const DEVMODE* dev_mode,
620 gfx::NativeDrawingContext* context) {
[email protected]9f47bbf2011-05-06 19:03:17621 *context = CreateDC(L"WINSPOOL", device_name.c_str(), NULL, dev_mode);
[email protected]d8254622010-08-13 19:15:46622 DCHECK(*context);
623 return *context != NULL;
initial.commit09911bf2008-07-26 23:55:29624}
625
[email protected]51e8d9352010-10-06 22:21:17626PrintingContext::Result PrintingContextWin::ParseDialogResultEx(
initial.commit09911bf2008-07-26 23:55:29627 const PRINTDLGEX& dialog_options) {
628 // If the user clicked OK or Apply then Cancel, but not only Cancel.
629 if (dialog_options.dwResultAction != PD_RESULT_CANCEL) {
630 // Start fresh.
631 ResetSettings();
632
633 DEVMODE* dev_mode = NULL;
634 if (dialog_options.hDevMode) {
635 dev_mode =
636 reinterpret_cast<DEVMODE*>(GlobalLock(dialog_options.hDevMode));
637 DCHECK(dev_mode);
638 }
639
640 std::wstring device_name;
641 if (dialog_options.hDevNames) {
642 DEVNAMES* dev_names =
643 reinterpret_cast<DEVNAMES*>(GlobalLock(dialog_options.hDevNames));
644 DCHECK(dev_names);
645 if (dev_names) {
646 device_name =
647 reinterpret_cast<const wchar_t*>(
648 reinterpret_cast<const wchar_t*>(dev_names) +
649 dev_names->wDeviceOffset);
650 GlobalUnlock(dialog_options.hDevNames);
651 }
652 }
653
654 bool success = false;
655 if (dev_mode && !device_name.empty()) {
[email protected]b75dca82009-10-13 18:46:21656 context_ = dialog_options.hDC;
[email protected]c8ad40c2009-06-08 17:05:21657 PRINTPAGERANGE* page_ranges = NULL;
658 DWORD num_page_ranges = 0;
659 bool print_selection_only = false;
initial.commit09911bf2008-07-26 23:55:29660 if (dialog_options.Flags & PD_PAGENUMS) {
[email protected]c8ad40c2009-06-08 17:05:21661 page_ranges = dialog_options.lpPageRanges;
662 num_page_ranges = dialog_options.nPageRanges;
initial.commit09911bf2008-07-26 23:55:29663 }
[email protected]c8ad40c2009-06-08 17:05:21664 if (dialog_options.Flags & PD_SELECTION) {
665 print_selection_only = true;
666 }
667 success = InitializeSettings(*dev_mode,
668 device_name,
[email protected]d8254622010-08-13 19:15:46669 page_ranges,
670 num_page_ranges,
[email protected]c8ad40c2009-06-08 17:05:21671 print_selection_only);
initial.commit09911bf2008-07-26 23:55:29672 }
673
674 if (!success && dialog_options.hDC) {
675 DeleteDC(dialog_options.hDC);
[email protected]b75dca82009-10-13 18:46:21676 context_ = NULL;
initial.commit09911bf2008-07-26 23:55:29677 }
678
679 if (dev_mode) {
680 GlobalUnlock(dialog_options.hDevMode);
681 }
682 } else {
683 if (dialog_options.hDC) {
684 DeleteDC(dialog_options.hDC);
685 }
686 }
687
688 if (dialog_options.hDevMode != NULL)
689 GlobalFree(dialog_options.hDevMode);
690 if (dialog_options.hDevNames != NULL)
691 GlobalFree(dialog_options.hDevNames);
692
693 switch (dialog_options.dwResultAction) {
694 case PD_RESULT_PRINT:
[email protected]b75dca82009-10-13 18:46:21695 return context_ ? OK : FAILED;
initial.commit09911bf2008-07-26 23:55:29696 case PD_RESULT_APPLY:
[email protected]b75dca82009-10-13 18:46:21697 return context_ ? CANCEL : FAILED;
initial.commit09911bf2008-07-26 23:55:29698 case PD_RESULT_CANCEL:
699 return CANCEL;
700 default:
701 return FAILED;
702 }
703}
704
[email protected]51e8d9352010-10-06 22:21:17705PrintingContext::Result PrintingContextWin::ParseDialogResult(
initial.commit09911bf2008-07-26 23:55:29706 const PRINTDLG& dialog_options) {
707 // If the user clicked OK or Apply then Cancel, but not only Cancel.
708 // Start fresh.
709 ResetSettings();
710
711 DEVMODE* dev_mode = NULL;
712 if (dialog_options.hDevMode) {
713 dev_mode =
714 reinterpret_cast<DEVMODE*>(GlobalLock(dialog_options.hDevMode));
715 DCHECK(dev_mode);
716 }
717
718 std::wstring device_name;
719 if (dialog_options.hDevNames) {
720 DEVNAMES* dev_names =
721 reinterpret_cast<DEVNAMES*>(GlobalLock(dialog_options.hDevNames));
722 DCHECK(dev_names);
723 if (dev_names) {
724 device_name =
725 reinterpret_cast<const wchar_t*>(
726 reinterpret_cast<const wchar_t*>(dev_names) +
727 dev_names->wDeviceOffset);
728 GlobalUnlock(dialog_options.hDevNames);
729 }
730 }
731
732 bool success = false;
733 if (dev_mode && !device_name.empty()) {
[email protected]b75dca82009-10-13 18:46:21734 context_ = dialog_options.hDC;
[email protected]c8ad40c2009-06-08 17:05:21735 success = InitializeSettings(*dev_mode, device_name, NULL, 0, false);
initial.commit09911bf2008-07-26 23:55:29736 }
737
738 if (!success && dialog_options.hDC) {
739 DeleteDC(dialog_options.hDC);
[email protected]b75dca82009-10-13 18:46:21740 context_ = NULL;
initial.commit09911bf2008-07-26 23:55:29741 }
742
743 if (dev_mode) {
744 GlobalUnlock(dialog_options.hDevMode);
745 }
746
747 if (dialog_options.hDevMode != NULL)
748 GlobalFree(dialog_options.hDevMode);
749 if (dialog_options.hDevNames != NULL)
750 GlobalFree(dialog_options.hDevNames);
751
[email protected]b75dca82009-10-13 18:46:21752 return context_ ? OK : FAILED;
initial.commit09911bf2008-07-26 23:55:29753}
754
[email protected]d8254622010-08-13 19:15:46755// static
[email protected]51e8d9352010-10-06 22:21:17756void PrintingContextWin::GetPrinterHelper(HANDLE printer, int level,
757 scoped_array<uint8>* buffer) {
[email protected]d8254622010-08-13 19:15:46758 DWORD buf_size = 0;
759 GetPrinter(printer, level, NULL, 0, &buf_size);
760 if (buf_size) {
761 buffer->reset(new uint8[buf_size]);
762 memset(buffer->get(), 0, buf_size);
763 if (!GetPrinter(printer, level, buffer->get(), buf_size, &buf_size)) {
764 buffer->reset();
765 }
766 }
767}
768
initial.commit09911bf2008-07-26 23:55:29769} // namespace printing