Upstreaming browser/ui/uikit_ui_util from iOS.
[chromium-blink-merge.git] / printing / printing_context_system_dialog_win.cc
blobaaa5b68f2ebe69581c175df049f1b17d69fad821
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "printing/printing_context_system_dialog_win.h"
7 #include "base/auto_reset.h"
8 #include "base/message_loop/message_loop.h"
9 #include "printing/backend/win_helper.h"
10 #include "printing/print_settings_initializer_win.h"
11 #include "skia/ext/platform_device.h"
13 namespace printing {
15 PrintingContextSytemDialogWin::PrintingContextSytemDialogWin(Delegate* delegate)
16 : PrintingContextWin(delegate) {
19 PrintingContextSytemDialogWin::~PrintingContextSytemDialogWin() {
22 void PrintingContextSytemDialogWin::AskUserForSettings(
23 int max_pages,
24 bool has_selection,
25 bool is_scripted,
26 const PrintSettingsCallback& callback) {
27 DCHECK(!in_print_job_);
29 HWND window = GetRootWindow(delegate_->GetParentView());
30 DCHECK(window);
32 // Show the OS-dependent dialog box.
33 // If the user press
34 // - OK, the settings are reset and reinitialized with the new settings. OK
35 // is
36 // returned.
37 // - Apply then Cancel, the settings are reset and reinitialized with the
38 // new
39 // settings. CANCEL is returned.
40 // - Cancel, the settings are not changed, the previous setting, if it was
41 // initialized before, are kept. CANCEL is returned.
42 // On failure, the settings are reset and FAILED is returned.
43 PRINTDLGEX dialog_options = {sizeof(PRINTDLGEX)};
44 dialog_options.hwndOwner = window;
45 // Disable options we don't support currently.
46 // TODO(maruel): Reuse the previously loaded settings!
47 dialog_options.Flags = PD_RETURNDC | PD_USEDEVMODECOPIESANDCOLLATE |
48 PD_NOCURRENTPAGE | PD_HIDEPRINTTOFILE;
49 if (!has_selection)
50 dialog_options.Flags |= PD_NOSELECTION;
52 PRINTPAGERANGE ranges[32];
53 dialog_options.nStartPage = START_PAGE_GENERAL;
54 if (max_pages) {
55 // Default initialize to print all the pages.
56 memset(ranges, 0, sizeof(ranges));
57 ranges[0].nFromPage = 1;
58 ranges[0].nToPage = max_pages;
59 dialog_options.nPageRanges = 1;
60 dialog_options.nMaxPageRanges = arraysize(ranges);
61 dialog_options.nMinPage = 1;
62 dialog_options.nMaxPage = max_pages;
63 dialog_options.lpPageRanges = ranges;
64 } else {
65 // No need to bother, we don't know how many pages are available.
66 dialog_options.Flags |= PD_NOPAGENUMS;
69 if (ShowPrintDialog(&dialog_options) != S_OK) {
70 ResetSettings();
71 callback.Run(FAILED);
72 return;
75 // TODO(maruel): Support PD_PRINTTOFILE.
76 callback.Run(ParseDialogResultEx(dialog_options));
79 HRESULT PrintingContextSytemDialogWin::ShowPrintDialog(PRINTDLGEX* options) {
80 // Runs always on the UI thread.
81 static bool is_dialog_shown = false;
82 if (is_dialog_shown)
83 return E_FAIL;
84 // Block opening dialog from nested task. It crashes PrintDlgEx.
85 base::AutoReset<bool> auto_reset(&is_dialog_shown, true);
87 // Note that this cannot use ui::BaseShellDialog as the print dialog is
88 // system modal: opening it from a background thread can cause Windows to
89 // get the wrong Z-order which will make the print dialog appear behind the
90 // browser frame (but still being modal) so neither the browser frame nor
91 // the print dialog will get any input. See http://crbug.com/342697
92 // http://crbug.com/180997 for details.
93 base::MessageLoop::ScopedNestableTaskAllower allow(
94 base::MessageLoop::current());
96 return PrintDlgEx(options);
99 bool PrintingContextSytemDialogWin::InitializeSettingsWithRanges(
100 const DEVMODE& dev_mode,
101 const std::wstring& new_device_name,
102 const PRINTPAGERANGE* ranges,
103 int number_ranges,
104 bool selection_only) {
105 DCHECK(GetDeviceCaps(context(), CLIPCAPS));
106 DCHECK(GetDeviceCaps(context(), RASTERCAPS) & RC_STRETCHDIB);
107 DCHECK(GetDeviceCaps(context(), RASTERCAPS) & RC_BITMAP64);
108 // Some printers don't advertise these.
109 // DCHECK(GetDeviceCaps(context(), RASTERCAPS) & RC_SCALING);
110 // DCHECK(GetDeviceCaps(context(), SHADEBLENDCAPS) & SB_CONST_ALPHA);
111 // DCHECK(GetDeviceCaps(context(), SHADEBLENDCAPS) & SB_PIXEL_ALPHA);
113 // StretchDIBits() support is needed for printing.
114 if (!(GetDeviceCaps(context(), RASTERCAPS) & RC_STRETCHDIB) ||
115 !(GetDeviceCaps(context(), RASTERCAPS) & RC_BITMAP64)) {
116 NOTREACHED();
117 ResetSettings();
118 return false;
121 DCHECK(!in_print_job_);
122 DCHECK(context());
123 PageRanges ranges_vector;
124 if (!selection_only) {
125 // Convert the PRINTPAGERANGE array to a PrintSettings::PageRanges vector.
126 ranges_vector.reserve(number_ranges);
127 for (int i = 0; i < number_ranges; ++i) {
128 PageRange range;
129 // Transfer from 1-based to 0-based.
130 range.from = ranges[i].nFromPage - 1;
131 range.to = ranges[i].nToPage - 1;
132 ranges_vector.push_back(range);
136 settings_.set_ranges(ranges_vector);
137 settings_.set_device_name(new_device_name);
138 settings_.set_selection_only(selection_only);
139 PrintSettingsInitializerWin::InitPrintSettings(
140 context(), dev_mode, &settings_);
142 return true;
145 PrintingContext::Result PrintingContextSytemDialogWin::ParseDialogResultEx(
146 const PRINTDLGEX& dialog_options) {
147 // If the user clicked OK or Apply then Cancel, but not only Cancel.
148 if (dialog_options.dwResultAction != PD_RESULT_CANCEL) {
149 // Start fresh.
150 ResetSettings();
152 DEVMODE* dev_mode = NULL;
153 if (dialog_options.hDevMode) {
154 dev_mode =
155 reinterpret_cast<DEVMODE*>(GlobalLock(dialog_options.hDevMode));
156 DCHECK(dev_mode);
159 std::wstring device_name;
160 if (dialog_options.hDevNames) {
161 DEVNAMES* dev_names =
162 reinterpret_cast<DEVNAMES*>(GlobalLock(dialog_options.hDevNames));
163 DCHECK(dev_names);
164 if (dev_names) {
165 device_name = reinterpret_cast<const wchar_t*>(dev_names) +
166 dev_names->wDeviceOffset;
167 GlobalUnlock(dialog_options.hDevNames);
171 bool success = false;
172 if (dev_mode && !device_name.empty()) {
173 set_context(dialog_options.hDC);
174 PRINTPAGERANGE* page_ranges = NULL;
175 DWORD num_page_ranges = 0;
176 bool print_selection_only = false;
177 if (dialog_options.Flags & PD_PAGENUMS) {
178 page_ranges = dialog_options.lpPageRanges;
179 num_page_ranges = dialog_options.nPageRanges;
181 if (dialog_options.Flags & PD_SELECTION) {
182 print_selection_only = true;
184 success =
185 InitializeSettingsWithRanges(*dev_mode, device_name, page_ranges,
186 num_page_ranges, print_selection_only);
189 if (!success && dialog_options.hDC) {
190 DeleteDC(dialog_options.hDC);
191 set_context(NULL);
194 if (dev_mode) {
195 GlobalUnlock(dialog_options.hDevMode);
197 } else {
198 if (dialog_options.hDC) {
199 DeleteDC(dialog_options.hDC);
203 if (dialog_options.hDevMode != NULL)
204 GlobalFree(dialog_options.hDevMode);
205 if (dialog_options.hDevNames != NULL)
206 GlobalFree(dialog_options.hDevNames);
208 switch (dialog_options.dwResultAction) {
209 case PD_RESULT_PRINT:
210 return context() ? OK : FAILED;
211 case PD_RESULT_APPLY:
212 return context() ? CANCEL : FAILED;
213 case PD_RESULT_CANCEL:
214 return CANCEL;
215 default:
216 return FAILED;
220 PrintingContext::Result PrintingContextSytemDialogWin::ParseDialogResult(
221 const PRINTDLG& dialog_options) {
222 // If the user clicked OK or Apply then Cancel, but not only Cancel.
223 // Start fresh.
224 ResetSettings();
226 DEVMODE* dev_mode = NULL;
227 if (dialog_options.hDevMode) {
228 dev_mode = reinterpret_cast<DEVMODE*>(GlobalLock(dialog_options.hDevMode));
229 DCHECK(dev_mode);
232 std::wstring device_name;
233 if (dialog_options.hDevNames) {
234 DEVNAMES* dev_names =
235 reinterpret_cast<DEVNAMES*>(GlobalLock(dialog_options.hDevNames));
236 DCHECK(dev_names);
237 if (dev_names) {
238 device_name = reinterpret_cast<const wchar_t*>(
239 reinterpret_cast<const wchar_t*>(dev_names) +
240 dev_names->wDeviceOffset);
241 GlobalUnlock(dialog_options.hDevNames);
245 bool success = false;
246 if (dev_mode && !device_name.empty()) {
247 set_context(dialog_options.hDC);
248 success =
249 InitializeSettingsWithRanges(*dev_mode, device_name, NULL, 0, false);
252 if (!success && dialog_options.hDC) {
253 DeleteDC(dialog_options.hDC);
254 set_context(NULL);
257 if (dev_mode) {
258 GlobalUnlock(dialog_options.hDevMode);
261 if (dialog_options.hDevMode != NULL)
262 GlobalFree(dialog_options.hDevMode);
263 if (dialog_options.hDevNames != NULL)
264 GlobalFree(dialog_options.hDevNames);
266 return context() ? OK : FAILED;
269 } // namespace printing