Roll src/third_party/skia 054eef2:51985e3
[chromium-blink-merge.git] / printing / printing_context_system_dialog_win.cc
blobdd5e29020cc6539a6b2fd2b892dde42e667d8392
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::InitializeSettings(
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 = InitializeSettings(*dev_mode,
185 device_name,
186 page_ranges,
187 num_page_ranges,
188 print_selection_only);
191 if (!success && dialog_options.hDC) {
192 DeleteDC(dialog_options.hDC);
193 set_context(NULL);
196 if (dev_mode) {
197 GlobalUnlock(dialog_options.hDevMode);
199 } else {
200 if (dialog_options.hDC) {
201 DeleteDC(dialog_options.hDC);
205 if (dialog_options.hDevMode != NULL)
206 GlobalFree(dialog_options.hDevMode);
207 if (dialog_options.hDevNames != NULL)
208 GlobalFree(dialog_options.hDevNames);
210 switch (dialog_options.dwResultAction) {
211 case PD_RESULT_PRINT:
212 return context() ? OK : FAILED;
213 case PD_RESULT_APPLY:
214 return context() ? CANCEL : FAILED;
215 case PD_RESULT_CANCEL:
216 return CANCEL;
217 default:
218 return FAILED;
222 PrintingContext::Result PrintingContextSytemDialogWin::ParseDialogResult(
223 const PRINTDLG& dialog_options) {
224 // If the user clicked OK or Apply then Cancel, but not only Cancel.
225 // Start fresh.
226 ResetSettings();
228 DEVMODE* dev_mode = NULL;
229 if (dialog_options.hDevMode) {
230 dev_mode = reinterpret_cast<DEVMODE*>(GlobalLock(dialog_options.hDevMode));
231 DCHECK(dev_mode);
234 std::wstring device_name;
235 if (dialog_options.hDevNames) {
236 DEVNAMES* dev_names =
237 reinterpret_cast<DEVNAMES*>(GlobalLock(dialog_options.hDevNames));
238 DCHECK(dev_names);
239 if (dev_names) {
240 device_name = reinterpret_cast<const wchar_t*>(
241 reinterpret_cast<const wchar_t*>(dev_names) +
242 dev_names->wDeviceOffset);
243 GlobalUnlock(dialog_options.hDevNames);
247 bool success = false;
248 if (dev_mode && !device_name.empty()) {
249 set_context(dialog_options.hDC);
250 success = InitializeSettings(*dev_mode, device_name, NULL, 0, false);
253 if (!success && dialog_options.hDC) {
254 DeleteDC(dialog_options.hDC);
255 set_context(NULL);
258 if (dev_mode) {
259 GlobalUnlock(dialog_options.hDevMode);
262 if (dialog_options.hDevMode != NULL)
263 GlobalFree(dialog_options.hDevMode);
264 if (dialog_options.hDevNames != NULL)
265 GlobalFree(dialog_options.hDevNames);
267 return context() ? OK : FAILED;
270 } // namespace printing