OLD | NEW |
(Empty) | |
| 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. |
| 4 |
| 5 #include "printing/printing_context_system_dialog_win.h" |
| 6 |
| 7 #include "base/message_loop/message_loop.h" |
| 8 #include "printing/backend/win_helper.h" |
| 9 #include "printing/print_settings_initializer_win.h" |
| 10 #include "skia/ext/platform_device.h" |
| 11 |
| 12 namespace printing { |
| 13 |
| 14 PrintingContextSytemDialogWin::PrintingContextSytemDialogWin(Delegate* delegate) |
| 15 : PrintingContextWin(delegate), dialog_box_(NULL) { |
| 16 } |
| 17 |
| 18 PrintingContextSytemDialogWin::~PrintingContextSytemDialogWin() { |
| 19 } |
| 20 |
| 21 void PrintingContextSytemDialogWin::AskUserForSettings( |
| 22 int max_pages, |
| 23 bool has_selection, |
| 24 const PrintSettingsCallback& callback) { |
| 25 DCHECK(!in_print_job_); |
| 26 dialog_box_dismissed_ = false; |
| 27 |
| 28 HWND window = GetRootWindow(delegate_->GetParentView()); |
| 29 DCHECK(window); |
| 30 |
| 31 // Show the OS-dependent dialog box. |
| 32 // If the user press |
| 33 // - OK, the settings are reset and reinitialized with the new settings. OK |
| 34 // is |
| 35 // returned. |
| 36 // - Apply then Cancel, the settings are reset and reinitialized with the |
| 37 // new |
| 38 // settings. CANCEL is returned. |
| 39 // - Cancel, the settings are not changed, the previous setting, if it was |
| 40 // initialized before, are kept. CANCEL is returned. |
| 41 // On failure, the settings are reset and FAILED is returned. |
| 42 PRINTDLGEX dialog_options = {sizeof(PRINTDLGEX)}; |
| 43 dialog_options.hwndOwner = window; |
| 44 // Disable options we don't support currently. |
| 45 // TODO(maruel): Reuse the previously loaded settings! |
| 46 dialog_options.Flags = PD_RETURNDC | PD_USEDEVMODECOPIESANDCOLLATE | |
| 47 PD_NOCURRENTPAGE | PD_HIDEPRINTTOFILE; |
| 48 if (!has_selection) |
| 49 dialog_options.Flags |= PD_NOSELECTION; |
| 50 |
| 51 PRINTPAGERANGE ranges[32]; |
| 52 dialog_options.nStartPage = START_PAGE_GENERAL; |
| 53 if (max_pages) { |
| 54 // Default initialize to print all the pages. |
| 55 memset(ranges, 0, sizeof(ranges)); |
| 56 ranges[0].nFromPage = 1; |
| 57 ranges[0].nToPage = max_pages; |
| 58 dialog_options.nPageRanges = 1; |
| 59 dialog_options.nMaxPageRanges = arraysize(ranges); |
| 60 dialog_options.nMinPage = 1; |
| 61 dialog_options.nMaxPage = max_pages; |
| 62 dialog_options.lpPageRanges = ranges; |
| 63 } else { |
| 64 // No need to bother, we don't know how many pages are available. |
| 65 dialog_options.Flags |= PD_NOPAGENUMS; |
| 66 } |
| 67 |
| 68 if (ShowPrintDialog(&dialog_options) != S_OK) { |
| 69 ResetSettings(); |
| 70 callback.Run(FAILED); |
| 71 } |
| 72 |
| 73 // TODO(maruel): Support PD_PRINTTOFILE. |
| 74 callback.Run(ParseDialogResultEx(dialog_options)); |
| 75 } |
| 76 |
| 77 void PrintingContextSytemDialogWin::Cancel() { |
| 78 PrintingContextWin::Cancel(); |
| 79 if (dialog_box_) { |
| 80 DestroyWindow(dialog_box_); |
| 81 dialog_box_dismissed_ = true; |
| 82 } |
| 83 } |
| 84 |
| 85 HRESULT PrintingContextSytemDialogWin::ShowPrintDialog(PRINTDLGEX* options) { |
| 86 // Note that this cannot use ui::BaseShellDialog as the print dialog is |
| 87 // system modal: opening it from a background thread can cause Windows to |
| 88 // get the wrong Z-order which will make the print dialog appear behind the |
| 89 // browser frame (but still being modal) so neither the browser frame nor |
| 90 // the print dialog will get any input. See http://crbug.com/342697 |
| 91 // http://crbug.com/180997 for details. |
| 92 base::MessageLoop::ScopedNestableTaskAllower allow( |
| 93 base::MessageLoop::current()); |
| 94 |
| 95 return PrintDlgEx(options); |
| 96 } |
| 97 |
| 98 bool PrintingContextSytemDialogWin::InitializeSettings( |
| 99 const DEVMODE& dev_mode, |
| 100 const std::wstring& new_device_name, |
| 101 const PRINTPAGERANGE* ranges, |
| 102 int number_ranges, |
| 103 bool selection_only) { |
| 104 DCHECK(GetDeviceCaps(context(), CLIPCAPS)); |
| 105 DCHECK(GetDeviceCaps(context(), RASTERCAPS) & RC_STRETCHDIB); |
| 106 DCHECK(GetDeviceCaps(context(), RASTERCAPS) & RC_BITMAP64); |
| 107 // Some printers don't advertise these. |
| 108 // DCHECK(GetDeviceCaps(context(), RASTERCAPS) & RC_SCALING); |
| 109 // DCHECK(GetDeviceCaps(context(), SHADEBLENDCAPS) & SB_CONST_ALPHA); |
| 110 // DCHECK(GetDeviceCaps(context(), SHADEBLENDCAPS) & SB_PIXEL_ALPHA); |
| 111 |
| 112 // StretchDIBits() support is needed for printing. |
| 113 if (!(GetDeviceCaps(context(), RASTERCAPS) & RC_STRETCHDIB) || |
| 114 !(GetDeviceCaps(context(), RASTERCAPS) & RC_BITMAP64)) { |
| 115 NOTREACHED(); |
| 116 ResetSettings(); |
| 117 return false; |
| 118 } |
| 119 |
| 120 DCHECK(!in_print_job_); |
| 121 DCHECK(context()); |
| 122 PageRanges ranges_vector; |
| 123 if (!selection_only) { |
| 124 // Convert the PRINTPAGERANGE array to a PrintSettings::PageRanges vector. |
| 125 ranges_vector.reserve(number_ranges); |
| 126 for (int i = 0; i < number_ranges; ++i) { |
| 127 PageRange range; |
| 128 // Transfer from 1-based to 0-based. |
| 129 range.from = ranges[i].nFromPage - 1; |
| 130 range.to = ranges[i].nToPage - 1; |
| 131 ranges_vector.push_back(range); |
| 132 } |
| 133 } |
| 134 |
| 135 settings_.set_ranges(ranges_vector); |
| 136 settings_.set_device_name(new_device_name); |
| 137 settings_.set_selection_only(selection_only); |
| 138 PrintSettingsInitializerWin::InitPrintSettings( |
| 139 context(), dev_mode, &settings_); |
| 140 |
| 141 return true; |
| 142 } |
| 143 |
| 144 PrintingContext::Result PrintingContextSytemDialogWin::ParseDialogResultEx( |
| 145 const PRINTDLGEX& dialog_options) { |
| 146 // If the user clicked OK or Apply then Cancel, but not only Cancel. |
| 147 if (dialog_options.dwResultAction != PD_RESULT_CANCEL) { |
| 148 // Start fresh. |
| 149 ResetSettings(); |
| 150 |
| 151 DEVMODE* dev_mode = NULL; |
| 152 if (dialog_options.hDevMode) { |
| 153 dev_mode = |
| 154 reinterpret_cast<DEVMODE*>(GlobalLock(dialog_options.hDevMode)); |
| 155 DCHECK(dev_mode); |
| 156 } |
| 157 |
| 158 std::wstring device_name; |
| 159 if (dialog_options.hDevNames) { |
| 160 DEVNAMES* dev_names = |
| 161 reinterpret_cast<DEVNAMES*>(GlobalLock(dialog_options.hDevNames)); |
| 162 DCHECK(dev_names); |
| 163 if (dev_names) { |
| 164 device_name = reinterpret_cast<const wchar_t*>(dev_names) + |
| 165 dev_names->wDeviceOffset; |
| 166 GlobalUnlock(dialog_options.hDevNames); |
| 167 } |
| 168 } |
| 169 |
| 170 bool success = false; |
| 171 if (dev_mode && !device_name.empty()) { |
| 172 set_context(dialog_options.hDC); |
| 173 PRINTPAGERANGE* page_ranges = NULL; |
| 174 DWORD num_page_ranges = 0; |
| 175 bool print_selection_only = false; |
| 176 if (dialog_options.Flags & PD_PAGENUMS) { |
| 177 page_ranges = dialog_options.lpPageRanges; |
| 178 num_page_ranges = dialog_options.nPageRanges; |
| 179 } |
| 180 if (dialog_options.Flags & PD_SELECTION) { |
| 181 print_selection_only = true; |
| 182 } |
| 183 success = InitializeSettings(*dev_mode, |
| 184 device_name, |
| 185 page_ranges, |
| 186 num_page_ranges, |
| 187 print_selection_only); |
| 188 } |
| 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 |
| 221 PrintingContext::Result PrintingContextSytemDialogWin::ParseDialogResult( |
| 222 const PRINTDLG& dialog_options) { |
| 223 // If the user clicked OK or Apply then Cancel, but not only Cancel. |
| 224 // Start fresh. |
| 225 ResetSettings(); |
| 226 |
| 227 DEVMODE* dev_mode = NULL; |
| 228 if (dialog_options.hDevMode) { |
| 229 dev_mode = reinterpret_cast<DEVMODE*>(GlobalLock(dialog_options.hDevMode)); |
| 230 DCHECK(dev_mode); |
| 231 } |
| 232 |
| 233 std::wstring device_name; |
| 234 if (dialog_options.hDevNames) { |
| 235 DEVNAMES* dev_names = |
| 236 reinterpret_cast<DEVNAMES*>(GlobalLock(dialog_options.hDevNames)); |
| 237 DCHECK(dev_names); |
| 238 if (dev_names) { |
| 239 device_name = reinterpret_cast<const wchar_t*>( |
| 240 reinterpret_cast<const wchar_t*>(dev_names) + |
| 241 dev_names->wDeviceOffset); |
| 242 GlobalUnlock(dialog_options.hDevNames); |
| 243 } |
| 244 } |
| 245 |
| 246 bool success = false; |
| 247 if (dev_mode && !device_name.empty()) { |
| 248 set_context(dialog_options.hDC); |
| 249 success = InitializeSettings(*dev_mode, device_name, NULL, 0, false); |
| 250 } |
| 251 |
| 252 if (!success && dialog_options.hDC) { |
| 253 DeleteDC(dialog_options.hDC); |
| 254 set_context(NULL); |
| 255 } |
| 256 |
| 257 if (dev_mode) { |
| 258 GlobalUnlock(dialog_options.hDevMode); |
| 259 } |
| 260 |
| 261 if (dialog_options.hDevMode != NULL) |
| 262 GlobalFree(dialog_options.hDevMode); |
| 263 if (dialog_options.hDevNames != NULL) |
| 264 GlobalFree(dialog_options.hDevNames); |
| 265 |
| 266 return context() ? OK : FAILED; |
| 267 } |
| 268 |
| 269 } // namespace printing |
OLD | NEW |