Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / printing / backend / print_backend_win.cc
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
3 // found in the LICENSE file.
4
5 #include "printing/backend/print_backend.h"
6
7 #include <objidl.h>
8 #include <winspool.h>
9
10 #include "base/memory/scoped_ptr.h"
11 #include "base/numerics/safe_conversions.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "base/strings/string_piece.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "base/win/scoped_bstr.h"
16 #include "base/win/scoped_comptr.h"
17 #include "base/win/scoped_hglobal.h"
18 #include "printing/backend/print_backend_consts.h"
19 #include "printing/backend/printing_info_win.h"
20 #include "printing/backend/win_helper.h"
21
22 namespace printing {
23
24 namespace {
25
26 HRESULT StreamOnHGlobalToString(IStream* stream, std::string* out) {
27   DCHECK(stream);
28   DCHECK(out);
29   HGLOBAL hdata = NULL;
30   HRESULT hr = GetHGlobalFromStream(stream, &hdata);
31   if (SUCCEEDED(hr)) {
32     DCHECK(hdata);
33     base::win::ScopedHGlobal<char*> locked_data(hdata);
34     out->assign(locked_data.release(), locked_data.Size());
35   }
36   return hr;
37 }
38
39 template <class T>
40 void GetDeviceCapabilityArray(const wchar_t* printer,
41                               const wchar_t* port,
42                               WORD id,
43                               std::vector<T>* result) {
44   int count = DeviceCapabilities(printer, port, id, NULL, NULL);
45   if (count <= 0)
46     return;
47   std::vector<T> tmp;
48   tmp.resize(count * 2);
49   count = DeviceCapabilities(printer, port, id,
50                              reinterpret_cast<LPTSTR>(tmp.data()), NULL);
51   if (count <= 0)
52     return;
53   CHECK_LE(count, base::checked_cast<int>(tmp.size()));
54   tmp.resize(count);
55   result->swap(tmp);
56 }
57
58 void LoadPaper(const wchar_t* printer,
59                const wchar_t* port,
60                const DEVMODE* devmode,
61                PrinterSemanticCapsAndDefaults* caps) {
62   static const size_t kToUm = 100;  // Windows uses 0.1mm.
63   static const size_t kMaxPaperName = 64;
64
65   struct PaperName {
66     wchar_t chars[kMaxPaperName];
67   };
68
69   DCHECK_EQ(sizeof(PaperName), sizeof(wchar_t) * kMaxPaperName);
70
71   // Paper
72   std::vector<PaperName> names;
73   GetDeviceCapabilityArray(printer, port, DC_PAPERNAMES, &names);
74
75   std::vector<POINT> sizes;
76   GetDeviceCapabilityArray(printer, port, DC_PAPERSIZE, &sizes);
77
78   std::vector<WORD> ids;
79   GetDeviceCapabilityArray(printer, port, DC_PAPERS, &ids);
80
81   DCHECK_EQ(ids.size(), sizes.size());
82   DCHECK_EQ(names.size(), sizes.size());
83
84   if (ids.size() != sizes.size())
85     ids.clear();
86   if (names.size() != sizes.size())
87     names.clear();
88
89   for (size_t i = 0; i < sizes.size(); ++i) {
90     PrinterSemanticCapsAndDefaults::Paper paper;
91     paper.size_um.SetSize(sizes[i].x * kToUm, sizes[i].y * kToUm);
92     if (!names.empty()) {
93       const wchar_t* name_start = names[i].chars;
94       base::string16 tmp_name(name_start, kMaxPaperName);
95       // Trim trailing zeros.
96       tmp_name = tmp_name.c_str();
97       paper.display_name = base::WideToUTF8(tmp_name);
98     }
99     if (!ids.empty())
100       paper.vendor_id = base::UintToString(ids[i]);
101     caps->papers.push_back(paper);
102   }
103
104   if (devmode) {
105     // Copy paper with the same ID as default paper.
106     if (devmode->dmFields & DM_PAPERSIZE) {
107       for (size_t i = 0; i < ids.size(); ++i) {
108         if (ids[i] == devmode->dmPaperSize) {
109           DCHECK_EQ(ids.size(), caps->papers.size());
110           caps->default_paper = caps->papers[i];
111           break;
112         }
113       }
114     }
115
116     gfx::Size default_size;
117     if (devmode->dmFields & DM_PAPERWIDTH)
118       default_size.set_width(devmode->dmPaperWidth * kToUm);
119     if (devmode->dmFields & DM_PAPERLENGTH)
120       default_size.set_height(devmode->dmPaperLength * kToUm);
121
122     if (!default_size.IsEmpty()) {
123       // Reset default paper if |dmPaperWidth| or |dmPaperLength| does not
124       // match default paper set by.
125       if (default_size != caps->default_paper.size_um)
126         caps->default_paper = PrinterSemanticCapsAndDefaults::Paper();
127       caps->default_paper.size_um = default_size;
128     }
129   }
130 }
131
132 void LoadDpi(const wchar_t* printer,
133              const wchar_t* port,
134              const DEVMODE* devmode,
135              PrinterSemanticCapsAndDefaults* caps) {
136   std::vector<POINT> dpis;
137   GetDeviceCapabilityArray(printer, port, DC_ENUMRESOLUTIONS, &dpis);
138
139   for (size_t i = 0; i < dpis.size() ; ++i)
140     caps->dpis.push_back(gfx::Size(dpis[i].x, dpis[i].y));
141
142   if (devmode) {
143     if ((devmode->dmFields & DM_PRINTQUALITY) && devmode->dmPrintQuality > 0) {
144       caps->default_dpi.SetSize(devmode->dmPrintQuality,
145                                 devmode->dmPrintQuality);
146       if (devmode->dmFields & DM_YRESOLUTION) {
147         caps->default_dpi.set_height(devmode->dmYResolution);
148       }
149     }
150   }
151 }
152
153 }  // namespace
154
155 class PrintBackendWin : public PrintBackend {
156  public:
157   PrintBackendWin() {}
158
159   // PrintBackend implementation.
160   virtual bool EnumeratePrinters(PrinterList* printer_list) override;
161   virtual std::string GetDefaultPrinterName() override;
162   virtual bool GetPrinterSemanticCapsAndDefaults(
163       const std::string& printer_name,
164       PrinterSemanticCapsAndDefaults* printer_info) override;
165   virtual bool GetPrinterCapsAndDefaults(
166       const std::string& printer_name,
167       PrinterCapsAndDefaults* printer_info) override;
168   virtual std::string GetPrinterDriverInfo(
169       const std::string& printer_name) override;
170   virtual bool IsValidPrinter(const std::string& printer_name) override;
171
172  protected:
173   virtual ~PrintBackendWin() {}
174 };
175
176 bool PrintBackendWin::EnumeratePrinters(PrinterList* printer_list) {
177   DCHECK(printer_list);
178   DWORD bytes_needed = 0;
179   DWORD count_returned = 0;
180   const DWORD kLevel = 4;
181   BOOL ret = EnumPrinters(PRINTER_ENUM_LOCAL|PRINTER_ENUM_CONNECTIONS, NULL,
182                           kLevel, NULL, 0, &bytes_needed, &count_returned);
183   if (!bytes_needed)
184     return false;
185   scoped_ptr<BYTE[]> printer_info_buffer(new BYTE[bytes_needed]);
186   ret = EnumPrinters(PRINTER_ENUM_LOCAL|PRINTER_ENUM_CONNECTIONS, NULL, kLevel,
187                      printer_info_buffer.get(), bytes_needed, &bytes_needed,
188                      &count_returned);
189   DCHECK(ret);
190   if (!ret)
191     return false;
192
193   std::string default_printer = GetDefaultPrinterName();
194   PRINTER_INFO_4* printer_info =
195       reinterpret_cast<PRINTER_INFO_4*>(printer_info_buffer.get());
196   for (DWORD index = 0; index < count_returned; index++) {
197     ScopedPrinterHandle printer;
198     PrinterBasicInfo info;
199     if (printer.OpenPrinter(printer_info[index].pPrinterName) &&
200         InitBasicPrinterInfo(printer.Get(), &info)) {
201       info.is_default = (info.printer_name == default_printer);
202       printer_list->push_back(info);
203     }
204   }
205   return true;
206 }
207
208 std::string PrintBackendWin::GetDefaultPrinterName() {
209   DWORD size = MAX_PATH;
210   TCHAR default_printer_name[MAX_PATH];
211   if (!::GetDefaultPrinter(default_printer_name, &size))
212     return std::string();
213   return base::WideToUTF8(default_printer_name);
214 }
215
216 bool PrintBackendWin::GetPrinterSemanticCapsAndDefaults(
217     const std::string& printer_name,
218     PrinterSemanticCapsAndDefaults* printer_info) {
219   ScopedPrinterHandle printer_handle;
220   if (!printer_handle.OpenPrinter(base::UTF8ToWide(printer_name).c_str())) {
221     LOG(WARNING) << "Failed to open printer, error = " << GetLastError();
222     return false;
223   }
224
225   PrinterInfo5 info_5;
226   if (!info_5.Init(printer_handle.Get()))
227     return false;
228   const wchar_t* name = info_5.get()->pPrinterName;
229   const wchar_t* port = info_5.get()->pPortName;
230   DCHECK_EQ(name, base::UTF8ToUTF16(printer_name));
231
232   PrinterSemanticCapsAndDefaults caps;
233
234   scoped_ptr<DEVMODE, base::FreeDeleter> user_settings =
235       CreateDevMode(printer_handle.Get(), NULL);
236   if (user_settings) {
237     if (user_settings->dmFields & DM_COLOR)
238       caps.color_default = (user_settings->dmColor == DMCOLOR_COLOR);
239
240     if (user_settings->dmFields & DM_DUPLEX) {
241       switch (user_settings->dmDuplex) {
242       case DMDUP_SIMPLEX:
243         caps.duplex_default = SIMPLEX;
244         break;
245       case DMDUP_VERTICAL:
246         caps.duplex_default = LONG_EDGE;
247         break;
248       case DMDUP_HORIZONTAL:
249         caps.duplex_default = SHORT_EDGE;
250         break;
251       default:
252         NOTREACHED();
253       }
254     }
255
256     if (user_settings->dmFields & DM_COLLATE)
257       caps.collate_default = (user_settings->dmCollate == DMCOLLATE_TRUE);
258   } else {
259     LOG(WARNING) << "Fallback to color/simplex mode.";
260     caps.color_default = caps.color_changeable;
261     caps.duplex_default = SIMPLEX;
262   }
263
264   // Get printer capabilities. For more info see here:
265   // http://msdn.microsoft.com/en-us/library/windows/desktop/dd183552(v=vs.85).aspx
266   caps.color_changeable =
267       (DeviceCapabilities(name, port, DC_COLORDEVICE, NULL, NULL) == 1);
268   caps.color_model = printing::COLOR;
269   caps.bw_model = printing::GRAY;
270
271   caps.duplex_capable =
272       (DeviceCapabilities(name, port, DC_DUPLEX, NULL, NULL) == 1);
273
274   caps.collate_capable =
275       (DeviceCapabilities(name, port, DC_COLLATE, NULL, NULL) == 1);
276
277   caps.copies_capable =
278       (DeviceCapabilities(name, port, DC_COPIES, NULL, NULL) > 1);
279
280   LoadPaper(name, port, user_settings.get(), &caps);
281   LoadDpi(name, port, user_settings.get(), &caps);
282
283   *printer_info = caps;
284   return true;
285 }
286
287 bool PrintBackendWin::GetPrinterCapsAndDefaults(
288     const std::string& printer_name,
289     PrinterCapsAndDefaults* printer_info) {
290   ScopedXPSInitializer xps_initializer;
291   if (!xps_initializer.initialized()) {
292     // TODO(sanjeevr): Handle legacy proxy case (with no prntvpt.dll)
293     return false;
294   }
295   if (!IsValidPrinter(printer_name)) {
296     return false;
297   }
298   DCHECK(printer_info);
299   HPTPROVIDER provider = NULL;
300   std::wstring printer_name_wide = base::UTF8ToWide(printer_name);
301   HRESULT hr = XPSModule::OpenProvider(printer_name_wide, 1, &provider);
302   if (provider) {
303     base::win::ScopedComPtr<IStream> print_capabilities_stream;
304     hr = CreateStreamOnHGlobal(NULL, TRUE,
305                                print_capabilities_stream.Receive());
306     DCHECK(SUCCEEDED(hr));
307     if (print_capabilities_stream) {
308       base::win::ScopedBstr error;
309       hr = XPSModule::GetPrintCapabilities(provider,
310                                            NULL,
311                                            print_capabilities_stream,
312                                            error.Receive());
313       DCHECK(SUCCEEDED(hr));
314       if (FAILED(hr)) {
315         return false;
316       }
317       hr = StreamOnHGlobalToString(print_capabilities_stream.get(),
318                                    &printer_info->printer_capabilities);
319       DCHECK(SUCCEEDED(hr));
320       printer_info->caps_mime_type = "text/xml";
321     }
322     ScopedPrinterHandle printer_handle;
323     if (printer_handle.OpenPrinter(printer_name_wide.c_str())) {
324       scoped_ptr<DEVMODE, base::FreeDeleter> devmode_out(
325           CreateDevMode(printer_handle.Get(), NULL));
326       if (!devmode_out)
327         return false;
328       base::win::ScopedComPtr<IStream> printer_defaults_stream;
329       hr = CreateStreamOnHGlobal(NULL, TRUE,
330                                  printer_defaults_stream.Receive());
331       DCHECK(SUCCEEDED(hr));
332       if (printer_defaults_stream) {
333         DWORD dm_size = devmode_out->dmSize + devmode_out->dmDriverExtra;
334         hr = XPSModule::ConvertDevModeToPrintTicket(provider, dm_size,
335             devmode_out.get(), kPTJobScope, printer_defaults_stream);
336         DCHECK(SUCCEEDED(hr));
337         if (SUCCEEDED(hr)) {
338           hr = StreamOnHGlobalToString(printer_defaults_stream.get(),
339                                        &printer_info->printer_defaults);
340           DCHECK(SUCCEEDED(hr));
341           printer_info->defaults_mime_type = "text/xml";
342         }
343       }
344     }
345     XPSModule::CloseProvider(provider);
346   }
347   return true;
348 }
349
350 // Gets the information about driver for a specific printer.
351 std::string PrintBackendWin::GetPrinterDriverInfo(
352     const std::string& printer_name) {
353   ScopedPrinterHandle printer;
354   if (!printer.OpenPrinter(base::UTF8ToWide(printer_name).c_str())) {
355     return std::string();
356   }
357   return GetDriverInfo(printer.Get());
358 }
359
360 bool PrintBackendWin::IsValidPrinter(const std::string& printer_name) {
361   ScopedPrinterHandle printer_handle;
362   return printer_handle.OpenPrinter(base::UTF8ToWide(printer_name).c_str());
363 }
364
365 scoped_refptr<PrintBackend> PrintBackend::CreateInstance(
366     const base::DictionaryValue* print_backend_settings) {
367   return new PrintBackendWin;
368 }
369
370 }  // namespace printing