blob: 0d09fb356190f368d7a04689185b41e468e8f00d [file] [log] [blame]
vitalybukaf9d0c0c2014-09-09 19:53:331// 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.
4
5#include "printing/printing_context_system_dialog_win.h"
6
vitalybukaa58ec6a2015-02-23 18:30:497#include "base/auto_reset.h"
avi126e93c2015-12-21 21:48:168#include "base/macros.h"
vitalybukaf9d0c0c2014-09-09 19:53:339#include "base/message_loop/message_loop.h"
10#include "printing/backend/win_helper.h"
11#include "printing/print_settings_initializer_win.h"
tomhudson828dddb2015-12-04 14:34:1612#include "skia/ext/skia_utils_win.h"
vitalybukaf9d0c0c2014-09-09 19:53:3313
14namespace printing {
15
thestige85e6b62016-08-25 00:00:0616PrintingContextSystemDialogWin::PrintingContextSystemDialogWin(
17 Delegate* delegate)
18 : PrintingContextWin(delegate) {}
vitalybukaf9d0c0c2014-09-09 19:53:3319
thestige85e6b62016-08-25 00:00:0620PrintingContextSystemDialogWin::~PrintingContextSystemDialogWin() {}
vitalybukaf9d0c0c2014-09-09 19:53:3321
thestige85e6b62016-08-25 00:00:0622void PrintingContextSystemDialogWin::AskUserForSettings(
vitalybukaf9d0c0c2014-09-09 19:53:3323 int max_pages,
24 bool has_selection,
dgn4c172eea2014-12-15 21:11:2325 bool is_scripted,
vitalybukaf9d0c0c2014-09-09 19:53:3326 const PrintSettingsCallback& callback) {
27 DCHECK(!in_print_job_);
vitalybukaf9d0c0c2014-09-09 19:53:3328
29 HWND window = GetRootWindow(delegate_->GetParentView());
30 DCHECK(window);
31
32 // Show the OS-dependent dialog box.
33 // If the user press
thestige85e6b62016-08-25 00:00:0634 // - OK, the settings are reset and reinitialized with the new settings. OK is
vitalybukaf9d0c0c2014-09-09 19:53:3335 // returned.
thestige85e6b62016-08-25 00:00:0636 // - Apply then Cancel, the settings are reset and reinitialized with the new
vitalybukaf9d0c0c2014-09-09 19:53:3337 // settings. CANCEL is returned.
38 // - Cancel, the settings are not changed, the previous setting, if it was
39 // initialized before, are kept. CANCEL is returned.
40 // On failure, the settings are reset and FAILED is returned.
41 PRINTDLGEX dialog_options = {sizeof(PRINTDLGEX)};
42 dialog_options.hwndOwner = window;
43 // Disable options we don't support currently.
44 // TODO(maruel): Reuse the previously loaded settings!
45 dialog_options.Flags = PD_RETURNDC | PD_USEDEVMODECOPIESANDCOLLATE |
46 PD_NOCURRENTPAGE | PD_HIDEPRINTTOFILE;
47 if (!has_selection)
48 dialog_options.Flags |= PD_NOSELECTION;
49
50 PRINTPAGERANGE ranges[32];
51 dialog_options.nStartPage = START_PAGE_GENERAL;
52 if (max_pages) {
53 // Default initialize to print all the pages.
54 memset(ranges, 0, sizeof(ranges));
55 ranges[0].nFromPage = 1;
56 ranges[0].nToPage = max_pages;
57 dialog_options.nPageRanges = 1;
58 dialog_options.nMaxPageRanges = arraysize(ranges);
59 dialog_options.nMinPage = 1;
60 dialog_options.nMaxPage = max_pages;
61 dialog_options.lpPageRanges = ranges;
62 } else {
63 // No need to bother, we don't know how many pages are available.
64 dialog_options.Flags |= PD_NOPAGENUMS;
65 }
66
67 if (ShowPrintDialog(&dialog_options) != S_OK) {
68 ResetSettings();
69 callback.Run(FAILED);
vitalybuka442258d2015-04-11 01:46:4270 return;
vitalybukaf9d0c0c2014-09-09 19:53:3371 }
72
73 // TODO(maruel): Support PD_PRINTTOFILE.
74 callback.Run(ParseDialogResultEx(dialog_options));
75}
76
thestige85e6b62016-08-25 00:00:0677HRESULT PrintingContextSystemDialogWin::ShowPrintDialog(PRINTDLGEX* options) {
vitalybukaa58ec6a2015-02-23 18:30:4978 // Runs always on the UI thread.
79 static bool is_dialog_shown = false;
80 if (is_dialog_shown)
81 return E_FAIL;
82 // Block opening dialog from nested task. It crashes PrintDlgEx.
83 base::AutoReset<bool> auto_reset(&is_dialog_shown, true);
84
vitalybukaf9d0c0c2014-09-09 19:53:3385 // Note that this cannot use ui::BaseShellDialog as the print dialog is
86 // system modal: opening it from a background thread can cause Windows to
87 // get the wrong Z-order which will make the print dialog appear behind the
88 // browser frame (but still being modal) so neither the browser frame nor
89 // the print dialog will get any input. See http://crbug.com/342697
90 // http://crbug.com/180997 for details.
91 base::MessageLoop::ScopedNestableTaskAllower allow(
92 base::MessageLoop::current());
93
94 return PrintDlgEx(options);
95}
96
thestige85e6b62016-08-25 00:00:0697bool PrintingContextSystemDialogWin::InitializeSettingsWithRanges(
vitalybukaf9d0c0c2014-09-09 19:53:3398 const DEVMODE& dev_mode,
99 const std::wstring& new_device_name,
100 const PRINTPAGERANGE* ranges,
101 int number_ranges,
102 bool selection_only) {
103 DCHECK(GetDeviceCaps(context(), CLIPCAPS));
104 DCHECK(GetDeviceCaps(context(), RASTERCAPS) & RC_STRETCHDIB);
105 DCHECK(GetDeviceCaps(context(), RASTERCAPS) & RC_BITMAP64);
106 // Some printers don't advertise these.
107 // DCHECK(GetDeviceCaps(context(), RASTERCAPS) & RC_SCALING);
108 // DCHECK(GetDeviceCaps(context(), SHADEBLENDCAPS) & SB_CONST_ALPHA);
109 // DCHECK(GetDeviceCaps(context(), SHADEBLENDCAPS) & SB_PIXEL_ALPHA);
110
111 // StretchDIBits() support is needed for printing.
112 if (!(GetDeviceCaps(context(), RASTERCAPS) & RC_STRETCHDIB) ||
113 !(GetDeviceCaps(context(), RASTERCAPS) & RC_BITMAP64)) {
114 NOTREACHED();
115 ResetSettings();
116 return false;
117 }
118
119 DCHECK(!in_print_job_);
120 DCHECK(context());
121 PageRanges ranges_vector;
122 if (!selection_only) {
123 // Convert the PRINTPAGERANGE array to a PrintSettings::PageRanges vector.
124 ranges_vector.reserve(number_ranges);
125 for (int i = 0; i < number_ranges; ++i) {
126 PageRange range;
127 // Transfer from 1-based to 0-based.
128 range.from = ranges[i].nFromPage - 1;
129 range.to = ranges[i].nToPage - 1;
130 ranges_vector.push_back(range);
131 }
132 }
133
134 settings_.set_ranges(ranges_vector);
135 settings_.set_device_name(new_device_name);
136 settings_.set_selection_only(selection_only);
137 PrintSettingsInitializerWin::InitPrintSettings(
138 context(), dev_mode, &settings_);
139
140 return true;
141}
142
thestige85e6b62016-08-25 00:00:06143PrintingContext::Result PrintingContextSystemDialogWin::ParseDialogResultEx(
vitalybukaf9d0c0c2014-09-09 19:53:33144 const PRINTDLGEX& dialog_options) {
145 // If the user clicked OK or Apply then Cancel, but not only Cancel.
146 if (dialog_options.dwResultAction != PD_RESULT_CANCEL) {
thestige85e6b62016-08-25 00:00:06147 // Start fresh, but preserve GDI print setting.
148 bool print_text_with_gdi = settings_.print_text_with_gdi();
vitalybukaf9d0c0c2014-09-09 19:53:33149 ResetSettings();
thestige85e6b62016-08-25 00:00:06150 settings_.set_print_text_with_gdi(print_text_with_gdi);
vitalybukaf9d0c0c2014-09-09 19:53:33151
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);
157 }
158
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);
168 }
169 }
170
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;
180 }
181 if (dialog_options.Flags & PD_SELECTION) {
182 print_selection_only = true;
183 }
mgiuca8ca59182015-07-08 02:10:21184 success =
185 InitializeSettingsWithRanges(*dev_mode, device_name, page_ranges,
186 num_page_ranges, print_selection_only);
vitalybukaf9d0c0c2014-09-09 19:53:33187 }
188
189 if (!success && dialog_options.hDC) {
190 DeleteDC(dialog_options.hDC);
191 set_context(NULL);
192 }
193
194 if (dev_mode) {
195 GlobalUnlock(dialog_options.hDevMode);
196 }
197 } else {
198 if (dialog_options.hDC) {
199 DeleteDC(dialog_options.hDC);
200 }
201 }
202
203 if (dialog_options.hDevMode != NULL)
204 GlobalFree(dialog_options.hDevMode);
205 if (dialog_options.hDevNames != NULL)
206 GlobalFree(dialog_options.hDevNames);
207
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;
217 }
218}
219
vitalybukaf9d0c0c2014-09-09 19:53:33220} // namespace printing