blob: fed7428489cad1a554fba6f9f439f5547f997b7b [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"
Gabriel Charetted258c512018-04-20 00:50:459#include "base/message_loop/message_loop_current.h"
vitalybukaf9d0c0c2014-09-09 19:53:3310#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,
Vladislav Kuzkokov48ceab22018-02-14 16:29:2826 PrintSettingsCallback callback) {
vitalybukaf9d0c0c2014-09-09 19:53:3327 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();
Vladislav Kuzkokov48ceab22018-02-14 16:29:2869 std::move(callback).Run(FAILED);
vitalybuka442258d2015-04-11 01:46:4270 return;
vitalybukaf9d0c0c2014-09-09 19:53:3371 }
72
73 // TODO(maruel): Support PD_PRINTTOFILE.
Vladislav Kuzkokov48ceab22018-02-14 16:29:2874 std::move(callback).Run(ParseDialogResultEx(dialog_options));
vitalybukaf9d0c0c2014-09-09 19:53:3375}
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.
Gabriel Charetted258c512018-04-20 00:50:4591 base::MessageLoopCurrent::ScopedNestableTaskAllower allow;
vitalybukaf9d0c0c2014-09-09 19:53:3392
93 return PrintDlgEx(options);
94}
95
thestige85e6b62016-08-25 00:00:0696bool PrintingContextSystemDialogWin::InitializeSettingsWithRanges(
vitalybukaf9d0c0c2014-09-09 19:53:3397 const DEVMODE& dev_mode,
98 const std::wstring& new_device_name,
99 const PRINTPAGERANGE* ranges,
100 int number_ranges,
101 bool selection_only) {
102 DCHECK(GetDeviceCaps(context(), CLIPCAPS));
103 DCHECK(GetDeviceCaps(context(), RASTERCAPS) & RC_STRETCHDIB);
104 DCHECK(GetDeviceCaps(context(), RASTERCAPS) & RC_BITMAP64);
105 // Some printers don't advertise these.
106 // DCHECK(GetDeviceCaps(context(), RASTERCAPS) & RC_SCALING);
107 // DCHECK(GetDeviceCaps(context(), SHADEBLENDCAPS) & SB_CONST_ALPHA);
108 // DCHECK(GetDeviceCaps(context(), SHADEBLENDCAPS) & SB_PIXEL_ALPHA);
109
110 // StretchDIBits() support is needed for printing.
111 if (!(GetDeviceCaps(context(), RASTERCAPS) & RC_STRETCHDIB) ||
112 !(GetDeviceCaps(context(), RASTERCAPS) & RC_BITMAP64)) {
113 NOTREACHED();
114 ResetSettings();
115 return false;
116 }
117
118 DCHECK(!in_print_job_);
119 DCHECK(context());
120 PageRanges ranges_vector;
121 if (!selection_only) {
122 // Convert the PRINTPAGERANGE array to a PrintSettings::PageRanges vector.
123 ranges_vector.reserve(number_ranges);
124 for (int i = 0; i < number_ranges; ++i) {
125 PageRange range;
126 // Transfer from 1-based to 0-based.
127 range.from = ranges[i].nFromPage - 1;
128 range.to = ranges[i].nToPage - 1;
129 ranges_vector.push_back(range);
130 }
131 }
132
133 settings_.set_ranges(ranges_vector);
134 settings_.set_device_name(new_device_name);
135 settings_.set_selection_only(selection_only);
136 PrintSettingsInitializerWin::InitPrintSettings(
137 context(), dev_mode, &settings_);
138
139 return true;
140}
141
thestige85e6b62016-08-25 00:00:06142PrintingContext::Result PrintingContextSystemDialogWin::ParseDialogResultEx(
vitalybukaf9d0c0c2014-09-09 19:53:33143 const PRINTDLGEX& dialog_options) {
144 // If the user clicked OK or Apply then Cancel, but not only Cancel.
145 if (dialog_options.dwResultAction != PD_RESULT_CANCEL) {
Lei Zhang3764d52b2018-07-24 22:31:11146 // Start fresh, but preserve is_modifiable and GDI print setting.
147 bool is_modifiable = settings_.is_modifiable();
thestige85e6b62016-08-25 00:00:06148 bool print_text_with_gdi = settings_.print_text_with_gdi();
vitalybukaf9d0c0c2014-09-09 19:53:33149 ResetSettings();
Lei Zhang3764d52b2018-07-24 22:31:11150 settings_.set_is_modifiable(is_modifiable);
thestige85e6b62016-08-25 00:00:06151 settings_.set_print_text_with_gdi(print_text_with_gdi);
vitalybukaf9d0c0c2014-09-09 19:53:33152
153 DEVMODE* dev_mode = NULL;
154 if (dialog_options.hDevMode) {
155 dev_mode =
156 reinterpret_cast<DEVMODE*>(GlobalLock(dialog_options.hDevMode));
157 DCHECK(dev_mode);
158 }
159
160 std::wstring device_name;
161 if (dialog_options.hDevNames) {
162 DEVNAMES* dev_names =
163 reinterpret_cast<DEVNAMES*>(GlobalLock(dialog_options.hDevNames));
164 DCHECK(dev_names);
165 if (dev_names) {
166 device_name = reinterpret_cast<const wchar_t*>(dev_names) +
167 dev_names->wDeviceOffset;
168 GlobalUnlock(dialog_options.hDevNames);
169 }
170 }
171
172 bool success = false;
173 if (dev_mode && !device_name.empty()) {
174 set_context(dialog_options.hDC);
175 PRINTPAGERANGE* page_ranges = NULL;
176 DWORD num_page_ranges = 0;
177 bool print_selection_only = false;
178 if (dialog_options.Flags & PD_PAGENUMS) {
179 page_ranges = dialog_options.lpPageRanges;
180 num_page_ranges = dialog_options.nPageRanges;
181 }
182 if (dialog_options.Flags & PD_SELECTION) {
183 print_selection_only = true;
184 }
mgiuca8ca59182015-07-08 02:10:21185 success =
186 InitializeSettingsWithRanges(*dev_mode, device_name, page_ranges,
187 num_page_ranges, print_selection_only);
vitalybukaf9d0c0c2014-09-09 19:53:33188 }
189
190 if (!success && dialog_options.hDC) {
191 DeleteDC(dialog_options.hDC);
192 set_context(NULL);
193 }
194
195 if (dev_mode) {
196 GlobalUnlock(dialog_options.hDevMode);
197 }
198 } else {
199 if (dialog_options.hDC) {
200 DeleteDC(dialog_options.hDC);
201 }
202 }
203
204 if (dialog_options.hDevMode != NULL)
205 GlobalFree(dialog_options.hDevMode);
206 if (dialog_options.hDevNames != NULL)
207 GlobalFree(dialog_options.hDevNames);
208
209 switch (dialog_options.dwResultAction) {
210 case PD_RESULT_PRINT:
211 return context() ? OK : FAILED;
212 case PD_RESULT_APPLY:
213 return context() ? CANCEL : FAILED;
214 case PD_RESULT_CANCEL:
215 return CANCEL;
216 default:
217 return FAILED;
218 }
219}
220
vitalybukaf9d0c0c2014-09-09 19:53:33221} // namespace printing