[email protected] | d0767cb54 | 2009-10-08 17:38:30 | [diff] [blame] | 1 | // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
license.bot | bf09a50 | 2008-08-24 00:55:55 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 4 | |
[email protected] | 8ff1d42 | 2009-07-07 21:31:39 | [diff] [blame] | 5 | #include "printing/printing_context.h" |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 6 | |
| 7 | #include <winspool.h> |
| 8 | |
| 9 | #include "base/file_util.h" |
[email protected] | d0767cb54 | 2009-10-08 17:38:30 | [diff] [blame] | 10 | #include "base/i18n/file_util_icu.h" |
[email protected] | 260d157 | 2009-10-09 18:50:35 | [diff] [blame] | 11 | #include "base/i18n/time_formatting.h" |
[email protected] | dcccb94 | 2009-02-01 18:23:00 | [diff] [blame] | 12 | #include "base/message_loop.h" |
| 13 | #include "base/time.h" |
[email protected] | d9d4299 | 2010-09-13 19:39:19 | [diff] [blame] | 14 | #include "base/utf_string_conversions.h" |
[email protected] | 8ff1d42 | 2009-07-07 21:31:39 | [diff] [blame] | 15 | #include "printing/printed_document.h" |
[email protected] | c399a8a | 2008-11-22 19:38:00 | [diff] [blame] | 16 | #include "skia/ext/platform_device_win.h" |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 17 | |
[email protected] | e1acf6f | 2008-10-27 20:43:33 | [diff] [blame] | 18 | using base::Time; |
| 19 | |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 20 | namespace printing { |
| 21 | |
[email protected] | 5930cb6 | 2009-12-08 02:04:22 | [diff] [blame] | 22 | class PrintingContext::CallbackHandler : public IPrintDialogCallback, |
| 23 | public IObjectWithSite { |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 24 | public: |
| 25 | CallbackHandler(PrintingContext& owner, HWND owner_hwnd) |
| 26 | : owner_(owner), |
| 27 | owner_hwnd_(owner_hwnd), |
| 28 | services_(NULL) { |
| 29 | } |
| 30 | |
| 31 | ~CallbackHandler() { |
| 32 | if (services_) |
| 33 | services_->Release(); |
| 34 | } |
| 35 | |
| 36 | IUnknown* ToIUnknown() { |
| 37 | return static_cast<IUnknown*>(static_cast<IPrintDialogCallback*>(this)); |
| 38 | } |
| 39 | |
| 40 | // IUnknown |
| 41 | virtual HRESULT WINAPI QueryInterface(REFIID riid, void**object) { |
| 42 | if (riid == IID_IUnknown) { |
| 43 | *object = ToIUnknown(); |
| 44 | } else if (riid == IID_IPrintDialogCallback) { |
| 45 | *object = static_cast<IPrintDialogCallback*>(this); |
| 46 | } else if (riid == IID_IObjectWithSite) { |
| 47 | *object = static_cast<IObjectWithSite*>(this); |
| 48 | } else { |
| 49 | return E_NOINTERFACE; |
| 50 | } |
| 51 | return S_OK; |
| 52 | } |
| 53 | |
| 54 | // No real ref counting. |
| 55 | virtual ULONG WINAPI AddRef() { |
| 56 | return 1; |
| 57 | } |
| 58 | virtual ULONG WINAPI Release() { |
| 59 | return 1; |
| 60 | } |
| 61 | |
| 62 | // IPrintDialogCallback methods |
| 63 | virtual HRESULT WINAPI InitDone() { |
| 64 | return S_OK; |
| 65 | } |
| 66 | |
| 67 | virtual HRESULT WINAPI SelectionChange() { |
| 68 | if (services_) { |
| 69 | // TODO(maruel): Get the devmode for the new printer with |
| 70 | // services_->GetCurrentDevMode(&devmode, &size), send that information |
| 71 | // back to our client and continue. The client needs to recalculate the |
| 72 | // number of rendered pages and send back this information here. |
| 73 | } |
| 74 | return S_OK; |
| 75 | } |
| 76 | |
| 77 | virtual HRESULT WINAPI HandleMessage(HWND dialog, |
| 78 | UINT message, |
| 79 | WPARAM wparam, |
| 80 | LPARAM lparam, |
| 81 | LRESULT* result) { |
| 82 | // Cheap way to retrieve the window handle. |
| 83 | if (!owner_.dialog_box_) { |
| 84 | // The handle we receive is the one of the groupbox in the General tab. We |
| 85 | // need to get the grand-father to get the dialog box handle. |
| 86 | owner_.dialog_box_ = GetAncestor(dialog, GA_ROOT); |
| 87 | // Trick to enable the owner window. This can cause issues with navigation |
| 88 | // events so it may have to be disabled if we don't fix the side-effects. |
| 89 | EnableWindow(owner_hwnd_, TRUE); |
| 90 | } |
| 91 | return S_FALSE; |
| 92 | } |
| 93 | |
| 94 | virtual HRESULT WINAPI SetSite(IUnknown* site) { |
| 95 | if (!site) { |
| 96 | DCHECK(services_); |
| 97 | services_->Release(); |
| 98 | services_ = NULL; |
| 99 | // The dialog box is destroying, PrintJob::Worker don't need the handle |
| 100 | // anymore. |
| 101 | owner_.dialog_box_ = NULL; |
| 102 | } else { |
| 103 | DCHECK(services_ == NULL); |
| 104 | HRESULT hr = site->QueryInterface(IID_IPrintDialogServices, |
| 105 | reinterpret_cast<void**>(&services_)); |
| 106 | DCHECK(SUCCEEDED(hr)); |
| 107 | } |
| 108 | return S_OK; |
| 109 | } |
| 110 | |
| 111 | virtual HRESULT WINAPI GetSite(REFIID riid, void** site) { |
| 112 | return E_NOTIMPL; |
| 113 | } |
| 114 | |
| 115 | private: |
| 116 | PrintingContext& owner_; |
| 117 | HWND owner_hwnd_; |
| 118 | IPrintDialogServices* services_; |
| 119 | |
[email protected] | 5930cb6 | 2009-12-08 02:04:22 | [diff] [blame] | 120 | DISALLOW_COPY_AND_ASSIGN(CallbackHandler); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 121 | }; |
| 122 | |
| 123 | PrintingContext::PrintingContext() |
[email protected] | b75dca8 | 2009-10-13 18:46:21 | [diff] [blame] | 124 | : context_(NULL), |
[email protected] | 0ae80b89 | 2008-10-15 17:56:40 | [diff] [blame] | 125 | #ifndef NDEBUG |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 126 | page_number_(-1), |
| 127 | #endif |
| 128 | dialog_box_(NULL), |
| 129 | dialog_box_dismissed_(false), |
[email protected] | 8ff1d42 | 2009-07-07 21:31:39 | [diff] [blame] | 130 | in_print_job_(false), |
[email protected] | d825462 | 2010-08-13 19:15:46 | [diff] [blame] | 131 | abort_printing_(false), |
| 132 | print_dialog_func_(&PrintDlgEx) { |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 133 | } |
| 134 | |
| 135 | PrintingContext::~PrintingContext() { |
| 136 | ResetSettings(); |
| 137 | } |
| 138 | |
[email protected] | b719142 | 2010-09-21 19:18:05 | [diff] [blame] | 139 | void PrintingContext::AskUserForSettings(HWND view, |
| 140 | int max_pages, |
| 141 | bool has_selection, |
| 142 | PrintSettingsCallback* callback) { |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 143 | DCHECK(!in_print_job_); |
| 144 | dialog_box_dismissed_ = false; |
[email protected] | fc790462 | 2010-05-12 19:26:40 | [diff] [blame] | 145 | |
| 146 | HWND window; |
| 147 | if (!view || !IsWindow(view)) { |
| 148 | // TODO(maruel): bug 1214347 Get the right browser window instead. |
| 149 | window = GetDesktopWindow(); |
| 150 | } else { |
| 151 | window = GetAncestor(view, GA_ROOTOWNER); |
| 152 | } |
| 153 | DCHECK(window); |
| 154 | |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 155 | // Show the OS-dependent dialog box. |
| 156 | // If the user press |
| 157 | // - OK, the settings are reset and reinitialized with the new settings. OK is |
| 158 | // returned. |
| 159 | // - Apply then Cancel, the settings are reset and reinitialized with the new |
| 160 | // settings. CANCEL is returned. |
| 161 | // - Cancel, the settings are not changed, the previous setting, if it was |
| 162 | // initialized before, are kept. CANCEL is returned. |
| 163 | // On failure, the settings are reset and FAILED is returned. |
| 164 | PRINTDLGEX dialog_options = { sizeof(PRINTDLGEX) }; |
| 165 | dialog_options.hwndOwner = window; |
[email protected] | c8ad40c | 2009-06-08 17:05:21 | [diff] [blame] | 166 | // Disable options we don't support currently. |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 167 | // TODO(maruel): Reuse the previously loaded settings! |
| 168 | dialog_options.Flags = PD_RETURNDC | PD_USEDEVMODECOPIESANDCOLLATE | |
[email protected] | c8ad40c | 2009-06-08 17:05:21 | [diff] [blame] | 169 | PD_NOCURRENTPAGE | PD_HIDEPRINTTOFILE; |
| 170 | if (!has_selection) |
| 171 | dialog_options.Flags |= PD_NOSELECTION; |
| 172 | |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 173 | PRINTPAGERANGE ranges[32]; |
| 174 | dialog_options.nStartPage = START_PAGE_GENERAL; |
| 175 | if (max_pages) { |
| 176 | // Default initialize to print all the pages. |
| 177 | memset(ranges, 0, sizeof(ranges)); |
| 178 | ranges[0].nFromPage = 1; |
| 179 | ranges[0].nToPage = max_pages; |
| 180 | dialog_options.nPageRanges = 1; |
| 181 | dialog_options.nMaxPageRanges = arraysize(ranges); |
[email protected] | 3a0e4a3 | 2009-06-09 19:07:05 | [diff] [blame] | 182 | dialog_options.nMinPage = 1; |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 183 | dialog_options.nMaxPage = max_pages; |
| 184 | dialog_options.lpPageRanges = ranges; |
| 185 | } else { |
| 186 | // No need to bother, we don't know how many pages are available. |
| 187 | dialog_options.Flags |= PD_NOPAGENUMS; |
| 188 | } |
| 189 | |
| 190 | { |
[email protected] | d825462 | 2010-08-13 19:15:46 | [diff] [blame] | 191 | if ((*print_dialog_func_)(&dialog_options) != S_OK) { |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 192 | ResetSettings(); |
[email protected] | b719142 | 2010-09-21 19:18:05 | [diff] [blame] | 193 | callback->Run(FAILED); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 194 | } |
| 195 | } |
| 196 | // TODO(maruel): Support PD_PRINTTOFILE. |
[email protected] | b719142 | 2010-09-21 19:18:05 | [diff] [blame] | 197 | callback->Run(ParseDialogResultEx(dialog_options)); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 198 | } |
| 199 | |
| 200 | PrintingContext::Result PrintingContext::UseDefaultSettings() { |
| 201 | DCHECK(!in_print_job_); |
| 202 | |
| 203 | PRINTDLG dialog_options = { sizeof(PRINTDLG) }; |
| 204 | dialog_options.Flags = PD_RETURNDC | PD_RETURNDEFAULT; |
| 205 | if (PrintDlg(&dialog_options) == 0) { |
| 206 | ResetSettings(); |
| 207 | return FAILED; |
| 208 | } |
| 209 | return ParseDialogResult(dialog_options); |
| 210 | } |
| 211 | |
| 212 | PrintingContext::Result PrintingContext::InitWithSettings( |
| 213 | const PrintSettings& settings) { |
| 214 | DCHECK(!in_print_job_); |
| 215 | settings_ = settings; |
| 216 | // TODO(maruel): settings_->ToDEVMODE() |
| 217 | HANDLE printer; |
| 218 | if (!OpenPrinter(const_cast<wchar_t*>(settings_.device_name().c_str()), |
| 219 | &printer, |
| 220 | NULL)) |
| 221 | return FAILED; |
| 222 | |
| 223 | Result status = OK; |
| 224 | |
| 225 | if (!GetPrinterSettings(printer, settings_.device_name())) |
| 226 | status = FAILED; |
| 227 | |
| 228 | // Close the printer after retrieving the context. |
| 229 | ClosePrinter(printer); |
| 230 | |
| 231 | if (status != OK) |
| 232 | ResetSettings(); |
| 233 | return status; |
| 234 | } |
| 235 | |
| 236 | void PrintingContext::ResetSettings() { |
[email protected] | b75dca8 | 2009-10-13 18:46:21 | [diff] [blame] | 237 | if (context_ != NULL) { |
| 238 | DeleteDC(context_); |
| 239 | context_ = NULL; |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 240 | } |
| 241 | settings_.Clear(); |
| 242 | in_print_job_ = false; |
| 243 | |
[email protected] | 0ae80b89 | 2008-10-15 17:56:40 | [diff] [blame] | 244 | #ifndef NDEBUG |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 245 | page_number_ = -1; |
| 246 | #endif |
| 247 | } |
| 248 | |
| 249 | PrintingContext::Result PrintingContext::NewDocument( |
[email protected] | d9d4299 | 2010-09-13 19:39:19 | [diff] [blame] | 250 | const string16& document_name) { |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 251 | DCHECK(!in_print_job_); |
[email protected] | b75dca8 | 2009-10-13 18:46:21 | [diff] [blame] | 252 | if (!context_) |
[email protected] | c8ad40c | 2009-06-08 17:05:21 | [diff] [blame] | 253 | return OnError(); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 254 | |
| 255 | // Set the flag used by the AbortPrintJob dialog procedure. |
| 256 | abort_printing_ = false; |
| 257 | |
| 258 | in_print_job_ = true; |
| 259 | |
| 260 | // Register the application's AbortProc function with GDI. |
[email protected] | b75dca8 | 2009-10-13 18:46:21 | [diff] [blame] | 261 | if (SP_ERROR == SetAbortProc(context_, &AbortProc)) |
[email protected] | c8ad40c | 2009-06-08 17:05:21 | [diff] [blame] | 262 | return OnError(); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 263 | |
| 264 | DOCINFO di = { sizeof(DOCINFO) }; |
[email protected] | d9d4299 | 2010-09-13 19:39:19 | [diff] [blame] | 265 | di.lpszDocName = UTF16ToWide(document_name).c_str(); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 266 | |
| 267 | // Is there a debug dump directory specified? If so, force to print to a file. |
[email protected] | d9d4299 | 2010-09-13 19:39:19 | [diff] [blame] | 268 | FilePath debug_dump_path = PrintedDocument::debug_dump_path(); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 269 | if (!debug_dump_path.empty()) { |
| 270 | // Create a filename. |
| 271 | std::wstring filename; |
| 272 | Time now(Time::Now()); |
[email protected] | 5cca3a5 | 2008-08-19 22:35:29 | [diff] [blame] | 273 | filename = base::TimeFormatShortDateNumeric(now); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 274 | filename += L"_"; |
[email protected] | 5cca3a5 | 2008-08-19 22:35:29 | [diff] [blame] | 275 | filename += base::TimeFormatTimeOfDay(now); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 276 | filename += L"_"; |
[email protected] | d9d4299 | 2010-09-13 19:39:19 | [diff] [blame] | 277 | filename += UTF16ToWide(document_name); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 278 | filename += L"_"; |
| 279 | filename += L"buffer.prn"; |
[email protected] | de294335 | 2009-10-22 23:06:12 | [diff] [blame] | 280 | file_util::ReplaceIllegalCharactersInPath(&filename, '_'); |
[email protected] | d9d4299 | 2010-09-13 19:39:19 | [diff] [blame] | 281 | debug_dump_path.Append(filename); |
| 282 | di.lpszOutput = debug_dump_path.value().c_str(); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 283 | } |
| 284 | |
[email protected] | daee497 | 2009-07-09 14:28:24 | [diff] [blame] | 285 | // No message loop running in unit tests. |
| 286 | DCHECK(!MessageLoop::current() ? true : |
| 287 | !MessageLoop::current()->NestableTasksAllowed()); |
| 288 | |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 289 | // Begin a print job by calling the StartDoc function. |
| 290 | // NOTE: StartDoc() starts a message loop. That causes a lot of problems with |
| 291 | // IPC. Make sure recursive task processing is disabled. |
[email protected] | b75dca8 | 2009-10-13 18:46:21 | [diff] [blame] | 292 | if (StartDoc(context_, &di) <= 0) |
[email protected] | c8ad40c | 2009-06-08 17:05:21 | [diff] [blame] | 293 | return OnError(); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 294 | |
[email protected] | 0ae80b89 | 2008-10-15 17:56:40 | [diff] [blame] | 295 | #ifndef NDEBUG |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 296 | page_number_ = 0; |
| 297 | #endif |
| 298 | return OK; |
| 299 | } |
| 300 | |
| 301 | PrintingContext::Result PrintingContext::NewPage() { |
| 302 | if (abort_printing_) |
| 303 | return CANCEL; |
[email protected] | 3b52c98 | 2010-09-27 20:40:36 | [diff] [blame] | 304 | |
| 305 | DCHECK(context_); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 306 | DCHECK(in_print_job_); |
| 307 | |
| 308 | // Inform the driver that the application is about to begin sending data. |
[email protected] | b75dca8 | 2009-10-13 18:46:21 | [diff] [blame] | 309 | if (StartPage(context_) <= 0) |
[email protected] | c8ad40c | 2009-06-08 17:05:21 | [diff] [blame] | 310 | return OnError(); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 311 | |
[email protected] | 0ae80b89 | 2008-10-15 17:56:40 | [diff] [blame] | 312 | #ifndef NDEBUG |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 313 | ++page_number_; |
| 314 | #endif |
| 315 | |
| 316 | return OK; |
| 317 | } |
| 318 | |
| 319 | PrintingContext::Result PrintingContext::PageDone() { |
| 320 | if (abort_printing_) |
| 321 | return CANCEL; |
| 322 | DCHECK(in_print_job_); |
| 323 | |
[email protected] | b75dca8 | 2009-10-13 18:46:21 | [diff] [blame] | 324 | if (EndPage(context_) <= 0) |
[email protected] | c8ad40c | 2009-06-08 17:05:21 | [diff] [blame] | 325 | return OnError(); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 326 | return OK; |
| 327 | } |
| 328 | |
| 329 | PrintingContext::Result PrintingContext::DocumentDone() { |
| 330 | if (abort_printing_) |
| 331 | return CANCEL; |
| 332 | DCHECK(in_print_job_); |
[email protected] | 6074541 | 2010-09-27 23:46:07 | [diff] [blame^] | 333 | DCHECK(context_); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 334 | |
| 335 | // Inform the driver that document has ended. |
[email protected] | b75dca8 | 2009-10-13 18:46:21 | [diff] [blame] | 336 | if (EndDoc(context_) <= 0) |
[email protected] | c8ad40c | 2009-06-08 17:05:21 | [diff] [blame] | 337 | return OnError(); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 338 | |
| 339 | ResetSettings(); |
| 340 | return OK; |
| 341 | } |
| 342 | |
| 343 | void PrintingContext::Cancel() { |
| 344 | abort_printing_ = true; |
| 345 | in_print_job_ = false; |
[email protected] | b75dca8 | 2009-10-13 18:46:21 | [diff] [blame] | 346 | if (context_) |
| 347 | CancelDC(context_); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 348 | DismissDialog(); |
| 349 | } |
| 350 | |
| 351 | void PrintingContext::DismissDialog() { |
| 352 | if (dialog_box_) { |
| 353 | DestroyWindow(dialog_box_); |
| 354 | dialog_box_dismissed_ = true; |
| 355 | } |
| 356 | } |
| 357 | |
[email protected] | c8ad40c | 2009-06-08 17:05:21 | [diff] [blame] | 358 | PrintingContext::Result PrintingContext::OnError() { |
[email protected] | b75dca8 | 2009-10-13 18:46:21 | [diff] [blame] | 359 | // This will close context_ and clear settings_. |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 360 | ResetSettings(); |
| 361 | return abort_printing_ ? CANCEL : FAILED; |
| 362 | } |
| 363 | |
| 364 | // static |
| 365 | BOOL PrintingContext::AbortProc(HDC hdc, int nCode) { |
| 366 | if (nCode) { |
| 367 | // TODO(maruel): Need a way to find the right instance to set. Should |
| 368 | // leverage PrintJobManager here? |
| 369 | // abort_printing_ = true; |
| 370 | } |
| 371 | return true; |
| 372 | } |
| 373 | |
| 374 | bool PrintingContext::InitializeSettings(const DEVMODE& dev_mode, |
| 375 | const std::wstring& new_device_name, |
| 376 | const PRINTPAGERANGE* ranges, |
[email protected] | c8ad40c | 2009-06-08 17:05:21 | [diff] [blame] | 377 | int number_ranges, |
| 378 | bool selection_only) { |
[email protected] | b75dca8 | 2009-10-13 18:46:21 | [diff] [blame] | 379 | skia::PlatformDevice::InitializeDC(context_); |
| 380 | DCHECK(GetDeviceCaps(context_, CLIPCAPS)); |
| 381 | DCHECK(GetDeviceCaps(context_, RASTERCAPS) & RC_STRETCHDIB); |
| 382 | DCHECK(GetDeviceCaps(context_, RASTERCAPS) & RC_BITMAP64); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 383 | // Some printers don't advertise these. |
[email protected] | b75dca8 | 2009-10-13 18:46:21 | [diff] [blame] | 384 | // DCHECK(GetDeviceCaps(context_, RASTERCAPS) & RC_SCALING); |
| 385 | // DCHECK(GetDeviceCaps(context_, SHADEBLENDCAPS) & SB_CONST_ALPHA); |
| 386 | // DCHECK(GetDeviceCaps(context_, SHADEBLENDCAPS) & SB_PIXEL_ALPHA); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 387 | |
| 388 | // StretchDIBits() support is needed for printing. |
[email protected] | b75dca8 | 2009-10-13 18:46:21 | [diff] [blame] | 389 | if (!(GetDeviceCaps(context_, RASTERCAPS) & RC_STRETCHDIB) || |
| 390 | !(GetDeviceCaps(context_, RASTERCAPS) & RC_BITMAP64)) { |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 391 | NOTREACHED(); |
| 392 | ResetSettings(); |
| 393 | return false; |
| 394 | } |
| 395 | |
| 396 | DCHECK(!in_print_job_); |
[email protected] | b75dca8 | 2009-10-13 18:46:21 | [diff] [blame] | 397 | DCHECK(context_); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 398 | PageRanges ranges_vector; |
[email protected] | 8227045 | 2009-06-19 15:58:01 | [diff] [blame] | 399 | if (!selection_only) { |
| 400 | // Convert the PRINTPAGERANGE array to a PrintSettings::PageRanges vector. |
| 401 | ranges_vector.reserve(number_ranges); |
| 402 | for (int i = 0; i < number_ranges; ++i) { |
| 403 | PageRange range; |
| 404 | // Transfer from 1-based to 0-based. |
| 405 | range.from = ranges[i].nFromPage - 1; |
| 406 | range.to = ranges[i].nToPage - 1; |
| 407 | ranges_vector.push_back(range); |
| 408 | } |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 409 | } |
[email protected] | b75dca8 | 2009-10-13 18:46:21 | [diff] [blame] | 410 | settings_.Init(context_, |
[email protected] | c8ad40c | 2009-06-08 17:05:21 | [diff] [blame] | 411 | dev_mode, |
| 412 | ranges_vector, |
| 413 | new_device_name, |
| 414 | selection_only); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 415 | return true; |
| 416 | } |
| 417 | |
| 418 | bool PrintingContext::GetPrinterSettings(HANDLE printer, |
| 419 | const std::wstring& device_name) { |
| 420 | DCHECK(!in_print_job_); |
| 421 | scoped_array<uint8> buffer; |
| 422 | |
| 423 | // A PRINTER_INFO_9 structure specifying the per-user default printer |
| 424 | // settings. |
| 425 | GetPrinterHelper(printer, 9, &buffer); |
| 426 | if (buffer.get()) { |
| 427 | PRINTER_INFO_9* info_9 = reinterpret_cast<PRINTER_INFO_9*>(buffer.get()); |
| 428 | if (info_9->pDevMode != NULL) { |
[email protected] | d825462 | 2010-08-13 19:15:46 | [diff] [blame] | 429 | if (!AllocateContext(device_name, info_9->pDevMode, &context_)) { |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 430 | ResetSettings(); |
| 431 | return false; |
| 432 | } |
[email protected] | c8ad40c | 2009-06-08 17:05:21 | [diff] [blame] | 433 | return InitializeSettings(*info_9->pDevMode, device_name, NULL, 0, false); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 434 | } |
| 435 | buffer.reset(); |
| 436 | } |
| 437 | |
| 438 | // A PRINTER_INFO_8 structure specifying the global default printer settings. |
| 439 | GetPrinterHelper(printer, 8, &buffer); |
| 440 | if (buffer.get()) { |
| 441 | PRINTER_INFO_8* info_8 = reinterpret_cast<PRINTER_INFO_8*>(buffer.get()); |
| 442 | if (info_8->pDevMode != NULL) { |
[email protected] | d825462 | 2010-08-13 19:15:46 | [diff] [blame] | 443 | if (!AllocateContext(device_name, info_8->pDevMode, &context_)) { |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 444 | ResetSettings(); |
| 445 | return false; |
| 446 | } |
[email protected] | c8ad40c | 2009-06-08 17:05:21 | [diff] [blame] | 447 | return InitializeSettings(*info_8->pDevMode, device_name, NULL, 0, false); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 448 | } |
| 449 | buffer.reset(); |
| 450 | } |
| 451 | |
| 452 | // A PRINTER_INFO_2 structure specifying the driver's default printer |
| 453 | // settings. |
| 454 | GetPrinterHelper(printer, 2, &buffer); |
| 455 | if (buffer.get()) { |
| 456 | PRINTER_INFO_2* info_2 = reinterpret_cast<PRINTER_INFO_2*>(buffer.get()); |
| 457 | if (info_2->pDevMode != NULL) { |
[email protected] | d825462 | 2010-08-13 19:15:46 | [diff] [blame] | 458 | if (!AllocateContext(device_name, info_2->pDevMode, &context_)) { |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 459 | ResetSettings(); |
| 460 | return false; |
| 461 | } |
[email protected] | c8ad40c | 2009-06-08 17:05:21 | [diff] [blame] | 462 | return InitializeSettings(*info_2->pDevMode, device_name, NULL, 0, false); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 463 | } |
| 464 | buffer.reset(); |
| 465 | } |
| 466 | // Failed to retrieve the printer settings. |
| 467 | ResetSettings(); |
| 468 | return false; |
| 469 | } |
| 470 | |
[email protected] | d825462 | 2010-08-13 19:15:46 | [diff] [blame] | 471 | // static |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 472 | bool PrintingContext::AllocateContext(const std::wstring& printer_name, |
[email protected] | d825462 | 2010-08-13 19:15:46 | [diff] [blame] | 473 | const DEVMODE* dev_mode, |
| 474 | gfx::NativeDrawingContext* context) { |
| 475 | *context = CreateDC(L"WINSPOOL", printer_name.c_str(), NULL, dev_mode); |
| 476 | DCHECK(*context); |
| 477 | return *context != NULL; |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 478 | } |
| 479 | |
| 480 | PrintingContext::Result PrintingContext::ParseDialogResultEx( |
| 481 | const PRINTDLGEX& dialog_options) { |
| 482 | // If the user clicked OK or Apply then Cancel, but not only Cancel. |
| 483 | if (dialog_options.dwResultAction != PD_RESULT_CANCEL) { |
| 484 | // Start fresh. |
| 485 | ResetSettings(); |
| 486 | |
| 487 | DEVMODE* dev_mode = NULL; |
| 488 | if (dialog_options.hDevMode) { |
| 489 | dev_mode = |
| 490 | reinterpret_cast<DEVMODE*>(GlobalLock(dialog_options.hDevMode)); |
| 491 | DCHECK(dev_mode); |
| 492 | } |
| 493 | |
| 494 | std::wstring device_name; |
| 495 | if (dialog_options.hDevNames) { |
| 496 | DEVNAMES* dev_names = |
| 497 | reinterpret_cast<DEVNAMES*>(GlobalLock(dialog_options.hDevNames)); |
| 498 | DCHECK(dev_names); |
| 499 | if (dev_names) { |
| 500 | device_name = |
| 501 | reinterpret_cast<const wchar_t*>( |
| 502 | reinterpret_cast<const wchar_t*>(dev_names) + |
| 503 | dev_names->wDeviceOffset); |
| 504 | GlobalUnlock(dialog_options.hDevNames); |
| 505 | } |
| 506 | } |
| 507 | |
| 508 | bool success = false; |
| 509 | if (dev_mode && !device_name.empty()) { |
[email protected] | b75dca8 | 2009-10-13 18:46:21 | [diff] [blame] | 510 | context_ = dialog_options.hDC; |
[email protected] | c8ad40c | 2009-06-08 17:05:21 | [diff] [blame] | 511 | PRINTPAGERANGE* page_ranges = NULL; |
| 512 | DWORD num_page_ranges = 0; |
| 513 | bool print_selection_only = false; |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 514 | if (dialog_options.Flags & PD_PAGENUMS) { |
[email protected] | c8ad40c | 2009-06-08 17:05:21 | [diff] [blame] | 515 | page_ranges = dialog_options.lpPageRanges; |
| 516 | num_page_ranges = dialog_options.nPageRanges; |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 517 | } |
[email protected] | c8ad40c | 2009-06-08 17:05:21 | [diff] [blame] | 518 | if (dialog_options.Flags & PD_SELECTION) { |
| 519 | print_selection_only = true; |
| 520 | } |
| 521 | success = InitializeSettings(*dev_mode, |
| 522 | device_name, |
[email protected] | d825462 | 2010-08-13 19:15:46 | [diff] [blame] | 523 | page_ranges, |
| 524 | num_page_ranges, |
[email protected] | c8ad40c | 2009-06-08 17:05:21 | [diff] [blame] | 525 | print_selection_only); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 526 | } |
| 527 | |
| 528 | if (!success && dialog_options.hDC) { |
| 529 | DeleteDC(dialog_options.hDC); |
[email protected] | b75dca8 | 2009-10-13 18:46:21 | [diff] [blame] | 530 | context_ = NULL; |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 531 | } |
| 532 | |
| 533 | if (dev_mode) { |
| 534 | GlobalUnlock(dialog_options.hDevMode); |
| 535 | } |
| 536 | } else { |
| 537 | if (dialog_options.hDC) { |
| 538 | DeleteDC(dialog_options.hDC); |
| 539 | } |
| 540 | } |
| 541 | |
| 542 | if (dialog_options.hDevMode != NULL) |
| 543 | GlobalFree(dialog_options.hDevMode); |
| 544 | if (dialog_options.hDevNames != NULL) |
| 545 | GlobalFree(dialog_options.hDevNames); |
| 546 | |
| 547 | switch (dialog_options.dwResultAction) { |
| 548 | case PD_RESULT_PRINT: |
[email protected] | b75dca8 | 2009-10-13 18:46:21 | [diff] [blame] | 549 | return context_ ? OK : FAILED; |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 550 | case PD_RESULT_APPLY: |
[email protected] | b75dca8 | 2009-10-13 18:46:21 | [diff] [blame] | 551 | return context_ ? CANCEL : FAILED; |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 552 | case PD_RESULT_CANCEL: |
| 553 | return CANCEL; |
| 554 | default: |
| 555 | return FAILED; |
| 556 | } |
| 557 | } |
| 558 | |
| 559 | PrintingContext::Result PrintingContext::ParseDialogResult( |
| 560 | const PRINTDLG& dialog_options) { |
| 561 | // If the user clicked OK or Apply then Cancel, but not only Cancel. |
| 562 | // Start fresh. |
| 563 | ResetSettings(); |
| 564 | |
| 565 | DEVMODE* dev_mode = NULL; |
| 566 | if (dialog_options.hDevMode) { |
| 567 | dev_mode = |
| 568 | reinterpret_cast<DEVMODE*>(GlobalLock(dialog_options.hDevMode)); |
| 569 | DCHECK(dev_mode); |
| 570 | } |
| 571 | |
| 572 | std::wstring device_name; |
| 573 | if (dialog_options.hDevNames) { |
| 574 | DEVNAMES* dev_names = |
| 575 | reinterpret_cast<DEVNAMES*>(GlobalLock(dialog_options.hDevNames)); |
| 576 | DCHECK(dev_names); |
| 577 | if (dev_names) { |
| 578 | device_name = |
| 579 | reinterpret_cast<const wchar_t*>( |
| 580 | reinterpret_cast<const wchar_t*>(dev_names) + |
| 581 | dev_names->wDeviceOffset); |
| 582 | GlobalUnlock(dialog_options.hDevNames); |
| 583 | } |
| 584 | } |
| 585 | |
| 586 | bool success = false; |
| 587 | if (dev_mode && !device_name.empty()) { |
[email protected] | b75dca8 | 2009-10-13 18:46:21 | [diff] [blame] | 588 | context_ = dialog_options.hDC; |
[email protected] | c8ad40c | 2009-06-08 17:05:21 | [diff] [blame] | 589 | success = InitializeSettings(*dev_mode, device_name, NULL, 0, false); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 590 | } |
| 591 | |
| 592 | if (!success && dialog_options.hDC) { |
| 593 | DeleteDC(dialog_options.hDC); |
[email protected] | b75dca8 | 2009-10-13 18:46:21 | [diff] [blame] | 594 | context_ = NULL; |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 595 | } |
| 596 | |
| 597 | if (dev_mode) { |
| 598 | GlobalUnlock(dialog_options.hDevMode); |
| 599 | } |
| 600 | |
| 601 | if (dialog_options.hDevMode != NULL) |
| 602 | GlobalFree(dialog_options.hDevMode); |
| 603 | if (dialog_options.hDevNames != NULL) |
| 604 | GlobalFree(dialog_options.hDevNames); |
| 605 | |
[email protected] | b75dca8 | 2009-10-13 18:46:21 | [diff] [blame] | 606 | return context_ ? OK : FAILED; |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 607 | } |
| 608 | |
[email protected] | d825462 | 2010-08-13 19:15:46 | [diff] [blame] | 609 | // static |
| 610 | void PrintingContext::GetPrinterHelper(HANDLE printer, int level, |
| 611 | scoped_array<uint8>* buffer) { |
| 612 | DWORD buf_size = 0; |
| 613 | GetPrinter(printer, level, NULL, 0, &buf_size); |
| 614 | if (buf_size) { |
| 615 | buffer->reset(new uint8[buf_size]); |
| 616 | memset(buffer->get(), 0, buf_size); |
| 617 | if (!GetPrinter(printer, level, buffer->get(), buf_size, &buf_size)) { |
| 618 | buffer->reset(); |
| 619 | } |
| 620 | } |
| 621 | } |
| 622 | |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 623 | } // namespace printing |