Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "printing/backend/print_backend.h" | 5 #include "printing/backend/print_backend.h" |
| 6 | 6 |
| 7 #include <objidl.h> | 7 #include <objidl.h> |
| 8 #include <winspool.h> | 8 #include <winspool.h> |
| 9 | 9 |
| 10 #include "base/memory/scoped_ptr.h" | 10 #include "base/memory/scoped_ptr.h" |
| 11 #include "base/strings/string_piece.h" | 11 #include "base/strings/string_piece.h" |
| 12 #include "base/strings/utf_string_conversions.h" | 12 #include "base/strings/utf_string_conversions.h" |
| 13 #include "base/win/scoped_bstr.h" | 13 #include "base/win/scoped_bstr.h" |
| 14 #include "base/win/scoped_comptr.h" | 14 #include "base/win/scoped_comptr.h" |
| 15 #include "base/win/scoped_hglobal.h" | 15 #include "base/win/scoped_hglobal.h" |
| 16 #include "printing/backend/print_backend_consts.h" | 16 #include "printing/backend/print_backend_consts.h" |
| 17 #include "printing/backend/printing_info_win.h" | 17 #include "printing/backend/printing_info_win.h" |
| 18 #include "printing/backend/win_helper.h" | 18 #include "printing/backend/win_helper.h" |
| 19 | 19 |
| 20 namespace printing { | |
| 20 | 21 |
| 21 namespace { | 22 namespace { |
| 22 | 23 |
| 23 HRESULT StreamOnHGlobalToString(IStream* stream, std::string* out) { | 24 HRESULT StreamOnHGlobalToString(IStream* stream, std::string* out) { |
| 24 DCHECK(stream); | 25 DCHECK(stream); |
| 25 DCHECK(out); | 26 DCHECK(out); |
| 26 HGLOBAL hdata = NULL; | 27 HGLOBAL hdata = NULL; |
| 27 HRESULT hr = GetHGlobalFromStream(stream, &hdata); | 28 HRESULT hr = GetHGlobalFromStream(stream, &hdata); |
| 28 if (SUCCEEDED(hr)) { | 29 if (SUCCEEDED(hr)) { |
| 29 DCHECK(hdata); | 30 DCHECK(hdata); |
| 30 base::win::ScopedHGlobal<char> locked_data(hdata); | 31 base::win::ScopedHGlobal<char> locked_data(hdata); |
| 31 out->assign(locked_data.release(), locked_data.Size()); | 32 out->assign(locked_data.release(), locked_data.Size()); |
| 32 } | 33 } |
| 33 return hr; | 34 return hr; |
| 34 } | 35 } |
| 35 | 36 |
| 37 template <class T> | |
| 38 void GetDeviceCapabilityArray(const wchar_t* printer, | |
| 39 const wchar_t* port, | |
| 40 WORD id, | |
| 41 std::vector<T>* result) { | |
| 42 int count = DeviceCapabilities(printer, port, id, NULL, NULL); | |
| 43 if (count <= 0) | |
| 44 return; | |
| 45 result->resize(count); | |
| 46 CHECK_EQ(count, | |
| 47 DeviceCapabilities(printer, port, id, | |
|
Noam Samuel
2014/02/04 18:33:22
Misaligned.
Vitaly Buka (NO REVIEWS)
2014/02/04 18:48:24
Done.
| |
| 48 reinterpret_cast<LPTSTR>(result->data()), NULL)); | |
| 49 } | |
| 50 | |
| 51 void LoadPaper(const wchar_t* printer, | |
| 52 const wchar_t* port, | |
| 53 const DEVMODE* devmode, | |
| 54 PrinterSemanticCapsAndDefaults* caps) { | |
| 55 static const size_t kToUm = 100; | |
| 56 static const size_t kMaxPaperName = 64; | |
| 57 | |
| 58 short default_id = 0; | |
| 59 gfx::Size default_size; | |
| 60 | |
| 61 if (devmode) { | |
| 62 if ((devmode->dmFields & DM_PAPERSIZE) == DM_PAPERSIZE) | |
| 63 default_id = devmode->dmPaperSize; | |
| 64 if ((devmode->dmFields & DM_PAPERWIDTH) == DM_PAPERWIDTH) | |
| 65 default_size.set_width(devmode->dmPaperWidth * kToUm); | |
| 66 if ((devmode->dmFields & DM_PAPERLENGTH) == DM_PAPERLENGTH) | |
| 67 default_size.set_height(devmode->dmPaperLength * kToUm); | |
| 68 } | |
| 69 | |
| 70 struct PaperName { | |
| 71 wchar_t chars[kMaxPaperName]; | |
| 72 }; | |
| 73 | |
| 74 // Paper | |
| 75 std::vector<PaperName> names; | |
| 76 GetDeviceCapabilityArray(printer, port, DC_PAPERNAMES, &names); | |
| 77 | |
| 78 std::vector<POINT> sizes; | |
| 79 GetDeviceCapabilityArray(printer, port, DC_PAPERSIZE, &sizes); | |
| 80 | |
| 81 std::vector<WORD> ids; | |
| 82 GetDeviceCapabilityArray(printer, port, DC_PAPERS, &ids); | |
| 83 | |
| 84 DCHECK_EQ(ids.size(), sizes.size()); | |
| 85 DCHECK_EQ(names.size(), sizes.size()); | |
| 86 | |
| 87 if (ids.size() != sizes.size()) | |
| 88 ids.clear(); | |
| 89 if (names.size() != sizes.size()) | |
| 90 names.clear(); | |
| 91 | |
| 92 for (size_t i = 0; i < sizes.size(); ++i) { | |
| 93 PrinterSemanticCapsAndDefaults::Paper paper; | |
| 94 paper.size_um.SetSize(sizes[i].x * kToUm, sizes[i].y * kToUm); | |
| 95 if (!names.empty()) { | |
| 96 paper.name.assign(&names[i].chars, &names[i].chars + kMaxPaperName); | |
| 97 // Trim trailing zeros. | |
| 98 paper.name = paper.name.c_str(); | |
| 99 } | |
| 100 if (caps->default_paper < 0) { | |
| 101 if (!default_size.IsEmpty()) { | |
| 102 if (default_size == paper.size_um) | |
| 103 caps->default_paper = i; | |
| 104 } else if (default_id && !ids.empty() && ids[i] == default_id) { | |
| 105 caps->default_paper = i; | |
| 106 } | |
| 107 } | |
| 108 caps->papers.push_back(paper); | |
| 109 } | |
| 110 | |
| 111 if (caps->default_paper < 0) { | |
| 112 // Add default paper because DeviceCapabilities it was not found yet. | |
|
Noam Samuel
2014/02/04 18:33:22
"Add default paper because DeviceCapabilities hasn
Vitaly Buka (NO REVIEWS)
2014/02/04 18:48:24
Done.
| |
| 113 if (!default_size.IsEmpty()) { | |
| 114 caps->default_paper = caps->papers.size(); | |
| 115 PrinterSemanticCapsAndDefaults::Paper paper; | |
| 116 paper.size_um = default_size; | |
| 117 paper.name = "CUSTOM"; | |
| 118 caps->papers.push_back(paper); | |
| 119 } | |
| 120 } | |
| 121 } | |
| 122 | |
| 123 void LoadDpi(const wchar_t* printer, | |
| 124 const wchar_t* port, | |
| 125 const DEVMODE* devmode, | |
| 126 PrinterSemanticCapsAndDefaults* caps) { | |
| 127 gfx::Size default_dpi; | |
| 128 | |
| 129 if (devmode) { | |
| 130 if ((devmode->dmFields & DM_PRINTQUALITY) == DM_PRINTQUALITY && | |
| 131 devmode->dmPrintQuality > 0) { | |
| 132 default_dpi.SetSize(devmode->dmPrintQuality, devmode->dmPrintQuality); | |
| 133 if ((devmode->dmFields & DM_YRESOLUTION) == DM_PRINTQUALITY) { | |
| 134 default_dpi.set_height(devmode->dmYResolution); | |
| 135 } | |
| 136 } | |
| 137 } | |
| 138 | |
| 139 std::vector<POINT> dpis; | |
| 140 GetDeviceCapabilityArray(printer, port, DC_ENUMRESOLUTIONS, &dpis); | |
| 141 | |
| 142 for (size_t i = 0; i < dpis.size() ; ++i) { | |
| 143 gfx::Size dpi(dpis[i].x, dpis[i].y); | |
| 144 if (caps->default_dpi < 0 && default_dpi == dpi) | |
| 145 caps->default_dpi = i; | |
| 146 caps->dpis.push_back(dpi); | |
| 147 } | |
| 148 | |
| 149 if (caps->default_dpi < 0) { | |
| 150 // Add default dpi because DeviceCapabilities didn't return it. | |
| 151 if (!default_dpi.IsEmpty()) { | |
| 152 caps->default_dpi = caps->dpis.size(); | |
| 153 caps->dpis.push_back(default_dpi); | |
| 154 } | |
| 155 } | |
| 156 } | |
| 157 | |
| 36 } // namespace | 158 } // namespace |
| 37 | 159 |
| 38 namespace printing { | |
| 39 | |
| 40 class PrintBackendWin : public PrintBackend { | 160 class PrintBackendWin : public PrintBackend { |
| 41 public: | 161 public: |
| 42 PrintBackendWin() {} | 162 PrintBackendWin() {} |
| 43 | 163 |
| 44 // PrintBackend implementation. | 164 // PrintBackend implementation. |
| 45 virtual bool EnumeratePrinters(PrinterList* printer_list) OVERRIDE; | 165 virtual bool EnumeratePrinters(PrinterList* printer_list) OVERRIDE; |
| 46 virtual std::string GetDefaultPrinterName() OVERRIDE; | 166 virtual std::string GetDefaultPrinterName() OVERRIDE; |
| 47 virtual bool GetPrinterSemanticCapsAndDefaults( | 167 virtual bool GetPrinterSemanticCapsAndDefaults( |
| 48 const std::string& printer_name, | 168 const std::string& printer_name, |
| 49 PrinterSemanticCapsAndDefaults* printer_info) OVERRIDE; | 169 PrinterSemanticCapsAndDefaults* printer_info) OVERRIDE; |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 101 bool PrintBackendWin::GetPrinterSemanticCapsAndDefaults( | 221 bool PrintBackendWin::GetPrinterSemanticCapsAndDefaults( |
| 102 const std::string& printer_name, | 222 const std::string& printer_name, |
| 103 PrinterSemanticCapsAndDefaults* printer_info) { | 223 PrinterSemanticCapsAndDefaults* printer_info) { |
| 104 ScopedPrinterHandle printer_handle; | 224 ScopedPrinterHandle printer_handle; |
| 105 if (!printer_handle.OpenPrinter(base::UTF8ToWide(printer_name).c_str())) { | 225 if (!printer_handle.OpenPrinter(base::UTF8ToWide(printer_name).c_str())) { |
| 106 LOG(WARNING) << "Failed to open printer, error = " << GetLastError(); | 226 LOG(WARNING) << "Failed to open printer, error = " << GetLastError(); |
| 107 return false; | 227 return false; |
| 108 } | 228 } |
| 109 | 229 |
| 110 PrinterInfo5 info_5; | 230 PrinterInfo5 info_5; |
| 111 if (!info_5.Init(printer_handle)) { | 231 if (!info_5.Init(printer_handle)) |
| 112 return false; | 232 return false; |
| 113 } | 233 const wchar_t* name = info_5.get()->pPrinterName; |
| 114 DCHECK_EQ(info_5.get()->pPrinterName, base::UTF8ToUTF16(printer_name)); | 234 const wchar_t* port = info_5.get()->pPortName; |
| 235 DCHECK_EQ(name, base::UTF8ToUTF16(printer_name)); | |
| 115 | 236 |
| 116 PrinterSemanticCapsAndDefaults caps; | 237 PrinterSemanticCapsAndDefaults caps; |
| 117 | |
| 118 // Get printer capabilities. For more info see here: | |
| 119 // http://msdn.microsoft.com/en-us/library/windows/desktop/dd183552(v=vs.85).a spx | |
| 120 caps.color_changeable = (::DeviceCapabilities(info_5.get()->pPrinterName, | |
| 121 info_5.get()->pPortName, | |
| 122 DC_COLORDEVICE, | |
| 123 NULL, | |
| 124 NULL) == 1); | |
| 125 | |
| 126 caps.duplex_capable = (::DeviceCapabilities(info_5.get()->pPrinterName, | |
| 127 info_5.get()->pPortName, | |
| 128 DC_DUPLEX, | |
| 129 NULL, | |
| 130 NULL) == 1); | |
| 131 | |
| 132 UserDefaultDevMode user_settings; | 238 UserDefaultDevMode user_settings; |
| 133 | |
| 134 if (user_settings.Init(printer_handle)) { | 239 if (user_settings.Init(printer_handle)) { |
| 135 if ((user_settings.get()->dmFields & DM_COLOR) == DM_COLOR) | 240 if ((user_settings.get()->dmFields & DM_COLOR) == DM_COLOR) |
| 136 caps.color_default = (user_settings.get()->dmColor == DMCOLOR_COLOR); | 241 caps.color_default = (user_settings.get()->dmColor == DMCOLOR_COLOR); |
| 137 | 242 |
| 138 if ((user_settings.get()->dmFields & DM_DUPLEX) == DM_DUPLEX) { | 243 if ((user_settings.get()->dmFields & DM_DUPLEX) == DM_DUPLEX) { |
| 139 switch (user_settings.get()->dmDuplex) { | 244 switch (user_settings.get()->dmDuplex) { |
| 140 case DMDUP_SIMPLEX: | 245 case DMDUP_SIMPLEX: |
| 141 caps.duplex_default = SIMPLEX; | 246 caps.duplex_default = SIMPLEX; |
| 142 break; | 247 break; |
| 143 case DMDUP_VERTICAL: | 248 case DMDUP_VERTICAL: |
| 144 caps.duplex_default = LONG_EDGE; | 249 caps.duplex_default = LONG_EDGE; |
| 145 break; | 250 break; |
| 146 case DMDUP_HORIZONTAL: | 251 case DMDUP_HORIZONTAL: |
| 147 caps.duplex_default = SHORT_EDGE; | 252 caps.duplex_default = SHORT_EDGE; |
| 148 break; | 253 break; |
| 149 default: | 254 default: |
| 150 NOTREACHED(); | 255 NOTREACHED(); |
| 151 } | 256 } |
| 152 } | 257 } |
| 258 | |
| 259 if ((user_settings.get()->dmFields & DM_COLLATE) == DM_COLLATE) | |
| 260 caps.collate_default = (user_settings.get()->dmCollate == DMCOLLATE_TRUE); | |
| 153 } else { | 261 } else { |
| 154 LOG(WARNING) << "Fallback to color/simplex mode."; | 262 LOG(WARNING) << "Fallback to color/simplex mode."; |
| 155 caps.color_default = caps.color_changeable; | 263 caps.color_default = caps.color_changeable; |
| 156 caps.duplex_default = SIMPLEX; | 264 caps.duplex_default = SIMPLEX; |
| 157 } | 265 } |
| 158 | 266 |
| 267 // Get printer capabilities. For more info see here: | |
| 268 // http://msdn.microsoft.com/en-us/library/windows/desktop/dd183552(v=vs.85).a spx | |
| 269 caps.color_changeable = | |
| 270 (DeviceCapabilities(name, port, DC_COLORDEVICE, NULL, NULL) == 1); | |
| 271 | |
| 272 caps.duplex_capable = | |
| 273 (DeviceCapabilities(name, port, DC_DUPLEX, NULL, NULL) == 1); | |
| 274 | |
| 275 caps.collate_capable = | |
| 276 (DeviceCapabilities(name, port, DC_COLLATE, NULL, NULL) == 1); | |
| 277 | |
| 278 caps.copies_capable = | |
| 279 (DeviceCapabilities(name, port, DC_COPIES, NULL, NULL) > 1); | |
| 280 | |
| 281 LoadPaper(name, port, user_settings.get(), &caps); | |
| 282 LoadDpi(name, port, user_settings.get(), &caps); | |
| 283 | |
| 159 *printer_info = caps; | 284 *printer_info = caps; |
| 160 return true; | 285 return true; |
| 161 } | 286 } |
| 162 | 287 |
| 163 bool PrintBackendWin::GetPrinterCapsAndDefaults( | 288 bool PrintBackendWin::GetPrinterCapsAndDefaults( |
| 164 const std::string& printer_name, | 289 const std::string& printer_name, |
| 165 PrinterCapsAndDefaults* printer_info) { | 290 PrinterCapsAndDefaults* printer_info) { |
| 166 ScopedXPSInitializer xps_initializer; | 291 ScopedXPSInitializer xps_initializer; |
| 167 if (!xps_initializer.initialized()) { | 292 if (!xps_initializer.initialized()) { |
| 168 // TODO(sanjeevr): Handle legacy proxy case (with no prntvpt.dll) | 293 // TODO(sanjeevr): Handle legacy proxy case (with no prntvpt.dll) |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 246 ScopedPrinterHandle printer_handle; | 371 ScopedPrinterHandle printer_handle; |
| 247 return printer_handle.OpenPrinter(base::UTF8ToWide(printer_name).c_str()); | 372 return printer_handle.OpenPrinter(base::UTF8ToWide(printer_name).c_str()); |
| 248 } | 373 } |
| 249 | 374 |
| 250 scoped_refptr<PrintBackend> PrintBackend::CreateInstance( | 375 scoped_refptr<PrintBackend> PrintBackend::CreateInstance( |
| 251 const base::DictionaryValue* print_backend_settings) { | 376 const base::DictionaryValue* print_backend_settings) { |
| 252 return new PrintBackendWin; | 377 return new PrintBackendWin; |
| 253 } | 378 } |
| 254 | 379 |
| 255 } // namespace printing | 380 } // namespace printing |
| OLD | NEW |