- add sources.
[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/strings/string_piece.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "base/win/scoped_bstr.h"
14 #include "base/win/scoped_comptr.h"
15 #include "base/win/scoped_hglobal.h"
16 #include "printing/backend/print_backend_consts.h"
17 #include "printing/backend/printing_info_win.h"
18 #include "printing/backend/win_helper.h"
19
20
21 namespace {
22
23 HRESULT StreamOnHGlobalToString(IStream* stream, std::string* out) {
24   DCHECK(stream);
25   DCHECK(out);
26   HGLOBAL hdata = NULL;
27   HRESULT hr = GetHGlobalFromStream(stream, &hdata);
28   if (SUCCEEDED(hr)) {
29     DCHECK(hdata);
30     base::win::ScopedHGlobal<char> locked_data(hdata);
31     out->assign(locked_data.release(), locked_data.Size());
32   }
33   return hr;
34 }
35
36 }  // namespace
37
38 namespace printing {
39
40 class PrintBackendWin : public PrintBackend {
41  public:
42   PrintBackendWin() {}
43
44   // PrintBackend implementation.
45   virtual bool EnumeratePrinters(PrinterList* printer_list) OVERRIDE;
46   virtual std::string GetDefaultPrinterName() OVERRIDE;
47   virtual bool GetPrinterSemanticCapsAndDefaults(
48       const std::string& printer_name,
49       PrinterSemanticCapsAndDefaults* printer_info) OVERRIDE;
50   virtual bool GetPrinterCapsAndDefaults(
51       const std::string& printer_name,
52       PrinterCapsAndDefaults* printer_info) OVERRIDE;
53   virtual std::string GetPrinterDriverInfo(
54       const std::string& printer_name) OVERRIDE;
55   virtual bool IsValidPrinter(const std::string& printer_name) OVERRIDE;
56
57  protected:
58   virtual ~PrintBackendWin() {}
59 };
60
61 bool PrintBackendWin::EnumeratePrinters(PrinterList* printer_list) {
62   DCHECK(printer_list);
63   DWORD bytes_needed = 0;
64   DWORD count_returned = 0;
65   const DWORD kLevel = 4;
66   BOOL ret = EnumPrinters(PRINTER_ENUM_LOCAL|PRINTER_ENUM_CONNECTIONS, NULL,
67                           kLevel, NULL, 0, &bytes_needed, &count_returned);
68   if (!bytes_needed)
69     return false;
70   scoped_ptr<BYTE[]> printer_info_buffer(new BYTE[bytes_needed]);
71   ret = EnumPrinters(PRINTER_ENUM_LOCAL|PRINTER_ENUM_CONNECTIONS, NULL, kLevel,
72                      printer_info_buffer.get(), bytes_needed, &bytes_needed,
73                      &count_returned);
74   DCHECK(ret);
75   if (!ret)
76     return false;
77
78   std::string default_printer = GetDefaultPrinterName();
79   PRINTER_INFO_4* printer_info =
80       reinterpret_cast<PRINTER_INFO_4*>(printer_info_buffer.get());
81   for (DWORD index = 0; index < count_returned; index++) {
82     ScopedPrinterHandle printer;
83     PrinterBasicInfo info;
84     if (printer.OpenPrinter(printer_info[index].pPrinterName) &&
85         InitBasicPrinterInfo(printer, &info)) {
86       info.is_default = (info.printer_name == default_printer);
87       printer_list->push_back(info);
88     }
89   }
90   return true;
91 }
92
93 std::string PrintBackendWin::GetDefaultPrinterName() {
94   DWORD size = MAX_PATH;
95   TCHAR default_printer_name[MAX_PATH];
96   if (!::GetDefaultPrinter(default_printer_name, &size))
97     return std::string();
98   return WideToUTF8(default_printer_name);
99 }
100
101 bool PrintBackendWin::GetPrinterSemanticCapsAndDefaults(
102     const std::string& printer_name,
103     PrinterSemanticCapsAndDefaults* printer_info) {
104   ScopedPrinterHandle printer_handle;
105   if (!printer_handle.OpenPrinter(UTF8ToWide(printer_name).c_str())) {
106     LOG(WARNING) << "Failed to open printer, error = " << GetLastError();
107     return false;
108   }
109
110   PrinterInfo5 info_5;
111   if (!info_5.Init(printer_handle)) {
112     return false;
113   }
114   DCHECK_EQ(info_5.get()->pPrinterName, UTF8ToUTF16(printer_name));
115
116   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).aspx
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;
133
134   if (user_settings.Init(printer_handle)) {
135     if ((user_settings.get()->dmFields & DM_COLOR) == DM_COLOR)
136       caps.color_default = (user_settings.get()->dmColor == DMCOLOR_COLOR);
137
138     if ((user_settings.get()->dmFields & DM_DUPLEX) == DM_DUPLEX) {
139       switch (user_settings.get()->dmDuplex) {
140       case DMDUP_SIMPLEX:
141         caps.duplex_default = SIMPLEX;
142         break;
143       case DMDUP_VERTICAL:
144         caps.duplex_default = LONG_EDGE;
145         break;
146       case DMDUP_HORIZONTAL:
147         caps.duplex_default = SHORT_EDGE;
148         break;
149       default:
150         NOTREACHED();
151       }
152     }
153   } else {
154     LOG(WARNING) << "Fallback to color/simplex mode.";
155     caps.color_default = caps.color_changeable;
156     caps.duplex_default = SIMPLEX;
157   }
158
159   *printer_info = caps;
160   return true;
161 }
162
163 bool PrintBackendWin::GetPrinterCapsAndDefaults(
164     const std::string& printer_name,
165     PrinterCapsAndDefaults* printer_info) {
166   ScopedXPSInitializer xps_initializer;
167   if (!xps_initializer.initialized()) {
168     // TODO(sanjeevr): Handle legacy proxy case (with no prntvpt.dll)
169     return false;
170   }
171   if (!IsValidPrinter(printer_name)) {
172     return false;
173   }
174   DCHECK(printer_info);
175   HPTPROVIDER provider = NULL;
176   std::wstring printer_name_wide = UTF8ToWide(printer_name);
177   HRESULT hr = XPSModule::OpenProvider(printer_name_wide, 1, &provider);
178   if (provider) {
179     base::win::ScopedComPtr<IStream> print_capabilities_stream;
180     hr = CreateStreamOnHGlobal(NULL, TRUE,
181                                print_capabilities_stream.Receive());
182     DCHECK(SUCCEEDED(hr));
183     if (print_capabilities_stream) {
184       base::win::ScopedBstr error;
185       hr = XPSModule::GetPrintCapabilities(provider,
186                                            NULL,
187                                            print_capabilities_stream,
188                                            error.Receive());
189       DCHECK(SUCCEEDED(hr));
190       if (FAILED(hr)) {
191         return false;
192       }
193       hr = StreamOnHGlobalToString(print_capabilities_stream.get(),
194                                    &printer_info->printer_capabilities);
195       DCHECK(SUCCEEDED(hr));
196       printer_info->caps_mime_type = "text/xml";
197     }
198     ScopedPrinterHandle printer_handle;
199     if (printer_handle.OpenPrinter(printer_name_wide.c_str())) {
200       LONG devmode_size = DocumentProperties(
201           NULL, printer_handle, const_cast<LPTSTR>(printer_name_wide.c_str()),
202           NULL, NULL, 0);
203       if (devmode_size <= 0)
204         return false;
205       scoped_ptr<BYTE[]> devmode_out_buffer(new BYTE[devmode_size]);
206       DEVMODE* devmode_out =
207           reinterpret_cast<DEVMODE*>(devmode_out_buffer.get());
208       DocumentProperties(
209           NULL, printer_handle, const_cast<LPTSTR>(printer_name_wide.c_str()),
210           devmode_out, NULL, DM_OUT_BUFFER);
211       base::win::ScopedComPtr<IStream> printer_defaults_stream;
212       hr = CreateStreamOnHGlobal(NULL, TRUE,
213                                  printer_defaults_stream.Receive());
214       DCHECK(SUCCEEDED(hr));
215       if (printer_defaults_stream) {
216         hr = XPSModule::ConvertDevModeToPrintTicket(provider,
217                                                     devmode_size,
218                                                     devmode_out,
219                                                     kPTJobScope,
220                                                     printer_defaults_stream);
221         DCHECK(SUCCEEDED(hr));
222         if (SUCCEEDED(hr)) {
223           hr = StreamOnHGlobalToString(printer_defaults_stream.get(),
224                                        &printer_info->printer_defaults);
225           DCHECK(SUCCEEDED(hr));
226           printer_info->defaults_mime_type = "text/xml";
227         }
228       }
229     }
230     XPSModule::CloseProvider(provider);
231   }
232   return true;
233 }
234
235 // Gets the information about driver for a specific printer.
236 std::string PrintBackendWin::GetPrinterDriverInfo(
237     const std::string& printer_name) {
238   ScopedPrinterHandle printer;
239   if (!printer.OpenPrinter(UTF8ToWide(printer_name).c_str())) {
240     return std::string();
241   }
242   return GetDriverInfo(printer);
243 }
244
245 bool PrintBackendWin::IsValidPrinter(const std::string& printer_name) {
246   ScopedPrinterHandle printer_handle;
247   return printer_handle.OpenPrinter(UTF8ToWide(printer_name).c_str());
248 }
249
250 scoped_refptr<PrintBackend> PrintBackend::CreateInstance(
251     const base::DictionaryValue* print_backend_settings) {
252   return new PrintBackendWin;
253 }
254
255 }  // namespace printing