blob: 74de8ba7a3d924c6d7f25e8a0b0e0f35d6dfca08 [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]d0767cb542009-10-08 17:38:309#include "base/i18n/file_util_icu.h"
[email protected]260d1572009-10-09 18:50:3510#include "base/i18n/time_formatting.h"
[email protected]dcccb942009-02-01 18:23:0011#include "base/message_loop.h"
12#include "base/time.h"
[email protected]d9d42992010-09-13 19:39:1913#include "base/utf_string_conversions.h"
[email protected]89f5aa8c2011-03-21 20:58:4414#include "base/values.h"
[email protected]c97e5e82011-04-05 18:50:2315#include "printing/print_job_constants.h"
[email protected]4993f342010-10-26 17:57:5216#include "printing/print_settings_initializer_win.h"
[email protected]8ff1d422009-07-07 21:31:3917#include "printing/printed_document.h"
[email protected]c399a8a2008-11-22 19:38:0018#include "skia/ext/platform_device_win.h"
initial.commit09911bf2008-07-26 23:55:2919
[email protected]e1acf6f2008-10-27 20:43:3320using base::Time;
21
[email protected]bd5baaf2011-04-21 20:48:3322namespace {
23
24// Retrieves the printer's PRINTER_INFO_* structure.
25// Output |level| can be 9 (user-default), 8 (admin-default), or 2
26// (printer-default).
27// |devmode| is a pointer points to the start of DEVMODE structure in
28// |buffer|.
29bool GetPrinterInfo(HANDLE printer,
30 const std::wstring &device_name,
31 int* level,
32 scoped_array<uint8>* buffer,
33 DEVMODE** dev_mode) {
34 DCHECK(buffer);
35
36 // A PRINTER_INFO_9 structure specifying the per-user default printer
37 // settings.
38 printing::PrintingContextWin::GetPrinterHelper(printer, 9, buffer);
39 if (buffer->get()) {
40 PRINTER_INFO_9* info_9 = reinterpret_cast<PRINTER_INFO_9*>(buffer->get());
41 if (info_9->pDevMode != NULL) {
42 *level = 9;
43 *dev_mode = info_9->pDevMode;
44 return true;
45 }
46 buffer->reset();
47 }
48
49 // A PRINTER_INFO_8 structure specifying the global default printer settings.
50 printing::PrintingContextWin::GetPrinterHelper(printer, 8, buffer);
51 if (buffer->get()) {
52 PRINTER_INFO_8* info_8 = reinterpret_cast<PRINTER_INFO_8*>(buffer->get());
53 if (info_8->pDevMode != NULL) {
54 *level = 8;
55 *dev_mode = info_8->pDevMode;
56 return true;
57 }
58 buffer->reset();
59 }
60
61 // A PRINTER_INFO_2 structure specifying the driver's default printer
62 // settings.
63 printing::PrintingContextWin::GetPrinterHelper(printer, 2, buffer);
64 if (buffer->get()) {
65 PRINTER_INFO_2* info_2 = reinterpret_cast<PRINTER_INFO_2*>(buffer->get());
66 if (info_2->pDevMode != NULL) {
67 *level = 2;
68 *dev_mode = info_2->pDevMode;
69 return true;
70 }
71 buffer->reset();
72 }
73
74 return false;
75}
76
77} // anonymous namespace
78
initial.commit09911bf2008-07-26 23:55:2979namespace printing {
80
[email protected]51e8d9352010-10-06 22:21:1781class PrintingContextWin::CallbackHandler : public IPrintDialogCallback,
82 public IObjectWithSite {
initial.commit09911bf2008-07-26 23:55:2983 public:
[email protected]51e8d9352010-10-06 22:21:1784 CallbackHandler(PrintingContextWin& owner, HWND owner_hwnd)
initial.commit09911bf2008-07-26 23:55:2985 : owner_(owner),
86 owner_hwnd_(owner_hwnd),
87 services_(NULL) {
88 }
89
90 ~CallbackHandler() {
91 if (services_)
92 services_->Release();
93 }
94
95 IUnknown* ToIUnknown() {
96 return static_cast<IUnknown*>(static_cast<IPrintDialogCallback*>(this));
97 }
98
99 // IUnknown
100 virtual HRESULT WINAPI QueryInterface(REFIID riid, void**object) {
101 if (riid == IID_IUnknown) {
102 *object = ToIUnknown();
103 } else if (riid == IID_IPrintDialogCallback) {
104 *object = static_cast<IPrintDialogCallback*>(this);
105 } else if (riid == IID_IObjectWithSite) {
106 *object = static_cast<IObjectWithSite*>(this);
107 } else {
108 return E_NOINTERFACE;
109 }
110 return S_OK;
111 }
112
113 // No real ref counting.
114 virtual ULONG WINAPI AddRef() {
115 return 1;
116 }
117 virtual ULONG WINAPI Release() {
118 return 1;
119 }
120
121 // IPrintDialogCallback methods
122 virtual HRESULT WINAPI InitDone() {
123 return S_OK;
124 }
125
126 virtual HRESULT WINAPI SelectionChange() {
127 if (services_) {
128 // TODO(maruel): Get the devmode for the new printer with
129 // services_->GetCurrentDevMode(&devmode, &size), send that information
130 // back to our client and continue. The client needs to recalculate the
131 // number of rendered pages and send back this information here.
132 }
133 return S_OK;
134 }
135
136 virtual HRESULT WINAPI HandleMessage(HWND dialog,
137 UINT message,
138 WPARAM wparam,
139 LPARAM lparam,
140 LRESULT* result) {
141 // Cheap way to retrieve the window handle.
142 if (!owner_.dialog_box_) {
143 // The handle we receive is the one of the groupbox in the General tab. We
144 // need to get the grand-father to get the dialog box handle.
145 owner_.dialog_box_ = GetAncestor(dialog, GA_ROOT);
146 // Trick to enable the owner window. This can cause issues with navigation
147 // events so it may have to be disabled if we don't fix the side-effects.
148 EnableWindow(owner_hwnd_, TRUE);
149 }
150 return S_FALSE;
151 }
152
153 virtual HRESULT WINAPI SetSite(IUnknown* site) {
154 if (!site) {
155 DCHECK(services_);
156 services_->Release();
157 services_ = NULL;
158 // The dialog box is destroying, PrintJob::Worker don't need the handle
159 // anymore.
160 owner_.dialog_box_ = NULL;
161 } else {
162 DCHECK(services_ == NULL);
163 HRESULT hr = site->QueryInterface(IID_IPrintDialogServices,
164 reinterpret_cast<void**>(&services_));
165 DCHECK(SUCCEEDED(hr));
166 }
167 return S_OK;
168 }
169
170 virtual HRESULT WINAPI GetSite(REFIID riid, void** site) {
171 return E_NOTIMPL;
172 }
173
174 private:
[email protected]51e8d9352010-10-06 22:21:17175 PrintingContextWin& owner_;
initial.commit09911bf2008-07-26 23:55:29176 HWND owner_hwnd_;
177 IPrintDialogServices* services_;
178
[email protected]5930cb62009-12-08 02:04:22179 DISALLOW_COPY_AND_ASSIGN(CallbackHandler);
initial.commit09911bf2008-07-26 23:55:29180};
181
[email protected]51e8d9352010-10-06 22:21:17182// static
[email protected]ee5f36e42010-12-03 22:40:37183PrintingContext* PrintingContext::Create(const std::string& app_locale) {
184 return static_cast<PrintingContext*>(new PrintingContextWin(app_locale));
[email protected]51e8d9352010-10-06 22:21:17185}
186
[email protected]ee5f36e42010-12-03 22:40:37187PrintingContextWin::PrintingContextWin(const std::string& app_locale)
188 : PrintingContext(app_locale),
[email protected]51e8d9352010-10-06 22:21:17189 context_(NULL),
initial.commit09911bf2008-07-26 23:55:29190 dialog_box_(NULL),
[email protected]d8254622010-08-13 19:15:46191 print_dialog_func_(&PrintDlgEx) {
initial.commit09911bf2008-07-26 23:55:29192}
193
[email protected]51e8d9352010-10-06 22:21:17194PrintingContextWin::~PrintingContextWin() {
195 ReleaseContext();
initial.commit09911bf2008-07-26 23:55:29196}
197
[email protected]51e8d9352010-10-06 22:21:17198void PrintingContextWin::AskUserForSettings(HWND view,
199 int max_pages,
200 bool has_selection,
201 PrintSettingsCallback* callback) {
initial.commit09911bf2008-07-26 23:55:29202 DCHECK(!in_print_job_);
203 dialog_box_dismissed_ = false;
[email protected]fc7904622010-05-12 19:26:40204
205 HWND window;
206 if (!view || !IsWindow(view)) {
207 // TODO(maruel): bug 1214347 Get the right browser window instead.
208 window = GetDesktopWindow();
209 } else {
210 window = GetAncestor(view, GA_ROOTOWNER);
211 }
212 DCHECK(window);
213
initial.commit09911bf2008-07-26 23:55:29214 // Show the OS-dependent dialog box.
215 // If the user press
216 // - OK, the settings are reset and reinitialized with the new settings. OK is
217 // returned.
218 // - Apply then Cancel, the settings are reset and reinitialized with the new
219 // settings. CANCEL is returned.
220 // - Cancel, the settings are not changed, the previous setting, if it was
221 // initialized before, are kept. CANCEL is returned.
222 // On failure, the settings are reset and FAILED is returned.
223 PRINTDLGEX dialog_options = { sizeof(PRINTDLGEX) };
224 dialog_options.hwndOwner = window;
[email protected]c8ad40c2009-06-08 17:05:21225 // Disable options we don't support currently.
initial.commit09911bf2008-07-26 23:55:29226 // TODO(maruel): Reuse the previously loaded settings!
227 dialog_options.Flags = PD_RETURNDC | PD_USEDEVMODECOPIESANDCOLLATE |
[email protected]c8ad40c2009-06-08 17:05:21228 PD_NOCURRENTPAGE | PD_HIDEPRINTTOFILE;
229 if (!has_selection)
230 dialog_options.Flags |= PD_NOSELECTION;
231
initial.commit09911bf2008-07-26 23:55:29232 PRINTPAGERANGE ranges[32];
233 dialog_options.nStartPage = START_PAGE_GENERAL;
234 if (max_pages) {
235 // Default initialize to print all the pages.
236 memset(ranges, 0, sizeof(ranges));
237 ranges[0].nFromPage = 1;
238 ranges[0].nToPage = max_pages;
239 dialog_options.nPageRanges = 1;
240 dialog_options.nMaxPageRanges = arraysize(ranges);
[email protected]3a0e4a32009-06-09 19:07:05241 dialog_options.nMinPage = 1;
initial.commit09911bf2008-07-26 23:55:29242 dialog_options.nMaxPage = max_pages;
243 dialog_options.lpPageRanges = ranges;
244 } else {
245 // No need to bother, we don't know how many pages are available.
246 dialog_options.Flags |= PD_NOPAGENUMS;
247 }
248
[email protected]128bec3c2011-01-20 22:57:35249 if ((*print_dialog_func_)(&dialog_options) != S_OK) {
250 ResetSettings();
251 callback->Run(FAILED);
initial.commit09911bf2008-07-26 23:55:29252 }
[email protected]128bec3c2011-01-20 22:57:35253
initial.commit09911bf2008-07-26 23:55:29254 // TODO(maruel): Support PD_PRINTTOFILE.
[email protected]b7191422010-09-21 19:18:05255 callback->Run(ParseDialogResultEx(dialog_options));
initial.commit09911bf2008-07-26 23:55:29256}
257
[email protected]51e8d9352010-10-06 22:21:17258PrintingContext::Result PrintingContextWin::UseDefaultSettings() {
initial.commit09911bf2008-07-26 23:55:29259 DCHECK(!in_print_job_);
260
261 PRINTDLG dialog_options = { sizeof(PRINTDLG) };
262 dialog_options.Flags = PD_RETURNDC | PD_RETURNDEFAULT;
[email protected]ff3ccc22011-04-18 21:35:48263 if (PrintDlg(&dialog_options))
264 return ParseDialogResult(dialog_options);
265
266 // No default printer configured, do we have any printers at all?
267 DWORD bytes_needed = 0;
268 DWORD count_returned = 0;
269 (void)::EnumPrinters(PRINTER_ENUM_LOCAL|PRINTER_ENUM_CONNECTIONS,
270 NULL, 2, NULL, 0, &bytes_needed, &count_returned);
271 if (bytes_needed) {
272 DCHECK(bytes_needed >= count_returned * sizeof(PRINTER_INFO_2));
273 scoped_array<BYTE> printer_info_buffer(new BYTE[bytes_needed]);
274 BOOL ret = ::EnumPrinters(PRINTER_ENUM_LOCAL|PRINTER_ENUM_CONNECTIONS,
275 NULL, 2, printer_info_buffer.get(),
276 bytes_needed, &bytes_needed,
277 &count_returned);
278 if (ret && count_returned) { // have printers
279 // Open the first successfully found printer.
[email protected]a5e0ef572011-04-21 18:38:54280 for (DWORD count = 0; count < count_returned; ++count) {
281 PRINTER_INFO_2* info_2 = reinterpret_cast<PRINTER_INFO_2*>(
[email protected]ff3ccc22011-04-18 21:35:48282 printer_info_buffer.get() + count * sizeof(PRINTER_INFO_2));
283 std::wstring printer_name = info_2->pPrinterName;
284 if (info_2->pDevMode == NULL || printer_name.length() == 0)
285 continue;
286 if (!AllocateContext(printer_name, info_2->pDevMode, &context_))
287 break;
288 if (InitializeSettings(*info_2->pDevMode, printer_name,
[email protected]a5e0ef572011-04-21 18:38:54289 NULL, 0, false)) {
[email protected]ff3ccc22011-04-18 21:35:48290 break;
[email protected]ff3ccc22011-04-18 21:35:48291 }
[email protected]a5e0ef572011-04-21 18:38:54292 ReleaseContext();
[email protected]ff3ccc22011-04-18 21:35:48293 }
294 if (context_)
295 return OK;
296 }
initial.commit09911bf2008-07-26 23:55:29297 }
[email protected]ff3ccc22011-04-18 21:35:48298
299 ResetSettings();
300 return FAILED;
initial.commit09911bf2008-07-26 23:55:29301}
302
[email protected]7868ecab2011-03-05 00:12:53303PrintingContext::Result PrintingContextWin::UpdatePrintSettings(
[email protected]bd5baaf2011-04-21 20:48:33304 const DictionaryValue& job_settings,
305 const PageRanges& ranges) {
[email protected]7868ecab2011-03-05 00:12:53306 DCHECK(!in_print_job_);
307
[email protected]bd5baaf2011-04-21 20:48:33308 bool is_landscape, is_collate, is_color;
309 string16 printer_name;
310 int copies, duplex_mode;
311 if (!job_settings.GetBoolean(kSettingLandscape, &is_landscape) ||
312 !job_settings.GetString(kSettingPrinterName, &printer_name) ||
313 !job_settings.GetInteger(kSettingCopies, &copies) ||
314 !job_settings.GetBoolean(kSettingCollate, &is_collate) ||
315 !job_settings.GetInteger(kSettingDuplexMode, &duplex_mode) ||
316 !job_settings.GetBoolean(kSettingColor, &is_color)) {
[email protected]c48bee22011-03-29 02:36:26317 return OnError();
[email protected]bd5baaf2011-04-21 20:48:33318 }
[email protected]37a401bf2011-03-31 16:12:36319
[email protected]bd5baaf2011-04-21 20:48:33320 // Underlying |settings_| do not have these attributes, so we need to
321 // operate on printer directly, which involves reloading settings.
322 // Therefore, reset the settings anyway.
323 ResetSettings();
[email protected]c48bee22011-03-29 02:36:26324
[email protected]bd5baaf2011-04-21 20:48:33325 HANDLE printer;
326 if (!OpenPrinter(const_cast<wchar_t*>(printer_name.c_str()),
327 &printer, NULL)) {
328 return OnError();
329 }
[email protected]afbdbf112011-03-28 22:09:37330
[email protected]bd5baaf2011-04-21 20:48:33331 scoped_array<uint8> buffer;
332 int level;
333 DEVMODE* dev_mode = NULL;
334 if (!GetPrinterInfo(printer, printer_name, &level, &buffer, &dev_mode) ||
335 dev_mode == NULL) {
336 ClosePrinter(printer);
337 return OnError();
338 }
[email protected]7868ecab2011-03-05 00:12:53339
[email protected]bd5baaf2011-04-21 20:48:33340 dev_mode->dmColor = is_color ? DMCOLOR_COLOR : DMCOLOR_MONOCHROME;
341 dev_mode->dmCopies = std::max(copies, 1);
342 if (dev_mode->dmCopies > 1) // do not change collate unless multiple copies
343 dev_mode->dmCollate = is_collate ? DMCOLLATE_TRUE : DMCOLLATE_FALSE;
344 switch (duplex_mode) {
345 case LONG_EDGE:
346 dev_mode->dmDuplex = DMDUP_VERTICAL;
347 break;
348 case SHORT_EDGE:
349 dev_mode->dmDuplex = DMDUP_HORIZONTAL;
350 break;
351 default: // simplex
352 dev_mode->dmDuplex = DMDUP_SIMPLEX;
353 break;
354 }
355 dev_mode->dmOrientation = is_landscape ? DMORIENT_LANDSCAPE :
356 DMORIENT_PORTRAIT;
357
358 // Set printer then refresh printer settings.
359 if (!SetPrinter(printer, level, buffer.get(), 0) ||
360 !AllocateContext(printer_name, dev_mode, &context_)) {
361 ClosePrinter(printer);
362 return OnError();
363 }
364 PrintSettingsInitializerWin::InitPrintSettings(context_, *dev_mode,
365 ranges, printer_name,
366 false, &settings_);
367 ClosePrinter(printer);
[email protected]afbdbf112011-03-28 22:09:37368 return OK;
[email protected]7868ecab2011-03-05 00:12:53369}
370
[email protected]51e8d9352010-10-06 22:21:17371PrintingContext::Result PrintingContextWin::InitWithSettings(
initial.commit09911bf2008-07-26 23:55:29372 const PrintSettings& settings) {
373 DCHECK(!in_print_job_);
[email protected]4993f342010-10-26 17:57:52374
initial.commit09911bf2008-07-26 23:55:29375 settings_ = settings;
[email protected]4993f342010-10-26 17:57:52376
377 // TODO(maruel): settings_.ToDEVMODE()
initial.commit09911bf2008-07-26 23:55:29378 HANDLE printer;
379 if (!OpenPrinter(const_cast<wchar_t*>(settings_.device_name().c_str()),
380 &printer,
381 NULL))
382 return FAILED;
383
384 Result status = OK;
385
386 if (!GetPrinterSettings(printer, settings_.device_name()))
387 status = FAILED;
388
389 // Close the printer after retrieving the context.
390 ClosePrinter(printer);
391
392 if (status != OK)
393 ResetSettings();
394 return status;
395}
396
[email protected]51e8d9352010-10-06 22:21:17397PrintingContext::Result PrintingContextWin::NewDocument(
[email protected]d9d42992010-09-13 19:39:19398 const string16& document_name) {
initial.commit09911bf2008-07-26 23:55:29399 DCHECK(!in_print_job_);
[email protected]b75dca82009-10-13 18:46:21400 if (!context_)
[email protected]c8ad40c2009-06-08 17:05:21401 return OnError();
initial.commit09911bf2008-07-26 23:55:29402
403 // Set the flag used by the AbortPrintJob dialog procedure.
404 abort_printing_ = false;
405
406 in_print_job_ = true;
407
408 // Register the application's AbortProc function with GDI.
[email protected]b75dca82009-10-13 18:46:21409 if (SP_ERROR == SetAbortProc(context_, &AbortProc))
[email protected]c8ad40c2009-06-08 17:05:21410 return OnError();
initial.commit09911bf2008-07-26 23:55:29411
412 DOCINFO di = { sizeof(DOCINFO) };
[email protected]ea6f72a97c2010-09-28 00:34:47413 const std::wstring& document_name_wide = UTF16ToWide(document_name);
414 di.lpszDocName = document_name_wide.c_str();
initial.commit09911bf2008-07-26 23:55:29415
416 // Is there a debug dump directory specified? If so, force to print to a file.
[email protected]d9d42992010-09-13 19:39:19417 FilePath debug_dump_path = PrintedDocument::debug_dump_path();
initial.commit09911bf2008-07-26 23:55:29418 if (!debug_dump_path.empty()) {
419 // Create a filename.
420 std::wstring filename;
421 Time now(Time::Now());
[email protected]5cca3a52008-08-19 22:35:29422 filename = base::TimeFormatShortDateNumeric(now);
initial.commit09911bf2008-07-26 23:55:29423 filename += L"_";
[email protected]5cca3a52008-08-19 22:35:29424 filename += base::TimeFormatTimeOfDay(now);
initial.commit09911bf2008-07-26 23:55:29425 filename += L"_";
[email protected]d9d42992010-09-13 19:39:19426 filename += UTF16ToWide(document_name);
initial.commit09911bf2008-07-26 23:55:29427 filename += L"_";
428 filename += L"buffer.prn";
[email protected]de2943352009-10-22 23:06:12429 file_util::ReplaceIllegalCharactersInPath(&filename, '_');
[email protected]d9d42992010-09-13 19:39:19430 debug_dump_path.Append(filename);
431 di.lpszOutput = debug_dump_path.value().c_str();
initial.commit09911bf2008-07-26 23:55:29432 }
433
[email protected]daee4972009-07-09 14:28:24434 // No message loop running in unit tests.
435 DCHECK(!MessageLoop::current() ? true :
436 !MessageLoop::current()->NestableTasksAllowed());
437
initial.commit09911bf2008-07-26 23:55:29438 // Begin a print job by calling the StartDoc function.
439 // NOTE: StartDoc() starts a message loop. That causes a lot of problems with
440 // IPC. Make sure recursive task processing is disabled.
[email protected]b75dca82009-10-13 18:46:21441 if (StartDoc(context_, &di) <= 0)
[email protected]c8ad40c2009-06-08 17:05:21442 return OnError();
initial.commit09911bf2008-07-26 23:55:29443
initial.commit09911bf2008-07-26 23:55:29444 return OK;
445}
446
[email protected]51e8d9352010-10-06 22:21:17447PrintingContext::Result PrintingContextWin::NewPage() {
initial.commit09911bf2008-07-26 23:55:29448 if (abort_printing_)
449 return CANCEL;
[email protected]3b52c982010-09-27 20:40:36450 DCHECK(context_);
initial.commit09911bf2008-07-26 23:55:29451 DCHECK(in_print_job_);
452
[email protected]b10c54d2011-03-16 18:22:35453 // Intentional No-op. NativeMetafile::SafePlayback takes care of calling
454 // ::StartPage().
initial.commit09911bf2008-07-26 23:55:29455
initial.commit09911bf2008-07-26 23:55:29456 return OK;
457}
458
[email protected]51e8d9352010-10-06 22:21:17459PrintingContext::Result PrintingContextWin::PageDone() {
initial.commit09911bf2008-07-26 23:55:29460 if (abort_printing_)
461 return CANCEL;
462 DCHECK(in_print_job_);
463
[email protected]b10c54d2011-03-16 18:22:35464 // Intentional No-op. NativeMetafile::SafePlayback takes care of calling
465 // ::EndPage().
466
initial.commit09911bf2008-07-26 23:55:29467 return OK;
468}
469
[email protected]51e8d9352010-10-06 22:21:17470PrintingContext::Result PrintingContextWin::DocumentDone() {
initial.commit09911bf2008-07-26 23:55:29471 if (abort_printing_)
472 return CANCEL;
473 DCHECK(in_print_job_);
[email protected]60745412010-09-27 23:46:07474 DCHECK(context_);
initial.commit09911bf2008-07-26 23:55:29475
476 // Inform the driver that document has ended.
[email protected]b75dca82009-10-13 18:46:21477 if (EndDoc(context_) <= 0)
[email protected]c8ad40c2009-06-08 17:05:21478 return OnError();
initial.commit09911bf2008-07-26 23:55:29479
480 ResetSettings();
481 return OK;
482}
483
[email protected]51e8d9352010-10-06 22:21:17484void PrintingContextWin::Cancel() {
initial.commit09911bf2008-07-26 23:55:29485 abort_printing_ = true;
486 in_print_job_ = false;
[email protected]b75dca82009-10-13 18:46:21487 if (context_)
488 CancelDC(context_);
initial.commit09911bf2008-07-26 23:55:29489 if (dialog_box_) {
490 DestroyWindow(dialog_box_);
491 dialog_box_dismissed_ = true;
492 }
493}
494
[email protected]51e8d9352010-10-06 22:21:17495void PrintingContextWin::ReleaseContext() {
496 if (context_) {
497 DeleteDC(context_);
498 context_ = NULL;
499 }
500}
501
502gfx::NativeDrawingContext PrintingContextWin::context() const {
503 return context_;
initial.commit09911bf2008-07-26 23:55:29504}
505
506// static
[email protected]51e8d9352010-10-06 22:21:17507BOOL PrintingContextWin::AbortProc(HDC hdc, int nCode) {
initial.commit09911bf2008-07-26 23:55:29508 if (nCode) {
509 // TODO(maruel): Need a way to find the right instance to set. Should
510 // leverage PrintJobManager here?
511 // abort_printing_ = true;
512 }
513 return true;
514}
515
[email protected]51e8d9352010-10-06 22:21:17516bool PrintingContextWin::InitializeSettings(const DEVMODE& dev_mode,
517 const std::wstring& new_device_name,
518 const PRINTPAGERANGE* ranges,
519 int number_ranges,
520 bool selection_only) {
[email protected]b75dca82009-10-13 18:46:21521 skia::PlatformDevice::InitializeDC(context_);
522 DCHECK(GetDeviceCaps(context_, CLIPCAPS));
523 DCHECK(GetDeviceCaps(context_, RASTERCAPS) & RC_STRETCHDIB);
524 DCHECK(GetDeviceCaps(context_, RASTERCAPS) & RC_BITMAP64);
initial.commit09911bf2008-07-26 23:55:29525 // Some printers don't advertise these.
[email protected]b75dca82009-10-13 18:46:21526 // DCHECK(GetDeviceCaps(context_, RASTERCAPS) & RC_SCALING);
527 // DCHECK(GetDeviceCaps(context_, SHADEBLENDCAPS) & SB_CONST_ALPHA);
528 // DCHECK(GetDeviceCaps(context_, SHADEBLENDCAPS) & SB_PIXEL_ALPHA);
initial.commit09911bf2008-07-26 23:55:29529
530 // StretchDIBits() support is needed for printing.
[email protected]b75dca82009-10-13 18:46:21531 if (!(GetDeviceCaps(context_, RASTERCAPS) & RC_STRETCHDIB) ||
532 !(GetDeviceCaps(context_, RASTERCAPS) & RC_BITMAP64)) {
initial.commit09911bf2008-07-26 23:55:29533 NOTREACHED();
534 ResetSettings();
535 return false;
536 }
537
538 DCHECK(!in_print_job_);
[email protected]b75dca82009-10-13 18:46:21539 DCHECK(context_);
initial.commit09911bf2008-07-26 23:55:29540 PageRanges ranges_vector;
[email protected]82270452009-06-19 15:58:01541 if (!selection_only) {
542 // Convert the PRINTPAGERANGE array to a PrintSettings::PageRanges vector.
543 ranges_vector.reserve(number_ranges);
544 for (int i = 0; i < number_ranges; ++i) {
545 PageRange range;
546 // Transfer from 1-based to 0-based.
547 range.from = ranges[i].nFromPage - 1;
548 range.to = ranges[i].nToPage - 1;
549 ranges_vector.push_back(range);
550 }
initial.commit09911bf2008-07-26 23:55:29551 }
[email protected]4993f342010-10-26 17:57:52552
553 PrintSettingsInitializerWin::InitPrintSettings(context_,
554 dev_mode,
555 ranges_vector,
556 new_device_name,
557 selection_only,
558 &settings_);
559
initial.commit09911bf2008-07-26 23:55:29560 return true;
561}
562
[email protected]51e8d9352010-10-06 22:21:17563bool PrintingContextWin::GetPrinterSettings(HANDLE printer,
564 const std::wstring& device_name) {
initial.commit09911bf2008-07-26 23:55:29565 DCHECK(!in_print_job_);
566 scoped_array<uint8> buffer;
[email protected]bd5baaf2011-04-21 20:48:33567 int level = 0;
568 DEVMODE* dev_mode = NULL;
initial.commit09911bf2008-07-26 23:55:29569
[email protected]bd5baaf2011-04-21 20:48:33570 if (GetPrinterInfo(printer, device_name, &level, &buffer, &dev_mode) &&
571 AllocateContext(device_name, dev_mode, &context_)) {
572 return InitializeSettings(*dev_mode, device_name, NULL, 0, false);
initial.commit09911bf2008-07-26 23:55:29573 }
574
[email protected]bd5baaf2011-04-21 20:48:33575 buffer.reset();
initial.commit09911bf2008-07-26 23:55:29576 ResetSettings();
577 return false;
578}
579
[email protected]d8254622010-08-13 19:15:46580// static
[email protected]51e8d9352010-10-06 22:21:17581bool PrintingContextWin::AllocateContext(const std::wstring& printer_name,
582 const DEVMODE* dev_mode,
583 gfx::NativeDrawingContext* context) {
[email protected]d8254622010-08-13 19:15:46584 *context = CreateDC(L"WINSPOOL", printer_name.c_str(), NULL, dev_mode);
585 DCHECK(*context);
586 return *context != NULL;
initial.commit09911bf2008-07-26 23:55:29587}
588
[email protected]51e8d9352010-10-06 22:21:17589PrintingContext::Result PrintingContextWin::ParseDialogResultEx(
initial.commit09911bf2008-07-26 23:55:29590 const PRINTDLGEX& dialog_options) {
591 // If the user clicked OK or Apply then Cancel, but not only Cancel.
592 if (dialog_options.dwResultAction != PD_RESULT_CANCEL) {
593 // Start fresh.
594 ResetSettings();
595
596 DEVMODE* dev_mode = NULL;
597 if (dialog_options.hDevMode) {
598 dev_mode =
599 reinterpret_cast<DEVMODE*>(GlobalLock(dialog_options.hDevMode));
600 DCHECK(dev_mode);
601 }
602
603 std::wstring device_name;
604 if (dialog_options.hDevNames) {
605 DEVNAMES* dev_names =
606 reinterpret_cast<DEVNAMES*>(GlobalLock(dialog_options.hDevNames));
607 DCHECK(dev_names);
608 if (dev_names) {
609 device_name =
610 reinterpret_cast<const wchar_t*>(
611 reinterpret_cast<const wchar_t*>(dev_names) +
612 dev_names->wDeviceOffset);
613 GlobalUnlock(dialog_options.hDevNames);
614 }
615 }
616
617 bool success = false;
618 if (dev_mode && !device_name.empty()) {
[email protected]b75dca82009-10-13 18:46:21619 context_ = dialog_options.hDC;
[email protected]c8ad40c2009-06-08 17:05:21620 PRINTPAGERANGE* page_ranges = NULL;
621 DWORD num_page_ranges = 0;
622 bool print_selection_only = false;
initial.commit09911bf2008-07-26 23:55:29623 if (dialog_options.Flags & PD_PAGENUMS) {
[email protected]c8ad40c2009-06-08 17:05:21624 page_ranges = dialog_options.lpPageRanges;
625 num_page_ranges = dialog_options.nPageRanges;
initial.commit09911bf2008-07-26 23:55:29626 }
[email protected]c8ad40c2009-06-08 17:05:21627 if (dialog_options.Flags & PD_SELECTION) {
628 print_selection_only = true;
629 }
630 success = InitializeSettings(*dev_mode,
631 device_name,
[email protected]d8254622010-08-13 19:15:46632 page_ranges,
633 num_page_ranges,
[email protected]c8ad40c2009-06-08 17:05:21634 print_selection_only);
initial.commit09911bf2008-07-26 23:55:29635 }
636
637 if (!success && dialog_options.hDC) {
638 DeleteDC(dialog_options.hDC);
[email protected]b75dca82009-10-13 18:46:21639 context_ = NULL;
initial.commit09911bf2008-07-26 23:55:29640 }
641
642 if (dev_mode) {
643 GlobalUnlock(dialog_options.hDevMode);
644 }
645 } else {
646 if (dialog_options.hDC) {
647 DeleteDC(dialog_options.hDC);
648 }
649 }
650
651 if (dialog_options.hDevMode != NULL)
652 GlobalFree(dialog_options.hDevMode);
653 if (dialog_options.hDevNames != NULL)
654 GlobalFree(dialog_options.hDevNames);
655
656 switch (dialog_options.dwResultAction) {
657 case PD_RESULT_PRINT:
[email protected]b75dca82009-10-13 18:46:21658 return context_ ? OK : FAILED;
initial.commit09911bf2008-07-26 23:55:29659 case PD_RESULT_APPLY:
[email protected]b75dca82009-10-13 18:46:21660 return context_ ? CANCEL : FAILED;
initial.commit09911bf2008-07-26 23:55:29661 case PD_RESULT_CANCEL:
662 return CANCEL;
663 default:
664 return FAILED;
665 }
666}
667
[email protected]51e8d9352010-10-06 22:21:17668PrintingContext::Result PrintingContextWin::ParseDialogResult(
initial.commit09911bf2008-07-26 23:55:29669 const PRINTDLG& dialog_options) {
670 // If the user clicked OK or Apply then Cancel, but not only Cancel.
671 // Start fresh.
672 ResetSettings();
673
674 DEVMODE* dev_mode = NULL;
675 if (dialog_options.hDevMode) {
676 dev_mode =
677 reinterpret_cast<DEVMODE*>(GlobalLock(dialog_options.hDevMode));
678 DCHECK(dev_mode);
679 }
680
681 std::wstring device_name;
682 if (dialog_options.hDevNames) {
683 DEVNAMES* dev_names =
684 reinterpret_cast<DEVNAMES*>(GlobalLock(dialog_options.hDevNames));
685 DCHECK(dev_names);
686 if (dev_names) {
687 device_name =
688 reinterpret_cast<const wchar_t*>(
689 reinterpret_cast<const wchar_t*>(dev_names) +
690 dev_names->wDeviceOffset);
691 GlobalUnlock(dialog_options.hDevNames);
692 }
693 }
694
695 bool success = false;
696 if (dev_mode && !device_name.empty()) {
[email protected]b75dca82009-10-13 18:46:21697 context_ = dialog_options.hDC;
[email protected]c8ad40c2009-06-08 17:05:21698 success = InitializeSettings(*dev_mode, device_name, NULL, 0, false);
initial.commit09911bf2008-07-26 23:55:29699 }
700
701 if (!success && dialog_options.hDC) {
702 DeleteDC(dialog_options.hDC);
[email protected]b75dca82009-10-13 18:46:21703 context_ = NULL;
initial.commit09911bf2008-07-26 23:55:29704 }
705
706 if (dev_mode) {
707 GlobalUnlock(dialog_options.hDevMode);
708 }
709
710 if (dialog_options.hDevMode != NULL)
711 GlobalFree(dialog_options.hDevMode);
712 if (dialog_options.hDevNames != NULL)
713 GlobalFree(dialog_options.hDevNames);
714
[email protected]b75dca82009-10-13 18:46:21715 return context_ ? OK : FAILED;
initial.commit09911bf2008-07-26 23:55:29716}
717
[email protected]d8254622010-08-13 19:15:46718// static
[email protected]51e8d9352010-10-06 22:21:17719void PrintingContextWin::GetPrinterHelper(HANDLE printer, int level,
720 scoped_array<uint8>* buffer) {
[email protected]d8254622010-08-13 19:15:46721 DWORD buf_size = 0;
722 GetPrinter(printer, level, NULL, 0, &buf_size);
723 if (buf_size) {
724 buffer->reset(new uint8[buf_size]);
725 memset(buffer->get(), 0, buf_size);
726 if (!GetPrinter(printer, level, buffer->get(), buf_size, &buf_size)) {
727 buffer->reset();
728 }
729 }
730}
731
initial.commit09911bf2008-07-26 23:55:29732} // namespace printing