OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "printing/printing_context_win.h" | 5 #include "printing/printing_context_win.h" |
6 | 6 |
7 #include <winspool.h> | |
8 | |
9 #include <algorithm> | |
10 | |
11 #include "base/message_loop/message_loop.h" | |
12 #include "base/metrics/histogram.h" | |
13 #include "base/strings/string_number_conversions.h" | 7 #include "base/strings/string_number_conversions.h" |
14 #include "base/strings/utf_string_conversions.h" | 8 #include "base/strings/utf_string_conversions.h" |
15 #include "base/values.h" | |
16 #include "printing/backend/print_backend.h" | 9 #include "printing/backend/print_backend.h" |
17 #include "printing/backend/printing_info_win.h" | |
18 #include "printing/backend/win_helper.h" | 10 #include "printing/backend/win_helper.h" |
19 #include "printing/print_job_constants.h" | |
20 #include "printing/print_settings_initializer_win.h" | 11 #include "printing/print_settings_initializer_win.h" |
21 #include "printing/printed_document.h" | 12 #include "printing/printed_document.h" |
22 #include "printing/printing_utils.h" | 13 #include "printing/printing_utils.h" |
23 #include "printing/units.h" | 14 #include "printing/units.h" |
24 #include "skia/ext/platform_device.h" | 15 #include "skia/ext/platform_device.h" |
25 | 16 |
26 #if defined(USE_AURA) | 17 #if defined(USE_AURA) |
27 #include "ui/aura/remote_window_tree_host_win.h" | 18 #include "ui/aura/remote_window_tree_host_win.h" |
28 #include "ui/aura/window.h" | 19 #include "ui/aura/window.h" |
29 #include "ui/aura/window_event_dispatcher.h" | |
30 #endif | 20 #endif |
31 | 21 |
32 namespace { | 22 namespace { |
33 | 23 |
34 HWND GetRootWindow(gfx::NativeView view) { | 24 HWND GetRootWindow(gfx::NativeView view) { |
35 HWND window = NULL; | 25 HWND window = NULL; |
36 #if defined(USE_AURA) | 26 #if defined(USE_AURA) |
37 if (view) | 27 if (view) |
38 window = view->GetHost()->GetAcceleratedWidget(); | 28 window = view->GetHost()->GetAcceleratedWidget(); |
39 #else | 29 #else |
40 if (view && IsWindow(view)) { | 30 if (view && IsWindow(view)) { |
41 window = GetAncestor(view, GA_ROOTOWNER); | 31 window = GetAncestor(view, GA_ROOTOWNER); |
42 } | 32 } |
43 #endif | 33 #endif |
44 if (!window) { | 34 if (!window) { |
45 // TODO(maruel): bug 1214347 Get the right browser window instead. | 35 // TODO(maruel): bug 1214347 Get the right browser window instead. |
46 return GetDesktopWindow(); | 36 return GetDesktopWindow(); |
47 } | 37 } |
48 return window; | 38 return window; |
49 } | 39 } |
50 | 40 |
51 } // anonymous namespace | 41 } // anonymous namespace |
52 | 42 |
53 namespace printing { | 43 namespace printing { |
54 | 44 |
55 class PrintingContextWin::CallbackHandler : public IPrintDialogCallback, | |
56 public IObjectWithSite { | |
57 public: | |
58 CallbackHandler(PrintingContextWin& owner, HWND owner_hwnd) | |
59 : owner_(owner), | |
60 owner_hwnd_(owner_hwnd), | |
61 services_(NULL) { | |
62 } | |
63 | |
64 ~CallbackHandler() { | |
65 if (services_) | |
66 services_->Release(); | |
67 } | |
68 | |
69 IUnknown* ToIUnknown() { | |
70 return static_cast<IUnknown*>(static_cast<IPrintDialogCallback*>(this)); | |
71 } | |
72 | |
73 // IUnknown | |
74 virtual HRESULT WINAPI QueryInterface(REFIID riid, void**object) { | |
75 if (riid == IID_IUnknown) { | |
76 *object = ToIUnknown(); | |
77 } else if (riid == IID_IPrintDialogCallback) { | |
78 *object = static_cast<IPrintDialogCallback*>(this); | |
79 } else if (riid == IID_IObjectWithSite) { | |
80 *object = static_cast<IObjectWithSite*>(this); | |
81 } else { | |
82 return E_NOINTERFACE; | |
83 } | |
84 return S_OK; | |
85 } | |
86 | |
87 // No real ref counting. | |
88 virtual ULONG WINAPI AddRef() { | |
89 return 1; | |
90 } | |
91 virtual ULONG WINAPI Release() { | |
92 return 1; | |
93 } | |
94 | |
95 // IPrintDialogCallback methods | |
96 virtual HRESULT WINAPI InitDone() { | |
97 return S_OK; | |
98 } | |
99 | |
100 virtual HRESULT WINAPI SelectionChange() { | |
101 if (services_) { | |
102 // TODO(maruel): Get the devmode for the new printer with | |
103 // services_->GetCurrentDevMode(&devmode, &size), send that information | |
104 // back to our client and continue. The client needs to recalculate the | |
105 // number of rendered pages and send back this information here. | |
106 } | |
107 return S_OK; | |
108 } | |
109 | |
110 virtual HRESULT WINAPI HandleMessage(HWND dialog, | |
111 UINT message, | |
112 WPARAM wparam, | |
113 LPARAM lparam, | |
114 LRESULT* result) { | |
115 // Cheap way to retrieve the window handle. | |
116 if (!owner_.dialog_box_) { | |
117 // The handle we receive is the one of the groupbox in the General tab. We | |
118 // need to get the grand-father to get the dialog box handle. | |
119 owner_.dialog_box_ = GetAncestor(dialog, GA_ROOT); | |
120 // Trick to enable the owner window. This can cause issues with navigation | |
121 // events so it may have to be disabled if we don't fix the side-effects. | |
122 EnableWindow(owner_hwnd_, TRUE); | |
123 } | |
124 return S_FALSE; | |
125 } | |
126 | |
127 virtual HRESULT WINAPI SetSite(IUnknown* site) { | |
128 if (!site) { | |
129 DCHECK(services_); | |
130 services_->Release(); | |
131 services_ = NULL; | |
132 // The dialog box is destroying, PrintJob::Worker don't need the handle | |
133 // anymore. | |
134 owner_.dialog_box_ = NULL; | |
135 } else { | |
136 DCHECK(services_ == NULL); | |
137 HRESULT hr = site->QueryInterface(IID_IPrintDialogServices, | |
138 reinterpret_cast<void**>(&services_)); | |
139 DCHECK(SUCCEEDED(hr)); | |
140 } | |
141 return S_OK; | |
142 } | |
143 | |
144 virtual HRESULT WINAPI GetSite(REFIID riid, void** site) { | |
145 return E_NOTIMPL; | |
146 } | |
147 | |
148 private: | |
149 PrintingContextWin& owner_; | |
150 HWND owner_hwnd_; | |
151 IPrintDialogServices* services_; | |
152 | |
153 DISALLOW_COPY_AND_ASSIGN(CallbackHandler); | |
154 }; | |
155 | |
156 // static | 45 // static |
157 PrintingContext* PrintingContext::Create(const std::string& app_locale) { | 46 PrintingContext* PrintingContext::Create(const std::string& app_locale) { |
158 return static_cast<PrintingContext*>(new PrintingContextWin(app_locale)); | 47 return static_cast<PrintingContext*>(new PrintingContextWin(app_locale)); |
159 } | 48 } |
160 | 49 |
161 PrintingContextWin::PrintingContextWin(const std::string& app_locale) | 50 PrintingContextWin::PrintingContextWin(const std::string& app_locale) |
162 : PrintingContext(app_locale), context_(NULL), dialog_box_(NULL) {} | 51 : PrintingContext(app_locale), context_(NULL) { |
| 52 } |
163 | 53 |
164 PrintingContextWin::~PrintingContextWin() { | 54 PrintingContextWin::~PrintingContextWin() { |
165 ReleaseContext(); | 55 ReleaseContext(); |
166 } | 56 } |
167 | 57 |
168 void PrintingContextWin::AskUserForSettings( | 58 void PrintingContextWin::AskUserForSettings( |
169 gfx::NativeView view, int max_pages, bool has_selection, | 59 gfx::NativeView view, int max_pages, bool has_selection, |
170 const PrintSettingsCallback& callback) { | 60 const PrintSettingsCallback& callback) { |
171 DCHECK(!in_print_job_); | 61 NOTIMPLEMENTED(); |
172 dialog_box_dismissed_ = false; | |
173 | |
174 HWND window = GetRootWindow(view); | |
175 DCHECK(window); | |
176 | |
177 // Show the OS-dependent dialog box. | |
178 // If the user press | |
179 // - OK, the settings are reset and reinitialized with the new settings. OK is | |
180 // returned. | |
181 // - Apply then Cancel, the settings are reset and reinitialized with the new | |
182 // settings. CANCEL is returned. | |
183 // - Cancel, the settings are not changed, the previous setting, if it was | |
184 // initialized before, are kept. CANCEL is returned. | |
185 // On failure, the settings are reset and FAILED is returned. | |
186 PRINTDLGEX dialog_options = { sizeof(PRINTDLGEX) }; | |
187 dialog_options.hwndOwner = window; | |
188 // Disable options we don't support currently. | |
189 // TODO(maruel): Reuse the previously loaded settings! | |
190 dialog_options.Flags = PD_RETURNDC | PD_USEDEVMODECOPIESANDCOLLATE | | |
191 PD_NOCURRENTPAGE | PD_HIDEPRINTTOFILE; | |
192 if (!has_selection) | |
193 dialog_options.Flags |= PD_NOSELECTION; | |
194 | |
195 PRINTPAGERANGE ranges[32]; | |
196 dialog_options.nStartPage = START_PAGE_GENERAL; | |
197 if (max_pages) { | |
198 // Default initialize to print all the pages. | |
199 memset(ranges, 0, sizeof(ranges)); | |
200 ranges[0].nFromPage = 1; | |
201 ranges[0].nToPage = max_pages; | |
202 dialog_options.nPageRanges = 1; | |
203 dialog_options.nMaxPageRanges = arraysize(ranges); | |
204 dialog_options.nMinPage = 1; | |
205 dialog_options.nMaxPage = max_pages; | |
206 dialog_options.lpPageRanges = ranges; | |
207 } else { | |
208 // No need to bother, we don't know how many pages are available. | |
209 dialog_options.Flags |= PD_NOPAGENUMS; | |
210 } | |
211 | |
212 if (ShowPrintDialog(&dialog_options) != S_OK) { | |
213 ResetSettings(); | |
214 callback.Run(FAILED); | |
215 } | |
216 | |
217 // TODO(maruel): Support PD_PRINTTOFILE. | |
218 callback.Run(ParseDialogResultEx(dialog_options)); | |
219 } | 62 } |
220 | 63 |
221 PrintingContext::Result PrintingContextWin::UseDefaultSettings() { | 64 PrintingContext::Result PrintingContextWin::UseDefaultSettings() { |
222 DCHECK(!in_print_job_); | 65 DCHECK(!in_print_job_); |
223 | 66 |
224 PRINTDLG dialog_options = { sizeof(PRINTDLG) }; | 67 scoped_refptr<PrintBackend> backend = PrintBackend::CreateInstance(NULL); |
225 dialog_options.Flags = PD_RETURNDC | PD_RETURNDEFAULT; | 68 base::string16 default_printer = |
226 if (PrintDlg(&dialog_options)) | 69 base::UTF8ToWide(backend->GetDefaultPrinterName()); |
227 return ParseDialogResult(dialog_options); | 70 if (!default_printer.empty()) { |
| 71 ScopedPrinterHandle printer; |
| 72 if (printer.OpenPrinter(default_printer.c_str())) { |
| 73 scoped_ptr<DEVMODE, base::FreeDeleter> dev_mode = |
| 74 CreateDevMode(printer, NULL); |
| 75 if (InitializeSettings(default_printer, dev_mode.get()) == OK) |
| 76 return OK; |
| 77 } |
| 78 } |
| 79 |
| 80 ReleaseContext(); |
228 | 81 |
229 // No default printer configured, do we have any printers at all? | 82 // No default printer configured, do we have any printers at all? |
230 DWORD bytes_needed = 0; | 83 DWORD bytes_needed = 0; |
231 DWORD count_returned = 0; | 84 DWORD count_returned = 0; |
232 (void)::EnumPrinters(PRINTER_ENUM_LOCAL|PRINTER_ENUM_CONNECTIONS, | 85 (void)::EnumPrinters(PRINTER_ENUM_LOCAL|PRINTER_ENUM_CONNECTIONS, |
233 NULL, 2, NULL, 0, &bytes_needed, &count_returned); | 86 NULL, 2, NULL, 0, &bytes_needed, &count_returned); |
234 if (bytes_needed) { | 87 if (bytes_needed) { |
235 DCHECK_GE(bytes_needed, count_returned * sizeof(PRINTER_INFO_2)); | 88 DCHECK_GE(bytes_needed, count_returned * sizeof(PRINTER_INFO_2)); |
236 scoped_ptr<BYTE[]> printer_info_buffer(new BYTE[bytes_needed]); | 89 scoped_ptr<BYTE[]> printer_info_buffer(new BYTE[bytes_needed]); |
237 BOOL ret = ::EnumPrinters(PRINTER_ENUM_LOCAL|PRINTER_ENUM_CONNECTIONS, | 90 BOOL ret = ::EnumPrinters(PRINTER_ENUM_LOCAL|PRINTER_ENUM_CONNECTIONS, |
238 NULL, 2, printer_info_buffer.get(), | 91 NULL, 2, printer_info_buffer.get(), |
239 bytes_needed, &bytes_needed, | 92 bytes_needed, &bytes_needed, |
240 &count_returned); | 93 &count_returned); |
241 if (ret && count_returned) { // have printers | 94 if (ret && count_returned) { // have printers |
242 // Open the first successfully found printer. | 95 // Open the first successfully found printer. |
243 const PRINTER_INFO_2* info_2 = | 96 const PRINTER_INFO_2* info_2 = |
244 reinterpret_cast<PRINTER_INFO_2*>(printer_info_buffer.get()); | 97 reinterpret_cast<PRINTER_INFO_2*>(printer_info_buffer.get()); |
245 const PRINTER_INFO_2* info_2_end = info_2 + count_returned; | 98 const PRINTER_INFO_2* info_2_end = info_2 + count_returned; |
246 for (; info_2 < info_2_end; ++info_2) { | 99 for (; info_2 < info_2_end; ++info_2) { |
247 ScopedPrinterHandle printer; | 100 ScopedPrinterHandle printer; |
248 if (!printer.OpenPrinter(info_2->pPrinterName)) | 101 if (!printer.OpenPrinter(info_2->pPrinterName)) |
249 continue; | 102 continue; |
250 scoped_ptr<DEVMODE, base::FreeDeleter> dev_mode = | 103 scoped_ptr<DEVMODE, base::FreeDeleter> dev_mode = |
251 CreateDevMode(printer, NULL); | 104 CreateDevMode(printer, NULL); |
252 if (!dev_mode || !AllocateContext(info_2->pPrinterName, dev_mode.get(), | 105 if (InitializeSettings(info_2->pPrinterName, dev_mode.get()) == OK) |
253 &context_)) { | |
254 continue; | |
255 } | |
256 if (InitializeSettings(*dev_mode.get(), info_2->pPrinterName, NULL, 0, | |
257 false)) { | |
258 return OK; | 106 return OK; |
259 } | |
260 ReleaseContext(); | |
261 } | 107 } |
262 if (context_) | 108 if (context_) |
263 return OK; | 109 return OK; |
264 } | 110 } |
265 } | 111 } |
266 | 112 |
267 ResetSettings(); | 113 return OnError(); |
268 return FAILED; | |
269 } | 114 } |
270 | 115 |
271 gfx::Size PrintingContextWin::GetPdfPaperSizeDeviceUnits() { | 116 gfx::Size PrintingContextWin::GetPdfPaperSizeDeviceUnits() { |
272 // Default fallback to Letter size. | 117 // Default fallback to Letter size. |
273 gfx::SizeF paper_size(kLetterWidthInch, kLetterHeightInch); | 118 gfx::SizeF paper_size(kLetterWidthInch, kLetterHeightInch); |
274 | 119 |
275 // Get settings from locale. Paper type buffer length is at most 4. | 120 // Get settings from locale. Paper type buffer length is at most 4. |
276 const int paper_type_buffer_len = 4; | 121 const int paper_type_buffer_len = 4; |
277 wchar_t paper_type_buffer[paper_type_buffer_len] = {0}; | 122 wchar_t paper_type_buffer[paper_type_buffer_len] = {0}; |
278 GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_IPAPERSIZE, paper_type_buffer, | 123 GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_IPAPERSIZE, paper_type_buffer, |
(...skipping 13 matching lines...) Expand all Loading... |
292 default: // DMPAPER_LETTER is used for default fallback. | 137 default: // DMPAPER_LETTER is used for default fallback. |
293 break; | 138 break; |
294 } | 139 } |
295 } | 140 } |
296 return gfx::Size( | 141 return gfx::Size( |
297 paper_size.width() * settings_.device_units_per_inch(), | 142 paper_size.width() * settings_.device_units_per_inch(), |
298 paper_size.height() * settings_.device_units_per_inch()); | 143 paper_size.height() * settings_.device_units_per_inch()); |
299 } | 144 } |
300 | 145 |
301 PrintingContext::Result PrintingContextWin::UpdatePrinterSettings( | 146 PrintingContext::Result PrintingContextWin::UpdatePrinterSettings( |
302 bool external_preview) { | 147 bool external_preview, |
| 148 bool show_system_dialog, |
| 149 gfx::NativeView parent_view) { |
303 DCHECK(!in_print_job_); | 150 DCHECK(!in_print_job_); |
304 DCHECK(!external_preview) << "Not implemented"; | 151 DCHECK(!external_preview) << "Not implemented"; |
305 | 152 |
306 ScopedPrinterHandle printer; | 153 ScopedPrinterHandle printer; |
307 if (!printer.OpenPrinter(settings_.device_name().c_str())) | 154 if (!printer.OpenPrinter(settings_.device_name().c_str())) |
308 return OnError(); | 155 return OnError(); |
309 | 156 |
310 // Make printer changes local to Chrome. | 157 // Make printer changes local to Chrome. |
311 // See MSDN documentation regarding DocumentProperties. | 158 // See MSDN documentation regarding DocumentProperties. |
312 scoped_ptr<DEVMODE, base::FreeDeleter> scoped_dev_mode = | 159 scoped_ptr<DEVMODE, base::FreeDeleter> scoped_dev_mode = |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
356 dev_mode->dmPaperSize = static_cast<short>(id); | 203 dev_mode->dmPaperSize = static_cast<short>(id); |
357 } else if (width > 0 && height > 0) { | 204 } else if (width > 0 && height > 0) { |
358 dev_mode->dmFields |= DM_PAPERWIDTH; | 205 dev_mode->dmFields |= DM_PAPERWIDTH; |
359 dev_mode->dmPaperWidth = width; | 206 dev_mode->dmPaperWidth = width; |
360 dev_mode->dmFields |= DM_PAPERLENGTH; | 207 dev_mode->dmFields |= DM_PAPERLENGTH; |
361 dev_mode->dmPaperLength = height; | 208 dev_mode->dmPaperLength = height; |
362 } | 209 } |
363 } | 210 } |
364 | 211 |
365 // Update data using DocumentProperties. | 212 // Update data using DocumentProperties. |
366 scoped_dev_mode = CreateDevMode(printer, scoped_dev_mode.get()); | 213 if (show_system_dialog) { |
367 if (!scoped_dev_mode) | 214 scoped_dev_mode = |
368 return OnError(); | 215 ShowPrintDialog(printer, parent_view, scoped_dev_mode.get()); |
369 | 216 } else { |
| 217 scoped_dev_mode = CreateDevMode(printer, scoped_dev_mode.get()); |
| 218 } |
370 // Set printer then refresh printer settings. | 219 // Set printer then refresh printer settings. |
371 if (!AllocateContext(settings_.device_name(), scoped_dev_mode.get(), | 220 return InitializeSettings(settings_.device_name(), scoped_dev_mode.get()); |
372 &context_)) { | |
373 return OnError(); | |
374 } | |
375 PrintSettingsInitializerWin::InitPrintSettings(context_, | |
376 *scoped_dev_mode.get(), | |
377 &settings_); | |
378 return OK; | |
379 } | 221 } |
380 | 222 |
381 PrintingContext::Result PrintingContextWin::InitWithSettings( | 223 PrintingContext::Result PrintingContextWin::InitWithSettings( |
382 const PrintSettings& settings) { | 224 const PrintSettings& settings) { |
383 DCHECK(!in_print_job_); | 225 DCHECK(!in_print_job_); |
384 | 226 |
385 settings_ = settings; | 227 settings_ = settings; |
386 | 228 |
387 // TODO(maruel): settings_.ToDEVMODE() | 229 // TODO(maruel): settings_.ToDEVMODE() |
388 ScopedPrinterHandle printer; | 230 ScopedPrinterHandle printer; |
389 if (!printer.OpenPrinter(settings_.device_name().c_str())) { | 231 if (!printer.OpenPrinter(settings_.device_name().c_str())) |
390 return FAILED; | 232 return FAILED; |
391 } | |
392 | 233 |
393 Result status = OK; | 234 scoped_ptr<DEVMODE, base::FreeDeleter> dev_mode = |
| 235 CreateDevMode(printer, NULL); |
394 | 236 |
395 if (!GetPrinterSettings(printer, settings_.device_name())) | 237 return InitializeSettings(settings_.device_name(), dev_mode.get()); |
396 status = FAILED; | |
397 | |
398 if (status != OK) | |
399 ResetSettings(); | |
400 return status; | |
401 } | 238 } |
402 | 239 |
403 PrintingContext::Result PrintingContextWin::NewDocument( | 240 PrintingContext::Result PrintingContextWin::NewDocument( |
404 const base::string16& document_name) { | 241 const base::string16& document_name) { |
405 DCHECK(!in_print_job_); | 242 DCHECK(!in_print_job_); |
406 if (!context_) | 243 if (!context_) |
407 return OnError(); | 244 return OnError(); |
408 | 245 |
409 // Set the flag used by the AbortPrintJob dialog procedure. | 246 // Set the flag used by the AbortPrintJob dialog procedure. |
410 abort_printing_ = false; | 247 abort_printing_ = false; |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
474 | 311 |
475 ResetSettings(); | 312 ResetSettings(); |
476 return OK; | 313 return OK; |
477 } | 314 } |
478 | 315 |
479 void PrintingContextWin::Cancel() { | 316 void PrintingContextWin::Cancel() { |
480 abort_printing_ = true; | 317 abort_printing_ = true; |
481 in_print_job_ = false; | 318 in_print_job_ = false; |
482 if (context_) | 319 if (context_) |
483 CancelDC(context_); | 320 CancelDC(context_); |
484 if (dialog_box_) { | |
485 DestroyWindow(dialog_box_); | |
486 dialog_box_dismissed_ = true; | |
487 } | |
488 } | 321 } |
489 | 322 |
490 void PrintingContextWin::ReleaseContext() { | 323 void PrintingContextWin::ReleaseContext() { |
491 if (context_) { | 324 if (context_) { |
492 DeleteDC(context_); | 325 DeleteDC(context_); |
493 context_ = NULL; | 326 context_ = NULL; |
494 } | 327 } |
495 } | 328 } |
496 | 329 |
497 gfx::NativeDrawingContext PrintingContextWin::context() const { | 330 gfx::NativeDrawingContext PrintingContextWin::context() const { |
498 return context_; | 331 return context_; |
499 } | 332 } |
500 | 333 |
501 // static | 334 // static |
502 BOOL PrintingContextWin::AbortProc(HDC hdc, int nCode) { | 335 BOOL PrintingContextWin::AbortProc(HDC hdc, int nCode) { |
503 if (nCode) { | 336 if (nCode) { |
504 // TODO(maruel): Need a way to find the right instance to set. Should | 337 // TODO(maruel): Need a way to find the right instance to set. Should |
505 // leverage PrintJobManager here? | 338 // leverage PrintJobManager here? |
506 // abort_printing_ = true; | 339 // abort_printing_ = true; |
507 } | 340 } |
508 return true; | 341 return true; |
509 } | 342 } |
510 | 343 |
511 bool PrintingContextWin::InitializeSettings(const DEVMODE& dev_mode, | 344 PrintingContext::Result PrintingContextWin::InitializeSettings( |
512 const std::wstring& new_device_name, | 345 const std::wstring& device_name, |
513 const PRINTPAGERANGE* ranges, | 346 DEVMODE* dev_mode) { |
514 int number_ranges, | 347 if (!dev_mode) |
515 bool selection_only) { | 348 return OnError(); |
| 349 |
| 350 ReleaseContext(); |
| 351 context_ = CreateDC(L"WINSPOOL", device_name.c_str(), NULL, dev_mode); |
| 352 if (!context_) |
| 353 return OnError(); |
| 354 |
516 skia::InitializeDC(context_); | 355 skia::InitializeDC(context_); |
517 DCHECK(GetDeviceCaps(context_, CLIPCAPS)); | |
518 DCHECK(GetDeviceCaps(context_, RASTERCAPS) & RC_STRETCHDIB); | |
519 DCHECK(GetDeviceCaps(context_, RASTERCAPS) & RC_BITMAP64); | |
520 // Some printers don't advertise these. | |
521 // DCHECK(GetDeviceCaps(context_, RASTERCAPS) & RC_SCALING); | |
522 // DCHECK(GetDeviceCaps(context_, SHADEBLENDCAPS) & SB_CONST_ALPHA); | |
523 // DCHECK(GetDeviceCaps(context_, SHADEBLENDCAPS) & SB_PIXEL_ALPHA); | |
524 | |
525 // StretchDIBits() support is needed for printing. | |
526 if (!(GetDeviceCaps(context_, RASTERCAPS) & RC_STRETCHDIB) || | |
527 !(GetDeviceCaps(context_, RASTERCAPS) & RC_BITMAP64)) { | |
528 NOTREACHED(); | |
529 ResetSettings(); | |
530 return false; | |
531 } | |
532 | 356 |
533 DCHECK(!in_print_job_); | 357 DCHECK(!in_print_job_); |
534 DCHECK(context_); | 358 settings_.set_device_name(device_name); |
535 PageRanges ranges_vector; | 359 PrintSettingsInitializerWin::InitPrintSettings( |
536 if (!selection_only) { | 360 context_, *dev_mode, &settings_); |
537 // Convert the PRINTPAGERANGE array to a PrintSettings::PageRanges vector. | |
538 ranges_vector.reserve(number_ranges); | |
539 for (int i = 0; i < number_ranges; ++i) { | |
540 PageRange range; | |
541 // Transfer from 1-based to 0-based. | |
542 range.from = ranges[i].nFromPage - 1; | |
543 range.to = ranges[i].nToPage - 1; | |
544 ranges_vector.push_back(range); | |
545 } | |
546 } | |
547 | 361 |
548 settings_.set_ranges(ranges_vector); | 362 return OK; |
549 settings_.set_device_name(new_device_name); | |
550 settings_.set_selection_only(selection_only); | |
551 PrintSettingsInitializerWin::InitPrintSettings(context_, dev_mode, | |
552 &settings_); | |
553 | |
554 return true; | |
555 } | 363 } |
556 | 364 |
557 bool PrintingContextWin::GetPrinterSettings(HANDLE printer, | 365 scoped_ptr<DEVMODE, base::FreeDeleter> PrintingContextWin::ShowPrintDialog( |
558 const std::wstring& device_name) { | 366 HANDLE printer, |
559 DCHECK(!in_print_job_); | 367 gfx::NativeView parent_view, |
560 | 368 DEVMODE* dev_mode) { |
561 scoped_ptr<DEVMODE, base::FreeDeleter> dev_mode = | |
562 CreateDevMode(printer, NULL); | |
563 | |
564 if (!dev_mode || !AllocateContext(device_name, dev_mode.get(), &context_)) { | |
565 ResetSettings(); | |
566 return false; | |
567 } | |
568 | |
569 return InitializeSettings(*dev_mode.get(), device_name, NULL, 0, false); | |
570 } | |
571 | |
572 // static | |
573 bool PrintingContextWin::AllocateContext(const std::wstring& device_name, | |
574 const DEVMODE* dev_mode, | |
575 gfx::NativeDrawingContext* context) { | |
576 *context = CreateDC(L"WINSPOOL", device_name.c_str(), NULL, dev_mode); | |
577 DCHECK(*context); | |
578 return *context != NULL; | |
579 } | |
580 | |
581 PrintingContext::Result PrintingContextWin::ParseDialogResultEx( | |
582 const PRINTDLGEX& dialog_options) { | |
583 // If the user clicked OK or Apply then Cancel, but not only Cancel. | |
584 if (dialog_options.dwResultAction != PD_RESULT_CANCEL) { | |
585 // Start fresh. | |
586 ResetSettings(); | |
587 | |
588 DEVMODE* dev_mode = NULL; | |
589 if (dialog_options.hDevMode) { | |
590 dev_mode = | |
591 reinterpret_cast<DEVMODE*>(GlobalLock(dialog_options.hDevMode)); | |
592 DCHECK(dev_mode); | |
593 } | |
594 | |
595 std::wstring device_name; | |
596 if (dialog_options.hDevNames) { | |
597 DEVNAMES* dev_names = | |
598 reinterpret_cast<DEVNAMES*>(GlobalLock(dialog_options.hDevNames)); | |
599 DCHECK(dev_names); | |
600 if (dev_names) { | |
601 device_name = reinterpret_cast<const wchar_t*>(dev_names) + | |
602 dev_names->wDeviceOffset; | |
603 GlobalUnlock(dialog_options.hDevNames); | |
604 } | |
605 } | |
606 | |
607 bool success = false; | |
608 if (dev_mode && !device_name.empty()) { | |
609 context_ = dialog_options.hDC; | |
610 PRINTPAGERANGE* page_ranges = NULL; | |
611 DWORD num_page_ranges = 0; | |
612 bool print_selection_only = false; | |
613 if (dialog_options.Flags & PD_PAGENUMS) { | |
614 page_ranges = dialog_options.lpPageRanges; | |
615 num_page_ranges = dialog_options.nPageRanges; | |
616 } | |
617 if (dialog_options.Flags & PD_SELECTION) { | |
618 print_selection_only = true; | |
619 } | |
620 success = InitializeSettings(*dev_mode, | |
621 device_name, | |
622 page_ranges, | |
623 num_page_ranges, | |
624 print_selection_only); | |
625 } | |
626 | |
627 if (!success && dialog_options.hDC) { | |
628 DeleteDC(dialog_options.hDC); | |
629 context_ = NULL; | |
630 } | |
631 | |
632 if (dev_mode) { | |
633 GlobalUnlock(dialog_options.hDevMode); | |
634 } | |
635 } else { | |
636 if (dialog_options.hDC) { | |
637 DeleteDC(dialog_options.hDC); | |
638 } | |
639 } | |
640 | |
641 if (dialog_options.hDevMode != NULL) | |
642 GlobalFree(dialog_options.hDevMode); | |
643 if (dialog_options.hDevNames != NULL) | |
644 GlobalFree(dialog_options.hDevNames); | |
645 | |
646 switch (dialog_options.dwResultAction) { | |
647 case PD_RESULT_PRINT: | |
648 return context_ ? OK : FAILED; | |
649 case PD_RESULT_APPLY: | |
650 return context_ ? CANCEL : FAILED; | |
651 case PD_RESULT_CANCEL: | |
652 return CANCEL; | |
653 default: | |
654 return FAILED; | |
655 } | |
656 } | |
657 | |
658 HRESULT PrintingContextWin::ShowPrintDialog(PRINTDLGEX* options) { | |
659 // Note that this cannot use ui::BaseShellDialog as the print dialog is | 369 // Note that this cannot use ui::BaseShellDialog as the print dialog is |
660 // system modal: opening it from a background thread can cause Windows to | 370 // system modal: opening it from a background thread can cause Windows to |
661 // get the wrong Z-order which will make the print dialog appear behind the | 371 // get the wrong Z-order which will make the print dialog appear behind the |
662 // browser frame (but still being modal) so neither the browser frame nor | 372 // browser frame (but still being modal) so neither the browser frame nor |
663 // the print dialog will get any input. See http://crbug.com/342697 | 373 // the print dialog will get any input. See http://crbug.com/342697 |
664 // http://crbug.com/180997 for details. | 374 // http://crbug.com/180997 for details. |
665 base::MessageLoop::ScopedNestableTaskAllower allow( | 375 base::MessageLoop::ScopedNestableTaskAllower allow( |
666 base::MessageLoop::current()); | 376 base::MessageLoop::current()); |
667 | 377 |
668 return PrintDlgEx(options); | 378 bool canceled = false; |
669 } | 379 scoped_ptr<DEVMODE, base::FreeDeleter> result = |
| 380 PromptDevMode(printer, |
| 381 settings_.device_name(), |
| 382 dev_mode, |
| 383 GetRootWindow(parent_view), |
| 384 &canceled); |
670 | 385 |
671 PrintingContext::Result PrintingContextWin::ParseDialogResult( | 386 if (canceled) { |
672 const PRINTDLG& dialog_options) { | 387 result.reset(); |
673 // If the user clicked OK or Apply then Cancel, but not only Cancel. | 388 abort_printing_ = true; |
674 // Start fresh. | |
675 ResetSettings(); | |
676 | |
677 DEVMODE* dev_mode = NULL; | |
678 if (dialog_options.hDevMode) { | |
679 dev_mode = | |
680 reinterpret_cast<DEVMODE*>(GlobalLock(dialog_options.hDevMode)); | |
681 DCHECK(dev_mode); | |
682 } | 389 } |
683 | 390 |
684 std::wstring device_name; | 391 return result.Pass(); |
685 if (dialog_options.hDevNames) { | |
686 DEVNAMES* dev_names = | |
687 reinterpret_cast<DEVNAMES*>(GlobalLock(dialog_options.hDevNames)); | |
688 DCHECK(dev_names); | |
689 if (dev_names) { | |
690 device_name = | |
691 reinterpret_cast<const wchar_t*>( | |
692 reinterpret_cast<const wchar_t*>(dev_names) + | |
693 dev_names->wDeviceOffset); | |
694 GlobalUnlock(dialog_options.hDevNames); | |
695 } | |
696 } | |
697 | |
698 bool success = false; | |
699 if (dev_mode && !device_name.empty()) { | |
700 context_ = dialog_options.hDC; | |
701 success = InitializeSettings(*dev_mode, device_name, NULL, 0, false); | |
702 } | |
703 | |
704 if (!success && dialog_options.hDC) { | |
705 DeleteDC(dialog_options.hDC); | |
706 context_ = NULL; | |
707 } | |
708 | |
709 if (dev_mode) { | |
710 GlobalUnlock(dialog_options.hDevMode); | |
711 } | |
712 | |
713 if (dialog_options.hDevMode != NULL) | |
714 GlobalFree(dialog_options.hDevMode); | |
715 if (dialog_options.hDevNames != NULL) | |
716 GlobalFree(dialog_options.hDevNames); | |
717 | |
718 return context_ ? OK : FAILED; | |
719 } | 392 } |
720 | 393 |
721 } // namespace printing | 394 } // namespace printing |
OLD | NEW |