Avi Drissman | db497b3 | 2022-09-15 19:47:28 | [diff] [blame] | 1 | // Copyright 2012 The Chromium Authors |
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] | 51e8d935 | 2010-10-06 22:21:17 | [diff] [blame] | 5 | #include "printing/printing_context_win.h" |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 6 | |
Lei Zhang | 151b1b9 | 2019-05-24 20:48:30 | [diff] [blame] | 7 | #include <winspool.h> |
| 8 | |
[email protected] | 19f09a6 | 2011-05-04 23:37:47 | [diff] [blame] | 9 | #include <algorithm> |
Vladislav Kuzkokov | 1999822 | 2019-08-12 14:26:09 | [diff] [blame] | 10 | #include <utility> |
thestig | b50a0c33 | 2016-09-30 04:22:45 | [diff] [blame] | 11 | #include <vector> |
[email protected] | 19f09a6 | 2011-05-04 23:37:47 | [diff] [blame] | 12 | |
vitalybuka | 12b8758 | 2014-12-08 18:57:10 | [diff] [blame] | 13 | #include "base/bind.h" |
Alan Screen | e9ed54a | 2021-11-24 18:22:46 | [diff] [blame] | 14 | #include "base/check.h" |
Alan Screen | 4e284e9cb | 2021-12-04 00:38:29 | [diff] [blame] | 15 | #include "base/check_op.h" |
dcheng | db5935f | 2016-03-26 00:16:27 | [diff] [blame] | 16 | #include "base/memory/free_deleter.h" |
[email protected] | ad3b0501 | 2014-06-16 23:02:15 | [diff] [blame] | 17 | #include "base/strings/string_number_conversions.h" |
[email protected] | 90626587 | 2013-06-07 22:40:45 | [diff] [blame] | 18 | #include "base/strings/utf_string_conversions.h" |
Carlos Caballero | b25fe847 | 2020-07-17 10:27:17 | [diff] [blame] | 19 | #include "base/task/current_thread.h" |
[email protected] | 09083eb | 2012-09-20 05:58:43 | [diff] [blame] | 20 | #include "printing/backend/print_backend.h" |
[email protected] | 55e8e9f | 2012-03-02 22:50:54 | [diff] [blame] | 21 | #include "printing/backend/win_helper.h" |
Scott Violet | 318a55f | 2018-03-30 19:08:19 | [diff] [blame] | 22 | #include "printing/buildflags/buildflags.h" |
Alan Screen | 4e284e9cb | 2021-12-04 00:38:29 | [diff] [blame] | 23 | #include "printing/metafile.h" |
Alan Screen | 13ec987ca | 2019-12-10 19:23:07 | [diff] [blame] | 24 | #include "printing/metafile_skia.h" |
Julie Jeongeun Kim | e454f260 | 2020-04-30 05:20:07 | [diff] [blame] | 25 | #include "printing/mojom/print.mojom.h" |
Alan Screen | 4e284e9cb | 2021-12-04 00:38:29 | [diff] [blame] | 26 | #include "printing/page_setup.h" |
[email protected] | 4993f34 | 2010-10-26 17:57:52 | [diff] [blame] | 27 | #include "printing/print_settings_initializer_win.h" |
[email protected] | 8ff1d42 | 2009-07-07 21:31:39 | [diff] [blame] | 28 | #include "printing/printed_document.h" |
Alan Screen | 4e284e9cb | 2021-12-04 00:38:29 | [diff] [blame] | 29 | #include "printing/printed_page_win.h" |
vitalybuka | f9d0c0c | 2014-09-09 19:53:33 | [diff] [blame] | 30 | #include "printing/printing_context_system_dialog_win.h" |
Alan Screen | 113d014 | 2020-01-31 06:11:21 | [diff] [blame] | 31 | #include "printing/printing_features.h" |
[email protected] | ec91bfa | 2013-11-09 17:24:27 | [diff] [blame] | 32 | #include "printing/printing_utils.h" |
[email protected] | e5636a5 | 2011-09-28 21:44:42 | [diff] [blame] | 33 | #include "printing/units.h" |
tomhudson | 828dddb | 2015-12-04 14:34:16 | [diff] [blame] | 34 | #include "skia/ext/skia_utils_win.h" |
[email protected] | 6b7bfd2 | 2013-05-28 23:55:15 | [diff] [blame] | 35 | #include "ui/aura/window.h" |
samli | 6d8217f | 2016-01-20 04:12:20 | [diff] [blame] | 36 | #include "ui/aura/window_tree_host.h" |
[email protected] | 6b7bfd2 | 2013-05-28 23:55:15 | [diff] [blame] | 37 | |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 38 | namespace printing { |
| 39 | |
vitalybuka | 12b8758 | 2014-12-08 18:57:10 | [diff] [blame] | 40 | namespace { |
| 41 | |
Alan Screen | 4e284e9cb | 2021-12-04 00:38:29 | [diff] [blame] | 42 | // Helper class to ensure that a saved device context state gets restored at end |
| 43 | // of scope. |
| 44 | class ScopedSavedState { |
| 45 | public: |
| 46 | ScopedSavedState(HDC context) |
| 47 | : context_(context), saved_state_(SaveDC(context)) { |
| 48 | DCHECK_NE(saved_state_, 0); |
| 49 | } |
| 50 | ~ScopedSavedState() { |
| 51 | BOOL res = RestoreDC(context_, saved_state_); |
| 52 | DCHECK_NE(res, 0); |
| 53 | } |
| 54 | |
| 55 | private: |
| 56 | HDC context_; |
| 57 | int saved_state_; |
| 58 | }; |
| 59 | |
Alan Screen | 202e49a | 2021-09-21 06:34:28 | [diff] [blame] | 60 | void AssignResult(mojom::ResultCode* out, mojom::ResultCode in) { |
vitalybuka | 12b8758 | 2014-12-08 18:57:10 | [diff] [blame] | 61 | *out = in; |
| 62 | } |
| 63 | |
Alan Screen | 4e284e9cb | 2021-12-04 00:38:29 | [diff] [blame] | 64 | void SimpleModifyWorldTransform(HDC context, |
| 65 | int offset_x, |
| 66 | int offset_y, |
| 67 | float shrink_factor) { |
| 68 | XFORM xform = {0}; |
| 69 | xform.eDx = static_cast<float>(offset_x); |
| 70 | xform.eDy = static_cast<float>(offset_y); |
| 71 | xform.eM11 = xform.eM22 = 1.f / shrink_factor; |
| 72 | BOOL res = ModifyWorldTransform(context, &xform, MWT_LEFTMULTIPLY); |
| 73 | DCHECK_NE(res, 0); |
| 74 | } |
| 75 | |
vitalybuka | 12b8758 | 2014-12-08 18:57:10 | [diff] [blame] | 76 | } // namespace |
| 77 | |
[email protected] | 51e8d935 | 2010-10-06 22:21:17 | [diff] [blame] | 78 | // static |
Alan Screen | f2fbeb7a | 2021-08-28 05:27:38 | [diff] [blame] | 79 | std::unique_ptr<PrintingContext> PrintingContext::CreateImpl( |
Alan Screen | e9ed54a | 2021-11-24 18:22:46 | [diff] [blame] | 80 | Delegate* delegate, |
| 81 | bool skip_system_calls) { |
| 82 | std::unique_ptr<PrintingContext> context; |
Alan Screen | e9ed54a | 2021-11-24 18:22:46 | [diff] [blame] | 83 | context = std::make_unique<PrintingContextSystemDialogWin>(delegate); |
Alan Screen | e9ed54a | 2021-11-24 18:22:46 | [diff] [blame] | 84 | #if BUILDFLAG(ENABLE_OOP_PRINTING) |
| 85 | if (skip_system_calls) |
| 86 | context->set_skip_system_calls(); |
| 87 | #endif |
| 88 | return context; |
[email protected] | 51e8d935 | 2010-10-06 22:21:17 | [diff] [blame] | 89 | } |
| 90 | |
Vitaly Buka | bd7c981 | 2014-08-26 08:57:54 | [diff] [blame] | 91 | PrintingContextWin::PrintingContextWin(Delegate* delegate) |
thestig | b50a0c33 | 2016-09-30 04:22:45 | [diff] [blame] | 92 | : PrintingContext(delegate), context_(nullptr) {} |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 93 | |
[email protected] | 51e8d935 | 2010-10-06 22:21:17 | [diff] [blame] | 94 | PrintingContextWin::~PrintingContextWin() { |
| 95 | ReleaseContext(); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 96 | } |
| 97 | |
Vladislav Kuzkokov | 48ceab2 | 2018-02-14 16:29:28 | [diff] [blame] | 98 | void PrintingContextWin::AskUserForSettings(int max_pages, |
| 99 | bool has_selection, |
| 100 | bool is_scripted, |
| 101 | PrintSettingsCallback callback) { |
vitalybuka | 92ab8ce | 2014-08-26 23:41:45 | [diff] [blame] | 102 | NOTIMPLEMENTED(); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 103 | } |
| 104 | |
Alan Screen | 202e49a | 2021-09-21 06:34:28 | [diff] [blame] | 105 | mojom::ResultCode PrintingContextWin::UseDefaultSettings() { |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 106 | DCHECK(!in_print_job_); |
| 107 | |
Daniel Hosseinian | 733106e | 2019-12-05 21:23:58 | [diff] [blame] | 108 | scoped_refptr<PrintBackend> backend = |
Alan Screen | e714d4b | 2020-08-14 19:44:14 | [diff] [blame] | 109 | PrintBackend::CreateInstance(delegate_->GetAppLocale()); |
Alan Screen | 322ed618 | 2021-06-03 15:26:47 | [diff] [blame] | 110 | std::string default_printer_name; |
| 111 | mojom::ResultCode result = |
| 112 | backend->GetDefaultPrinterName(default_printer_name); |
| 113 | if (result != mojom::ResultCode::kSuccess) |
Alan Screen | 202e49a | 2021-09-21 06:34:28 | [diff] [blame] | 114 | return result; |
Alan Screen | 322ed618 | 2021-06-03 15:26:47 | [diff] [blame] | 115 | |
| 116 | std::wstring default_printer = base::UTF8ToWide(default_printer_name); |
vitalybuka | 92ab8ce | 2014-08-26 23:41:45 | [diff] [blame] | 117 | if (!default_printer.empty()) { |
| 118 | ScopedPrinterHandle printer; |
Lei Zhang | 151b1b9 | 2019-05-24 20:48:30 | [diff] [blame] | 119 | if (printer.OpenPrinterWithName(default_printer.c_str())) { |
dcheng | c3df9ba | 2016-04-07 23:09:32 | [diff] [blame] | 120 | std::unique_ptr<DEVMODE, base::FreeDeleter> dev_mode = |
thestig | b50a0c33 | 2016-09-30 04:22:45 | [diff] [blame] | 121 | CreateDevMode(printer.Get(), nullptr); |
Alan Screen | 202e49a | 2021-09-21 06:34:28 | [diff] [blame] | 122 | if (InitializeSettings(default_printer, dev_mode.get()) == |
| 123 | mojom::ResultCode::kSuccess) { |
| 124 | return mojom::ResultCode::kSuccess; |
| 125 | } |
vitalybuka | 92ab8ce | 2014-08-26 23:41:45 | [diff] [blame] | 126 | } |
| 127 | } |
| 128 | |
| 129 | ReleaseContext(); |
[email protected] | ff3ccc2 | 2011-04-18 21:35:48 | [diff] [blame] | 130 | |
| 131 | // No default printer configured, do we have any printers at all? |
| 132 | DWORD bytes_needed = 0; |
| 133 | DWORD count_returned = 0; |
thestig | b50a0c33 | 2016-09-30 04:22:45 | [diff] [blame] | 134 | (void)::EnumPrinters(PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS, nullptr, |
| 135 | 2, nullptr, 0, &bytes_needed, &count_returned); |
[email protected] | ff3ccc2 | 2011-04-18 21:35:48 | [diff] [blame] | 136 | if (bytes_needed) { |
[email protected] | 1b24888 | 2014-02-25 04:39:14 | [diff] [blame] | 137 | DCHECK_GE(bytes_needed, count_returned * sizeof(PRINTER_INFO_2)); |
thestig | b50a0c33 | 2016-09-30 04:22:45 | [diff] [blame] | 138 | std::vector<BYTE> printer_info_buffer(bytes_needed); |
| 139 | BOOL ret = ::EnumPrinters(PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS, |
| 140 | nullptr, 2, printer_info_buffer.data(), |
| 141 | bytes_needed, &bytes_needed, &count_returned); |
[email protected] | ff3ccc2 | 2011-04-18 21:35:48 | [diff] [blame] | 142 | if (ret && count_returned) { // have printers |
| 143 | // Open the first successfully found printer. |
[email protected] | 1b24888 | 2014-02-25 04:39:14 | [diff] [blame] | 144 | const PRINTER_INFO_2* info_2 = |
thestig | b50a0c33 | 2016-09-30 04:22:45 | [diff] [blame] | 145 | reinterpret_cast<PRINTER_INFO_2*>(printer_info_buffer.data()); |
[email protected] | 1b24888 | 2014-02-25 04:39:14 | [diff] [blame] | 146 | const PRINTER_INFO_2* info_2_end = info_2 + count_returned; |
| 147 | for (; info_2 < info_2_end; ++info_2) { |
| 148 | ScopedPrinterHandle printer; |
Jan Wilken Dörrie | 00632a1 | 2021-02-24 09:42:00 | [diff] [blame] | 149 | if (!printer.OpenPrinterWithName(info_2->pPrinterName)) |
[email protected] | ff3ccc2 | 2011-04-18 21:35:48 | [diff] [blame] | 150 | continue; |
dcheng | c3df9ba | 2016-04-07 23:09:32 | [diff] [blame] | 151 | std::unique_ptr<DEVMODE, base::FreeDeleter> dev_mode = |
thestig | b50a0c33 | 2016-09-30 04:22:45 | [diff] [blame] | 152 | CreateDevMode(printer.Get(), nullptr); |
Alan Screen | 202e49a | 2021-09-21 06:34:28 | [diff] [blame] | 153 | if (InitializeSettings(info_2->pPrinterName, dev_mode.get()) == |
| 154 | mojom::ResultCode::kSuccess) { |
| 155 | return mojom::ResultCode::kSuccess; |
| 156 | } |
[email protected] | ff3ccc2 | 2011-04-18 21:35:48 | [diff] [blame] | 157 | } |
| 158 | if (context_) |
Alan Screen | 202e49a | 2021-09-21 06:34:28 | [diff] [blame] | 159 | return mojom::ResultCode::kSuccess; |
[email protected] | ff3ccc2 | 2011-04-18 21:35:48 | [diff] [blame] | 160 | } |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 161 | } |
[email protected] | ff3ccc2 | 2011-04-18 21:35:48 | [diff] [blame] | 162 | |
vitalybuka | 92ab8ce | 2014-08-26 23:41:45 | [diff] [blame] | 163 | return OnError(); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 164 | } |
| 165 | |
[email protected] | 4c9054b | 2013-11-04 18:34:29 | [diff] [blame] | 166 | gfx::Size PrintingContextWin::GetPdfPaperSizeDeviceUnits() { |
| 167 | // Default fallback to Letter size. |
| 168 | gfx::SizeF paper_size(kLetterWidthInch, kLetterHeightInch); |
| 169 | |
| 170 | // Get settings from locale. Paper type buffer length is at most 4. |
| 171 | const int paper_type_buffer_len = 4; |
| 172 | wchar_t paper_type_buffer[paper_type_buffer_len] = {0}; |
| 173 | GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_IPAPERSIZE, paper_type_buffer, |
| 174 | paper_type_buffer_len); |
| 175 | if (wcslen(paper_type_buffer)) { // The call succeeded. |
| 176 | int paper_code = _wtoi(paper_type_buffer); |
| 177 | switch (paper_code) { |
| 178 | case DMPAPER_LEGAL: |
| 179 | paper_size.SetSize(kLegalWidthInch, kLegalHeightInch); |
| 180 | break; |
| 181 | case DMPAPER_A4: |
| 182 | paper_size.SetSize(kA4WidthInch, kA4HeightInch); |
| 183 | break; |
| 184 | case DMPAPER_A3: |
| 185 | paper_size.SetSize(kA3WidthInch, kA3HeightInch); |
| 186 | break; |
| 187 | default: // DMPAPER_LETTER is used for default fallback. |
| 188 | break; |
| 189 | } |
| 190 | } |
Vladislav Kuzkokov | 1999822 | 2019-08-12 14:26:09 | [diff] [blame] | 191 | return gfx::Size(paper_size.width() * settings_->device_units_per_inch(), |
| 192 | paper_size.height() * settings_->device_units_per_inch()); |
[email protected] | 4c9054b | 2013-11-04 18:34:29 | [diff] [blame] | 193 | } |
| 194 | |
Alan Screen | 202e49a | 2021-09-21 06:34:28 | [diff] [blame] | 195 | mojom::ResultCode PrintingContextWin::UpdatePrinterSettings( |
Lei Zhang | a3fdad44 | 2021-11-15 23:55:33 | [diff] [blame] | 196 | const PrinterSettings& printer_settings) { |
[email protected] | 7868ecab | 2011-03-05 00:12:53 | [diff] [blame] | 197 | DCHECK(!in_print_job_); |
| 198 | |
[email protected] | 55e8e9f | 2012-03-02 22:50:54 | [diff] [blame] | 199 | ScopedPrinterHandle printer; |
Jan Wilken Dörrie | 00632a1 | 2021-02-24 09:42:00 | [diff] [blame] | 200 | if (!printer.OpenPrinterWithName(base::as_wcstr(settings_->device_name()))) |
[email protected] | bd5baaf | 2011-04-21 20:48:33 | [diff] [blame] | 201 | return OnError(); |
[email protected] | afbdbf11 | 2011-03-28 22:09:37 | [diff] [blame] | 202 | |
[email protected] | 30aaa81a | 2011-05-03 21:08:39 | [diff] [blame] | 203 | // Make printer changes local to Chrome. |
| 204 | // See MSDN documentation regarding DocumentProperties. |
dcheng | c3df9ba | 2016-04-07 23:09:32 | [diff] [blame] | 205 | std::unique_ptr<DEVMODE, base::FreeDeleter> scoped_dev_mode = |
Jan Wilken Dörrie | 00632a1 | 2021-02-24 09:42:00 | [diff] [blame] | 206 | CreateDevModeWithColor(printer.Get(), |
| 207 | base::UTF16ToWide(settings_->device_name()), |
Alan Screen | 3fb63bf | 2020-08-19 00:11:23 | [diff] [blame] | 208 | settings_->color() != mojom::ColorModel::kGray); |
[email protected] | b3b6b6f | 2014-02-14 20:19:54 | [diff] [blame] | 209 | if (!scoped_dev_mode) |
[email protected] | bd5baaf | 2011-04-21 20:48:33 | [diff] [blame] | 210 | return OnError(); |
[email protected] | 7868ecab | 2011-03-05 00:12:53 | [diff] [blame] | 211 | |
[email protected] | b3b6b6f | 2014-02-14 20:19:54 | [diff] [blame] | 212 | { |
| 213 | DEVMODE* dev_mode = scoped_dev_mode.get(); |
Vladislav Kuzkokov | 1999822 | 2019-08-12 14:26:09 | [diff] [blame] | 214 | dev_mode->dmCopies = std::max(settings_->copies(), 1); |
[email protected] | 299e3d00 | 2014-06-03 08:46:49 | [diff] [blame] | 215 | if (dev_mode->dmCopies > 1) { // do not change unless multiple copies |
[email protected] | b3b6b6f | 2014-02-14 20:19:54 | [diff] [blame] | 216 | dev_mode->dmFields |= DM_COPIES; |
Lei Zhang | 01a1d3c0 | 2019-05-21 04:59:10 | [diff] [blame] | 217 | dev_mode->dmCollate = |
Vladislav Kuzkokov | 1999822 | 2019-08-12 14:26:09 | [diff] [blame] | 218 | settings_->collate() ? DMCOLLATE_TRUE : DMCOLLATE_FALSE; |
[email protected] | b3b6b6f | 2014-02-14 20:19:54 | [diff] [blame] | 219 | } |
[email protected] | f3256b0d8 | 2011-09-04 23:36:29 | [diff] [blame] | 220 | |
Vladislav Kuzkokov | 1999822 | 2019-08-12 14:26:09 | [diff] [blame] | 221 | switch (settings_->duplex_mode()) { |
Julie Jeongeun Kim | e454f260 | 2020-04-30 05:20:07 | [diff] [blame] | 222 | case mojom::DuplexMode::kLongEdge: |
[email protected] | b3b6b6f | 2014-02-14 20:19:54 | [diff] [blame] | 223 | dev_mode->dmFields |= DM_DUPLEX; |
| 224 | dev_mode->dmDuplex = DMDUP_VERTICAL; |
| 225 | break; |
Julie Jeongeun Kim | e454f260 | 2020-04-30 05:20:07 | [diff] [blame] | 226 | case mojom::DuplexMode::kShortEdge: |
[email protected] | b3b6b6f | 2014-02-14 20:19:54 | [diff] [blame] | 227 | dev_mode->dmFields |= DM_DUPLEX; |
| 228 | dev_mode->dmDuplex = DMDUP_HORIZONTAL; |
| 229 | break; |
Julie Jeongeun Kim | e454f260 | 2020-04-30 05:20:07 | [diff] [blame] | 230 | case mojom::DuplexMode::kSimplex: |
[email protected] | b3b6b6f | 2014-02-14 20:19:54 | [diff] [blame] | 231 | dev_mode->dmFields |= DM_DUPLEX; |
| 232 | dev_mode->dmDuplex = DMDUP_SIMPLEX; |
| 233 | break; |
Julie Jeongeun Kim | e454f260 | 2020-04-30 05:20:07 | [diff] [blame] | 234 | default: // kUnknownDuplexMode |
[email protected] | b3b6b6f | 2014-02-14 20:19:54 | [diff] [blame] | 235 | break; |
| 236 | } |
| 237 | |
| 238 | dev_mode->dmFields |= DM_ORIENTATION; |
Lei Zhang | 01a1d3c0 | 2019-05-21 04:59:10 | [diff] [blame] | 239 | dev_mode->dmOrientation = |
Vladislav Kuzkokov | 1999822 | 2019-08-12 14:26:09 | [diff] [blame] | 240 | settings_->landscape() ? DMORIENT_LANDSCAPE : DMORIENT_PORTRAIT; |
[email protected] | ad3b0501 | 2014-06-16 23:02:15 | [diff] [blame] | 241 | |
Vladislav Kuzkokov | 1999822 | 2019-08-12 14:26:09 | [diff] [blame] | 242 | if (settings_->dpi_horizontal() > 0) { |
| 243 | dev_mode->dmPrintQuality = settings_->dpi_horizontal(); |
rbpotter | 116c2e1 | 2017-04-04 19:21:28 | [diff] [blame] | 244 | dev_mode->dmFields |= DM_PRINTQUALITY; |
| 245 | } |
Vladislav Kuzkokov | 1999822 | 2019-08-12 14:26:09 | [diff] [blame] | 246 | if (settings_->dpi_vertical() > 0) { |
| 247 | dev_mode->dmYResolution = settings_->dpi_vertical(); |
rbpotter | 116c2e1 | 2017-04-04 19:21:28 | [diff] [blame] | 248 | dev_mode->dmFields |= DM_YRESOLUTION; |
| 249 | } |
| 250 | |
[email protected] | ad3b0501 | 2014-06-16 23:02:15 | [diff] [blame] | 251 | const PrintSettings::RequestedMedia& requested_media = |
Vladislav Kuzkokov | 1999822 | 2019-08-12 14:26:09 | [diff] [blame] | 252 | settings_->requested_media(); |
[email protected] | ad3b0501 | 2014-06-16 23:02:15 | [diff] [blame] | 253 | unsigned id = 0; |
rbpotter | 1142f50 | 2017-09-29 18:09:19 | [diff] [blame] | 254 | // If the paper size is a custom user size, setting by ID may not work. |
| 255 | if (base::StringToUint(requested_media.vendor_id, &id) && id && |
| 256 | id < DMPAPER_USER) { |
[email protected] | ad3b0501 | 2014-06-16 23:02:15 | [diff] [blame] | 257 | dev_mode->dmFields |= DM_PAPERSIZE; |
| 258 | dev_mode->dmPaperSize = static_cast<short>(id); |
Lei Zhang | 9a9fe64 | 2017-10-03 22:07:24 | [diff] [blame] | 259 | } else if (!requested_media.size_microns.IsEmpty()) { |
| 260 | static constexpr int kFromUm = 100; // Windows uses 0.1mm. |
| 261 | dev_mode->dmFields |= DM_PAPERWIDTH | DM_PAPERLENGTH; |
| 262 | dev_mode->dmPaperWidth = requested_media.size_microns.width() / kFromUm; |
| 263 | dev_mode->dmPaperLength = requested_media.size_microns.height() / kFromUm; |
[email protected] | ad3b0501 | 2014-06-16 23:02:15 | [diff] [blame] | 264 | } |
[email protected] | e5324b5 | 2013-10-29 03:16:37 | [diff] [blame] | 265 | } |
[email protected] | bd5baaf | 2011-04-21 20:48:33 | [diff] [blame] | 266 | |
[email protected] | 30aaa81a | 2011-05-03 21:08:39 | [diff] [blame] | 267 | // Update data using DocumentProperties. |
Lei Zhang | a3fdad44 | 2021-11-15 23:55:33 | [diff] [blame] | 268 | if (printer_settings.show_system_dialog) { |
Alan Screen | 202e49a | 2021-09-21 06:34:28 | [diff] [blame] | 269 | mojom::ResultCode result = mojom::ResultCode::kFailed; |
Lei Zhang | a3fdad44 | 2021-11-15 23:55:33 | [diff] [blame] | 270 | AskUserForSettings(printer_settings.page_count, /*has_selection=*/false, |
| 271 | /*is_scripted=*/false, |
tzik | ea7713cd | 2018-03-09 09:39:09 | [diff] [blame] | 272 | base::BindOnce(&AssignResult, &result)); |
vitalybuka | 12b8758 | 2014-12-08 18:57:10 | [diff] [blame] | 273 | return result; |
[email protected] | bd5baaf | 2011-04-21 20:48:33 | [diff] [blame] | 274 | } |
vitalybuka | 92ab8ce | 2014-08-26 23:41:45 | [diff] [blame] | 275 | // Set printer then refresh printer settings. |
thestig | e85e6b6 | 2016-08-25 00:00:06 | [diff] [blame] | 276 | scoped_dev_mode = CreateDevMode(printer.Get(), scoped_dev_mode.get()); |
Alan Screen | 830ededb | 2020-03-18 17:59:15 | [diff] [blame] | 277 | if (!scoped_dev_mode) |
| 278 | return OnError(); |
| 279 | |
| 280 | // Since CreateDevMode() doesn't honor color settings through the GDI call |
| 281 | // to DocumentProperties(), ensure the requested values persist here. |
| 282 | scoped_dev_mode->dmFields |= DM_COLOR; |
Alan Screen | 3fb63bf | 2020-08-19 00:11:23 | [diff] [blame] | 283 | scoped_dev_mode->dmColor = settings_->color() != mojom::ColorModel::kGray |
| 284 | ? DMCOLOR_COLOR |
| 285 | : DMCOLOR_MONOCHROME; |
Alan Screen | 830ededb | 2020-03-18 17:59:15 | [diff] [blame] | 286 | |
Jan Wilken Dörrie | 00632a1 | 2021-02-24 09:42:00 | [diff] [blame] | 287 | return InitializeSettings(base::UTF16ToWide(settings_->device_name()), |
| 288 | scoped_dev_mode.get()); |
[email protected] | 7868ecab | 2011-03-05 00:12:53 | [diff] [blame] | 289 | } |
| 290 | |
Alan Screen | 202e49a | 2021-09-21 06:34:28 | [diff] [blame] | 291 | mojom::ResultCode PrintingContextWin::InitWithSettingsForTest( |
Vladislav Kuzkokov | 1999822 | 2019-08-12 14:26:09 | [diff] [blame] | 292 | std::unique_ptr<PrintSettings> settings) { |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 293 | DCHECK(!in_print_job_); |
[email protected] | 4993f34 | 2010-10-26 17:57:52 | [diff] [blame] | 294 | |
Vladislav Kuzkokov | 1999822 | 2019-08-12 14:26:09 | [diff] [blame] | 295 | settings_ = std::move(settings); |
[email protected] | 4993f34 | 2010-10-26 17:57:52 | [diff] [blame] | 296 | |
| 297 | // TODO(maruel): settings_.ToDEVMODE() |
[email protected] | 55e8e9f | 2012-03-02 22:50:54 | [diff] [blame] | 298 | ScopedPrinterHandle printer; |
Alan Screen | 39279cf0 | 2021-09-22 07:16:41 | [diff] [blame] | 299 | if (!printer.OpenPrinterWithName(base::as_wcstr(settings_->device_name()))) { |
| 300 | return logging::GetLastSystemErrorCode() == ERROR_ACCESS_DENIED |
| 301 | ? mojom::ResultCode::kAccessDenied |
| 302 | : mojom::ResultCode::kFailed; |
| 303 | } |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 304 | |
dcheng | c3df9ba | 2016-04-07 23:09:32 | [diff] [blame] | 305 | std::unique_ptr<DEVMODE, base::FreeDeleter> dev_mode = |
thestig | b50a0c33 | 2016-09-30 04:22:45 | [diff] [blame] | 306 | CreateDevMode(printer.Get(), nullptr); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 307 | |
Jan Wilken Dörrie | 00632a1 | 2021-02-24 09:42:00 | [diff] [blame] | 308 | return InitializeSettings(base::UTF16ToWide(settings_->device_name()), |
| 309 | dev_mode.get()); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 310 | } |
| 311 | |
Alan Screen | 202e49a | 2021-09-21 06:34:28 | [diff] [blame] | 312 | mojom::ResultCode PrintingContextWin::NewDocument( |
Jan Wilken Dörrie | 739ccc21 | 2021-03-11 18:13:05 | [diff] [blame] | 313 | const std::u16string& document_name) { |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 314 | DCHECK(!in_print_job_); |
Alan Screen | e9ed54a | 2021-11-24 18:22:46 | [diff] [blame] | 315 | if (!context_ && !skip_system_calls()) |
[email protected] | c8ad40c | 2009-06-08 17:05:21 | [diff] [blame] | 316 | return OnError(); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 317 | |
| 318 | // Set the flag used by the AbortPrintJob dialog procedure. |
| 319 | abort_printing_ = false; |
| 320 | |
| 321 | in_print_job_ = true; |
| 322 | |
Alan Screen | e9ed54a | 2021-11-24 18:22:46 | [diff] [blame] | 323 | if (skip_system_calls()) |
| 324 | return mojom::ResultCode::kSuccess; |
| 325 | |
Alan Screen | 202e49a | 2021-09-21 06:34:28 | [diff] [blame] | 326 | if (base::FeatureList::IsEnabled(printing::features::kUseXpsForPrinting)) { |
| 327 | // This is all the new document context needed when using XPS. |
| 328 | return mojom::ResultCode::kSuccess; |
| 329 | } |
Alan Screen | 13ec987ca | 2019-12-10 19:23:07 | [diff] [blame] | 330 | |
| 331 | // Need more context setup when using GDI. |
| 332 | |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 333 | // Register the application's AbortProc function with GDI. |
[email protected] | b75dca8 | 2009-10-13 18:46:21 | [diff] [blame] | 334 | if (SP_ERROR == SetAbortProc(context_, &AbortProc)) |
[email protected] | c8ad40c | 2009-06-08 17:05:21 | [diff] [blame] | 335 | return OnError(); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 336 | |
[email protected] | ec91bfa | 2013-11-09 17:24:27 | [diff] [blame] | 337 | DCHECK(SimplifyDocumentTitle(document_name) == document_name); |
Lei Zhang | 01a1d3c0 | 2019-05-21 04:59:10 | [diff] [blame] | 338 | DOCINFO di = {sizeof(DOCINFO)}; |
Peter Kasting | 3c73bbc | 2021-02-02 13:01:34 | [diff] [blame] | 339 | di.lpszDocName = base::as_wcstr(document_name); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 340 | |
| 341 | // Is there a debug dump directory specified? If so, force to print to a file. |
Lei Zhang | bdd6381 | 2017-12-12 06:29:51 | [diff] [blame] | 342 | if (PrintedDocument::HasDebugDumpPath()) { |
| 343 | base::FilePath debug_dump_path = PrintedDocument::CreateDebugDumpPath( |
| 344 | document_name, FILE_PATH_LITERAL(".prn")); |
| 345 | if (!debug_dump_path.empty()) |
| 346 | di.lpszOutput = debug_dump_path.value().c_str(); |
| 347 | } |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 348 | |
[email protected] | daee497 | 2009-07-09 14:28:24 | [diff] [blame] | 349 | // No message loop running in unit tests. |
Carlos Caballero | b25fe847 | 2020-07-17 10:27:17 | [diff] [blame] | 350 | DCHECK(!base::CurrentThread::Get() || |
| 351 | !base::CurrentThread::Get()->NestableTasksAllowed()); |
[email protected] | daee497 | 2009-07-09 14:28:24 | [diff] [blame] | 352 | |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 353 | // Begin a print job by calling the StartDoc function. |
| 354 | // NOTE: StartDoc() starts a message loop. That causes a lot of problems with |
| 355 | // IPC. Make sure recursive task processing is disabled. |
[email protected] | b75dca8 | 2009-10-13 18:46:21 | [diff] [blame] | 356 | if (StartDoc(context_, &di) <= 0) |
[email protected] | c8ad40c | 2009-06-08 17:05:21 | [diff] [blame] | 357 | return OnError(); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 358 | |
Alan Screen | 202e49a | 2021-09-21 06:34:28 | [diff] [blame] | 359 | return mojom::ResultCode::kSuccess; |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 360 | } |
| 361 | |
Alan Screen | 4e284e9cb | 2021-12-04 00:38:29 | [diff] [blame] | 362 | mojom::ResultCode PrintingContextWin::RenderPage(const PrintedPage& page, |
| 363 | const PageSetup& page_setup) { |
| 364 | if (abort_printing_) |
| 365 | return mojom::ResultCode::kCanceled; |
| 366 | DCHECK(context_); |
| 367 | DCHECK(in_print_job_); |
| 368 | |
| 369 | gfx::Rect content_area = GetCenteredPageContentRect( |
| 370 | page_setup.physical_size(), page.page_size(), page.page_content_rect()); |
| 371 | |
| 372 | // Save the state to make sure the context this function call does not modify |
| 373 | // the device context. |
| 374 | ScopedSavedState saved_state(context_); |
| 375 | skia::InitializeDC(context_); |
| 376 | { |
| 377 | // Save the state (again) to apply the necessary world transformation. |
| 378 | ScopedSavedState saved_state_inner(context_); |
| 379 | |
| 380 | // Setup the matrix to translate and scale to the right place. Take in |
| 381 | // account the actual shrinking factor. |
| 382 | // Note that the printing output is relative to printable area of the page. |
| 383 | // That is 0,0 is offset by PHYSICALOFFSETX/Y from the page. |
| 384 | SimpleModifyWorldTransform( |
| 385 | context_, content_area.x() - page_setup.printable_area().x(), |
| 386 | content_area.y() - page_setup.printable_area().y(), |
| 387 | page.shrink_factor()); |
| 388 | |
| 389 | if (::StartPage(context_) <= 0) |
| 390 | return mojom::ResultCode::kFailed; |
| 391 | bool played_back = page.metafile()->SafePlayback(context_); |
| 392 | DCHECK(played_back); |
| 393 | if (::EndPage(context_) <= 0) |
| 394 | return mojom::ResultCode::kFailed; |
| 395 | } |
| 396 | |
| 397 | return mojom::ResultCode::kSuccess; |
| 398 | } |
| 399 | |
Alan Screen | 4e284e9cb | 2021-12-04 00:38:29 | [diff] [blame] | 400 | mojom::ResultCode PrintingContextWin::PrintDocument( |
| 401 | const MetafilePlayer& metafile, |
| 402 | const PrintSettings& settings, |
| 403 | uint32_t num_pages) { |
| 404 | // TODO(crbug.com/1008222) |
| 405 | NOTIMPLEMENTED(); |
| 406 | return mojom::ResultCode::kFailed; |
| 407 | } |
| 408 | |
Alan Screen | 202e49a | 2021-09-21 06:34:28 | [diff] [blame] | 409 | mojom::ResultCode PrintingContextWin::DocumentDone() { |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 410 | if (abort_printing_) |
Alan Screen | 202e49a | 2021-09-21 06:34:28 | [diff] [blame] | 411 | return mojom::ResultCode::kCanceled; |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 412 | DCHECK(in_print_job_); |
[email protected] | 6074541 | 2010-09-27 23:46:07 | [diff] [blame] | 413 | DCHECK(context_); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 414 | |
| 415 | // Inform the driver that document has ended. |
[email protected] | b75dca8 | 2009-10-13 18:46:21 | [diff] [blame] | 416 | if (EndDoc(context_) <= 0) |
[email protected] | c8ad40c | 2009-06-08 17:05:21 | [diff] [blame] | 417 | return OnError(); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 418 | |
Vladislav Kuzkokov | 56e6bbbd | 2019-08-21 18:48:18 | [diff] [blame] | 419 | ResetSettings(); |
Alan Screen | 202e49a | 2021-09-21 06:34:28 | [diff] [blame] | 420 | return mojom::ResultCode::kSuccess; |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 421 | } |
| 422 | |
[email protected] | 51e8d935 | 2010-10-06 22:21:17 | [diff] [blame] | 423 | void PrintingContextWin::Cancel() { |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 424 | abort_printing_ = true; |
| 425 | in_print_job_ = false; |
[email protected] | b75dca8 | 2009-10-13 18:46:21 | [diff] [blame] | 426 | if (context_) |
| 427 | CancelDC(context_); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 428 | } |
| 429 | |
[email protected] | 51e8d935 | 2010-10-06 22:21:17 | [diff] [blame] | 430 | void PrintingContextWin::ReleaseContext() { |
| 431 | if (context_) { |
| 432 | DeleteDC(context_); |
thestig | b50a0c33 | 2016-09-30 04:22:45 | [diff] [blame] | 433 | context_ = nullptr; |
[email protected] | 51e8d935 | 2010-10-06 22:21:17 | [diff] [blame] | 434 | } |
| 435 | } |
| 436 | |
Nico Weber | 8e55956 | 2017-10-03 01:25:26 | [diff] [blame] | 437 | printing::NativeDrawingContext PrintingContextWin::context() const { |
[email protected] | 51e8d935 | 2010-10-06 22:21:17 | [diff] [blame] | 438 | return context_; |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 439 | } |
| 440 | |
| 441 | // static |
[email protected] | 51e8d935 | 2010-10-06 22:21:17 | [diff] [blame] | 442 | BOOL PrintingContextWin::AbortProc(HDC hdc, int nCode) { |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 443 | if (nCode) { |
| 444 | // TODO(maruel): Need a way to find the right instance to set. Should |
| 445 | // leverage PrintJobManager here? |
| 446 | // abort_printing_ = true; |
| 447 | } |
| 448 | return true; |
| 449 | } |
| 450 | |
Alan Screen | 202e49a | 2021-09-21 06:34:28 | [diff] [blame] | 451 | mojom::ResultCode PrintingContextWin::InitializeSettings( |
Jan Wilken Dörrie | 00632a1 | 2021-02-24 09:42:00 | [diff] [blame] | 452 | const std::wstring& device_name, |
vitalybuka | 92ab8ce | 2014-08-26 23:41:45 | [diff] [blame] | 453 | DEVMODE* dev_mode) { |
| 454 | if (!dev_mode) |
| 455 | return OnError(); |
| 456 | |
| 457 | ReleaseContext(); |
Jan Wilken Dörrie | 00632a1 | 2021-02-24 09:42:00 | [diff] [blame] | 458 | context_ = CreateDC(L"WINSPOOL", device_name.c_str(), nullptr, dev_mode); |
vitalybuka | 92ab8ce | 2014-08-26 23:41:45 | [diff] [blame] | 459 | if (!context_) |
| 460 | return OnError(); |
| 461 | |
[email protected] | 62f2e80 | 2011-05-26 14:28:35 | [diff] [blame] | 462 | skia::InitializeDC(context_); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 463 | |
| 464 | DCHECK(!in_print_job_); |
Jan Wilken Dörrie | 00632a1 | 2021-02-24 09:42:00 | [diff] [blame] | 465 | settings_->set_device_name(base::WideToUTF16(device_name)); |
Lei Zhang | 01a1d3c0 | 2019-05-21 04:59:10 | [diff] [blame] | 466 | PrintSettingsInitializerWin::InitPrintSettings(context_, *dev_mode, |
Vladislav Kuzkokov | 1999822 | 2019-08-12 14:26:09 | [diff] [blame] | 467 | settings_.get()); |
[email protected] | 4993f34 | 2010-10-26 17:57:52 | [diff] [blame] | 468 | |
Alan Screen | 202e49a | 2021-09-21 06:34:28 | [diff] [blame] | 469 | return mojom::ResultCode::kSuccess; |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 470 | } |
| 471 | |
Alan Screen | 39279cf0 | 2021-09-22 07:16:41 | [diff] [blame] | 472 | mojom::ResultCode PrintingContextWin::OnError() { |
| 473 | mojom::ResultCode result; |
| 474 | if (abort_printing_) { |
| 475 | result = mojom::ResultCode::kCanceled; |
| 476 | } else { |
| 477 | result = logging::GetLastSystemErrorCode() == ERROR_ACCESS_DENIED |
| 478 | ? mojom::ResultCode::kAccessDenied |
| 479 | : mojom::ResultCode::kFailed; |
| 480 | } |
| 481 | ResetSettings(); |
| 482 | return result; |
| 483 | } |
| 484 | |
vitalybuka | f9d0c0c | 2014-09-09 19:53:33 | [diff] [blame] | 485 | HWND PrintingContextWin::GetRootWindow(gfx::NativeView view) { |
thestig | b50a0c33 | 2016-09-30 04:22:45 | [diff] [blame] | 486 | HWND window = nullptr; |
vitalybuka | a58ec6a | 2015-02-23 18:30:49 | [diff] [blame] | 487 | if (view && view->GetHost()) |
vitalybuka | f9d0c0c | 2014-09-09 19:53:33 | [diff] [blame] | 488 | window = view->GetHost()->GetAcceleratedWidget(); |
vitalybuka | f9d0c0c | 2014-09-09 19:53:33 | [diff] [blame] | 489 | if (!window) { |
thestig | b50a0c33 | 2016-09-30 04:22:45 | [diff] [blame] | 490 | // TODO(maruel): b/1214347 Get the right browser window instead. |
vitalybuka | f9d0c0c | 2014-09-09 19:53:33 | [diff] [blame] | 491 | return GetDesktopWindow(); |
| 492 | } |
| 493 | return window; |
| 494 | } |
| 495 | |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 496 | } // namespace printing |