Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(74)

Side by Side Diff: chrome/service/cloud_print/print_system_win.cc

Issue 3945003: Move useful printing backend code from chrome/service/cloud_print to printing... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: resolve merge conflict Created 10 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2010 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 "chrome/service/cloud_print/print_system.h" 5 #include "chrome/service/cloud_print/print_system.h"
6 6
7 #include <windows.h>
8 #include <objidl.h> 7 #include <objidl.h>
9 #include <ocidl.h>
10 #include <olectl.h>
11 #include <prntvpt.h> 8 #include <prntvpt.h>
12 #include <winspool.h> 9 #include <winspool.h>
13 10
14 #include "base/lock.h" 11 #include "base/file_path.h"
15 #include "base/file_util.h"
16 #include "base/object_watcher.h" 12 #include "base/object_watcher.h"
17 #include "base/scoped_ptr.h" 13 #include "base/scoped_ptr.h"
18 #include "base/utf_string_conversions.h" 14 #include "base/utf_string_conversions.h"
19 #include "base/win/scoped_bstr.h" 15 #include "base/win/scoped_bstr.h"
20 #include "base/win/scoped_comptr.h" 16 #include "base/win/scoped_comptr.h"
21 #include "chrome/service/cloud_print/cloud_print_consts.h" 17 #include "chrome/service/cloud_print/cloud_print_consts.h"
22 #include "chrome/service/service_process.h" 18 #include "chrome/service/service_process.h"
23 #include "chrome/service/service_utility_process_host.h" 19 #include "chrome/service/service_utility_process_host.h"
24 #include "gfx/rect.h" 20 #include "gfx/rect.h"
21 #include "printing/backend/print_backend.h"
22 #include "printing/backend/print_backend_consts.h"
23 #include "printing/backend/win_helper.h"
25 #include "printing/native_metafile.h" 24 #include "printing/native_metafile.h"
26 #include "printing/page_range.h" 25 #include "printing/page_range.h"
27 26
28 #pragma comment(lib, "prntvpt.lib") 27 #pragma comment(lib, "prntvpt.lib")
29 #pragma comment(lib, "rpcrt4.lib")
30 28
31 using base::win::ScopedBstr; 29 using base::win::ScopedBstr;
32 using base::win::ScopedComPtr; 30 using base::win::ScopedComPtr;
33 31
34 namespace { 32 namespace {
35 33
36 class DevMode { 34 class DevMode {
37 public: 35 public:
38 DevMode() : dm_(NULL) {} 36 DevMode() : dm_(NULL) {}
39 ~DevMode() { Free(); } 37 ~DevMode() { Free(); }
40 38
41 void Allocate(int size) { 39 void Allocate(int size) {
42 Free(); 40 Free();
43 dm_ = reinterpret_cast<DEVMODE*>(new char[size]); 41 dm_ = reinterpret_cast<DEVMODE*>(new char[size]);
44 } 42 }
45 43
46 void Free() { 44 void Free() {
47 if (dm_) 45 if (dm_)
48 delete [] dm_; 46 delete [] dm_;
49 dm_ = NULL; 47 dm_ = NULL;
50 } 48 }
51 49
52 DEVMODE* dm_; 50 DEVMODE* dm_;
53 51
54 private: 52 private:
55 DISALLOW_COPY_AND_ASSIGN(DevMode); 53 DISALLOW_COPY_AND_ASSIGN(DevMode);
56 }; 54 };
57 55
58 bool InitXPSModule() {
59 HMODULE prntvpt_module = LoadLibrary(L"prntvpt.dll");
60 return (NULL != prntvpt_module);
61 }
62
63 inline HRESULT GetLastErrorHR() { 56 inline HRESULT GetLastErrorHR() {
64 LONG error = GetLastError(); 57 LONG error = GetLastError();
65 return HRESULT_FROM_WIN32(error); 58 return HRESULT_FROM_WIN32(error);
66 } 59 }
67 60
68 HRESULT StreamFromPrintTicket(const std::string& print_ticket, 61 HRESULT StreamFromPrintTicket(const std::string& print_ticket,
69 IStream** stream) { 62 IStream** stream) {
70 DCHECK(stream); 63 DCHECK(stream);
71 HRESULT hr = CreateStreamOnHGlobal(NULL, TRUE, stream); 64 HRESULT hr = CreateStreamOnHGlobal(NULL, TRUE, stream);
72 if (FAILED(hr)) { 65 if (FAILED(hr)) {
73 return hr; 66 return hr;
74 } 67 }
75 ULONG bytes_written = 0; 68 ULONG bytes_written = 0;
76 (*stream)->Write(print_ticket.c_str(), print_ticket.length(), &bytes_written); 69 (*stream)->Write(print_ticket.c_str(), print_ticket.length(), &bytes_written);
77 DCHECK(bytes_written == print_ticket.length()); 70 DCHECK(bytes_written == print_ticket.length());
78 LARGE_INTEGER pos = {0}; 71 LARGE_INTEGER pos = {0};
79 ULARGE_INTEGER new_pos = {0}; 72 ULARGE_INTEGER new_pos = {0};
80 (*stream)->Seek(pos, STREAM_SEEK_SET, &new_pos); 73 (*stream)->Seek(pos, STREAM_SEEK_SET, &new_pos);
81 return S_OK; 74 return S_OK;
82 } 75 }
83 76
84 HRESULT StreamOnHGlobalToString(IStream* stream, std::string* out) {
85 DCHECK(stream);
86 DCHECK(out);
87 HGLOBAL hdata = NULL;
88 HRESULT hr = GetHGlobalFromStream(stream, &hdata);
89 if (SUCCEEDED(hr)) {
90 DCHECK(hdata);
91 ScopedHGlobal<char> locked_data(hdata);
92 out->assign(locked_data.release(), locked_data.Size());
93 }
94 return hr;
95 }
96
97 HRESULT PrintTicketToDevMode(const std::string& printer_name, 77 HRESULT PrintTicketToDevMode(const std::string& printer_name,
98 const std::string& print_ticket, 78 const std::string& print_ticket,
99 DevMode* dev_mode) { 79 DevMode* dev_mode) {
100 DCHECK(dev_mode); 80 DCHECK(dev_mode);
101 81
102 ScopedComPtr<IStream> pt_stream; 82 ScopedComPtr<IStream> pt_stream;
103 HRESULT hr = StreamFromPrintTicket(print_ticket, pt_stream.Receive()); 83 HRESULT hr = StreamFromPrintTicket(print_ticket, pt_stream.Receive());
104 if (FAILED(hr)) 84 if (FAILED(hr))
105 return hr; 85 return hr;
106 86
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after
202 } else if (change & PRINTER_CHANGE_SET_PRINTER) { 182 } else if (change & PRINTER_CHANGE_SET_PRINTER) {
203 delegate_->OnPrinterChanged(); 183 delegate_->OnPrinterChanged();
204 } 184 }
205 if (change & PRINTER_CHANGE_JOB) { 185 if (change & PRINTER_CHANGE_JOB) {
206 delegate_->OnJobChanged(); 186 delegate_->OnJobChanged();
207 } 187 }
208 } 188 }
209 watcher_.StartWatching(printer_change_, this); 189 watcher_.StartWatching(printer_change_, this);
210 } 190 }
211 191
212 bool GetCurrentPrinterInfo(PrinterBasicInfo* printer_info) { 192 bool GetCurrentPrinterInfo(printing::PrinterBasicInfo* printer_info) {
213 DCHECK(printer_info); 193 DCHECK(printer_info);
214 if (!printer_) 194 if (!printer_)
215 return false; 195 return false;
216 196
217 DWORD bytes_needed = 0; 197 DWORD bytes_needed = 0;
218 bool ret = false; 198 bool ret = false;
219 GetPrinter(printer_, 2, NULL, 0, &bytes_needed); 199 GetPrinter(printer_, 2, NULL, 0, &bytes_needed);
220 if (0 != bytes_needed) { 200 if (0 != bytes_needed) {
221 scoped_ptr<BYTE> printer_info_buffer(new BYTE[bytes_needed]); 201 scoped_ptr<BYTE> printer_info_buffer(new BYTE[bytes_needed]);
222 if (GetPrinter(printer_, 2, printer_info_buffer.get(), 202 if (GetPrinter(printer_, 2, printer_info_buffer.get(),
(...skipping 26 matching lines...) Expand all
249 }; 229 };
250 230
251 // This typedef is to workaround the issue with certain versions of 231 // This typedef is to workaround the issue with certain versions of
252 // Visual Studio where it gets confused between multiple Delegate. 232 // Visual Studio where it gets confused between multiple Delegate.
253 // In this case, some compilers get confused and inherit 233 // In this case, some compilers get confused and inherit
254 // PrintSystemWin watchers from wrong Delegate, giving C2664 and C2259 errors. 234 // PrintSystemWin watchers from wrong Delegate, giving C2664 and C2259 errors.
255 typedef PrintSystemWatcherWin::Delegate PrintSystemWatcherWinDelegate; 235 typedef PrintSystemWatcherWin::Delegate PrintSystemWatcherWinDelegate;
256 236
257 class PrintSystemWin : public PrintSystem { 237 class PrintSystemWin : public PrintSystem {
258 public: 238 public:
259 virtual void EnumeratePrinters(PrinterList* printer_list); 239 PrintSystemWin();
260 240
261 virtual bool GetPrinterCapsAndDefaults(const std::string& printer_name, 241 // PrintSystem implementation.
262 PrinterCapsAndDefaults* printer_info); 242 virtual printing::PrintBackend* GetPrintBackend();
263 243
264 virtual bool ValidatePrintTicket(const std::string& printer_name, 244 virtual bool ValidatePrintTicket(const std::string& printer_name,
265 const std::string& print_ticket_data); 245 const std::string& print_ticket_data);
266 246
267 virtual bool GetJobDetails(const std::string& printer_name, 247 virtual bool GetJobDetails(const std::string& printer_name,
268 PlatformJobId job_id, 248 PlatformJobId job_id,
269 PrintJobDetails *job_details); 249 PrintJobDetails *job_details);
270 250
271 virtual bool IsValidPrinter(const std::string& printer_name);
272
273 class PrintServerWatcherWin 251 class PrintServerWatcherWin
274 : public PrintSystem::PrintServerWatcher, 252 : public PrintSystem::PrintServerWatcher,
275 public PrintSystemWatcherWinDelegate { 253 public PrintSystemWatcherWinDelegate {
276 public: 254 public:
277 PrintServerWatcherWin() {} 255 PrintServerWatcherWin() {}
278 256
279 // PrintSystem::PrintServerWatcher interface 257 // PrintSystem::PrintServerWatcher interface
280 virtual bool StartWatching( 258 virtual bool StartWatching(
281 PrintSystem::PrintServerWatcher::Delegate* delegate) { 259 PrintSystem::PrintServerWatcher::Delegate* delegate) {
282 delegate_ = delegate; 260 delegate_ = delegate;
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
316 virtual bool StartWatching( 294 virtual bool StartWatching(
317 PrintSystem::PrinterWatcher::Delegate* delegate) { 295 PrintSystem::PrinterWatcher::Delegate* delegate) {
318 delegate_ = delegate; 296 delegate_ = delegate;
319 return watcher_.Start(printer_name_, this); 297 return watcher_.Start(printer_name_, this);
320 } 298 }
321 virtual bool StopWatching() { 299 virtual bool StopWatching() {
322 bool ret = watcher_.Stop(); 300 bool ret = watcher_.Stop();
323 delegate_ = NULL; 301 delegate_ = NULL;
324 return ret; 302 return ret;
325 } 303 }
326 virtual bool GetCurrentPrinterInfo(PrinterBasicInfo* printer_info) { 304 virtual bool GetCurrentPrinterInfo(
305 printing::PrinterBasicInfo* printer_info) {
327 return watcher_.GetCurrentPrinterInfo(printer_info); 306 return watcher_.GetCurrentPrinterInfo(printer_info);
328 } 307 }
329 308
330 // PrintSystemWatcherWin::Delegate interface 309 // PrintSystemWatcherWin::Delegate interface
331 virtual void OnPrinterAdded() { 310 virtual void OnPrinterAdded() {
332 NOTREACHED(); 311 NOTREACHED();
333 } 312 }
334 virtual void OnPrinterDeleted() { 313 virtual void OnPrinterDeleted() {
335 delegate_->OnPrinterDeleted(); 314 delegate_->OnPrinterDeleted();
336 } 315 }
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
383 NOTREACHED(); 362 NOTREACHED();
384 return false; 363 return false;
385 } 364 }
386 last_page_printed_ = -1; 365 last_page_printed_ = -1;
387 // We only support PDFs for now. 366 // We only support PDFs for now.
388 if (print_data_mime_type != "application/pdf") { 367 if (print_data_mime_type != "application/pdf") {
389 NOTREACHED(); 368 NOTREACHED();
390 return false; 369 return false;
391 } 370 }
392 371
393 if (!InitXPSModule()) { 372 if (!printing::InitXPSModule()) {
394 // TODO(sanjeevr): Handle legacy proxy case (with no prntvpt.dll) 373 // TODO(sanjeevr): Handle legacy proxy case (with no prntvpt.dll)
395 return false; 374 return false;
396 } 375 }
397 DevMode pt_dev_mode; 376 DevMode pt_dev_mode;
398 HRESULT hr = PrintTicketToDevMode(printer_name, print_ticket, 377 HRESULT hr = PrintTicketToDevMode(printer_name, print_ticket,
399 &pt_dev_mode); 378 &pt_dev_mode);
400 if (FAILED(hr)) { 379 if (FAILED(hr)) {
401 NOTREACHED(); 380 NOTREACHED();
402 return false; 381 return false;
403 } 382 }
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after
520 DISALLOW_COPY_AND_ASSIGN(JobSpoolerWin::Core); 499 DISALLOW_COPY_AND_ASSIGN(JobSpoolerWin::Core);
521 }; 500 };
522 scoped_refptr<Core> core_; 501 scoped_refptr<Core> core_;
523 DISALLOW_COPY_AND_ASSIGN(JobSpoolerWin); 502 DISALLOW_COPY_AND_ASSIGN(JobSpoolerWin);
524 }; 503 };
525 504
526 virtual PrintSystem::PrintServerWatcher* CreatePrintServerWatcher(); 505 virtual PrintSystem::PrintServerWatcher* CreatePrintServerWatcher();
527 virtual PrintSystem::PrinterWatcher* CreatePrinterWatcher( 506 virtual PrintSystem::PrinterWatcher* CreatePrinterWatcher(
528 const std::string& printer_name); 507 const std::string& printer_name);
529 virtual PrintSystem::JobSpooler* CreateJobSpooler(); 508 virtual PrintSystem::JobSpooler* CreateJobSpooler();
509
510 private:
511 void Init();
512
513 scoped_refptr<printing::PrintBackend> print_backend_;
530 }; 514 };
531 515
532 void PrintSystemWin::EnumeratePrinters(PrinterList* printer_list) { 516 PrintSystemWin::PrintSystemWin() {
533 DCHECK(printer_list); 517 Init();
534 DWORD bytes_needed = 0;
535 DWORD count_returned = 0;
536 BOOL ret = EnumPrinters(PRINTER_ENUM_LOCAL|PRINTER_ENUM_CONNECTIONS, NULL, 2,
537 NULL, 0, &bytes_needed, &count_returned);
538 if (0 != bytes_needed) {
539 scoped_ptr<BYTE> printer_info_buffer(new BYTE[bytes_needed]);
540 ret = EnumPrinters(PRINTER_ENUM_LOCAL|PRINTER_ENUM_CONNECTIONS, NULL, 2,
541 printer_info_buffer.get(), bytes_needed, &bytes_needed,
542 &count_returned);
543 DCHECK(ret);
544 PRINTER_INFO_2* printer_info =
545 reinterpret_cast<PRINTER_INFO_2*>(printer_info_buffer.get());
546 for (DWORD index = 0; index < count_returned; index++) {
547 PrinterBasicInfo info;
548 info.printer_name = WideToUTF8(printer_info[index].pPrinterName);
549 if (printer_info[index].pComment)
550 info.printer_description = WideToUTF8(printer_info[index].pComment);
551 info.printer_status = printer_info[index].Status;
552 if (printer_info[index].pLocation)
553 info.options[kLocationTagName] =
554 WideToUTF8(printer_info[index].pLocation);
555 if (printer_info[index].pDriverName)
556 info.options[kDriverNameTagName] =
557 WideToUTF8(printer_info[index].pDriverName);
558 printer_list->push_back(info);
559 }
560 }
561 } 518 }
562 519
563 bool PrintSystemWin::GetPrinterCapsAndDefaults( 520 void PrintSystemWin::Init() {
564 const std::string& printer_name, 521 print_backend_ = printing::PrintBackend::CreateInstance(NULL);
565 PrinterCapsAndDefaults* printer_info) { 522 }
566 if (!InitXPSModule()) { 523
567 // TODO(sanjeevr): Handle legacy proxy case (with no prntvpt.dll) 524 printing::PrintBackend* PrintSystemWin::GetPrintBackend() {
568 return false; 525 return print_backend_;
569 }
570 if (!IsValidPrinter(printer_name)) {
571 return false;
572 }
573 DCHECK(printer_info);
574 HPTPROVIDER provider = NULL;
575 std::wstring printer_name_wide = UTF8ToWide(printer_name);
576 HRESULT hr = PTOpenProvider(printer_name_wide.c_str(), 1, &provider);
577 DCHECK(SUCCEEDED(hr));
578 if (provider) {
579 ScopedComPtr<IStream> print_capabilities_stream;
580 hr = CreateStreamOnHGlobal(NULL, TRUE,
581 print_capabilities_stream.Receive());
582 DCHECK(SUCCEEDED(hr));
583 if (print_capabilities_stream) {
584 ScopedBstr error;
585 hr = PTGetPrintCapabilities(provider, NULL, print_capabilities_stream,
586 error.Receive());
587 DCHECK(SUCCEEDED(hr));
588 if (FAILED(hr)) {
589 return false;
590 }
591 hr = StreamOnHGlobalToString(print_capabilities_stream.get(),
592 &printer_info->printer_capabilities);
593 DCHECK(SUCCEEDED(hr));
594 printer_info->caps_mime_type = "text/xml";
595 }
596 // TODO(sanjeevr): Add ScopedPrinterHandle
597 HANDLE printer_handle = NULL;
598 OpenPrinter(const_cast<LPTSTR>(printer_name_wide.c_str()), &printer_handle,
599 NULL);
600 DCHECK(printer_handle);
601 if (printer_handle) {
602 DWORD devmode_size = DocumentProperties(
603 NULL, printer_handle, const_cast<LPTSTR>(printer_name_wide.c_str()),
604 NULL, NULL, 0);
605 DCHECK(0 != devmode_size);
606 scoped_ptr<BYTE> devmode_out_buffer(new BYTE[devmode_size]);
607 DEVMODE* devmode_out =
608 reinterpret_cast<DEVMODE*>(devmode_out_buffer.get());
609 DocumentProperties(
610 NULL, printer_handle, const_cast<LPTSTR>(printer_name_wide.c_str()),
611 devmode_out, NULL, DM_OUT_BUFFER);
612 ScopedComPtr<IStream> printer_defaults_stream;
613 hr = CreateStreamOnHGlobal(NULL, TRUE,
614 printer_defaults_stream.Receive());
615 DCHECK(SUCCEEDED(hr));
616 if (printer_defaults_stream) {
617 hr = PTConvertDevModeToPrintTicket(provider, devmode_size,
618 devmode_out, kPTJobScope,
619 printer_defaults_stream);
620 DCHECK(SUCCEEDED(hr));
621 if (SUCCEEDED(hr)) {
622 hr = StreamOnHGlobalToString(printer_defaults_stream.get(),
623 &printer_info->printer_defaults);
624 DCHECK(SUCCEEDED(hr));
625 printer_info->defaults_mime_type = "text/xml";
626 }
627 }
628 ClosePrinter(printer_handle);
629 }
630 PTCloseProvider(provider);
631 }
632 return true;
633 } 526 }
634 527
635 bool PrintSystemWin::ValidatePrintTicket( 528 bool PrintSystemWin::ValidatePrintTicket(
636 const std::string& printer_name, 529 const std::string& printer_name,
637 const std::string& print_ticket_data) { 530 const std::string& print_ticket_data) {
638 if (!InitXPSModule()) { 531 if (!printing::InitXPSModule()) {
639 // TODO(sanjeevr): Handle legacy proxy case (with no prntvpt.dll) 532 // TODO(sanjeevr): Handle legacy proxy case (with no prntvpt.dll)
640 return false; 533 return false;
641 } 534 }
642 bool ret = false; 535 bool ret = false;
643 HPTPROVIDER provider = NULL; 536 HPTPROVIDER provider = NULL;
644 PTOpenProvider(UTF8ToWide(printer_name.c_str()).c_str(), 1, &provider); 537 PTOpenProvider(UTF8ToWide(printer_name.c_str()).c_str(), 1, &provider);
645 if (provider) { 538 if (provider) {
646 ScopedComPtr<IStream> print_ticket_stream; 539 ScopedComPtr<IStream> print_ticket_stream;
647 CreateStreamOnHGlobal(NULL, TRUE, print_ticket_stream.Receive()); 540 CreateStreamOnHGlobal(NULL, TRUE, print_ticket_stream.Receive());
648 ULONG bytes_written = 0; 541 ULONG bytes_written = 0;
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
705 job_details->total_pages = job_info->TotalPages; 598 job_details->total_pages = job_info->TotalPages;
706 job_details->pages_printed = job_info->PagesPrinted; 599 job_details->pages_printed = job_info->PagesPrinted;
707 ret = true; 600 ret = true;
708 } 601 }
709 } 602 }
710 ClosePrinter(printer_handle); 603 ClosePrinter(printer_handle);
711 } 604 }
712 return ret; 605 return ret;
713 } 606 }
714 607
715 bool PrintSystemWin::IsValidPrinter(const std::string& printer_name) {
716 std::wstring printer_name_wide = UTF8ToWide(printer_name);
717 HANDLE printer_handle = NULL;
718 OpenPrinter(const_cast<LPTSTR>(printer_name_wide.c_str()), &printer_handle,
719 NULL);
720 bool ret = false;
721 if (printer_handle) {
722 ret = true;
723 ClosePrinter(printer_handle);
724 }
725 return ret;
726 }
727
728 PrintSystem::PrintServerWatcher* 608 PrintSystem::PrintServerWatcher*
729 PrintSystemWin::CreatePrintServerWatcher() { 609 PrintSystemWin::CreatePrintServerWatcher() {
730 return new PrintServerWatcherWin(); 610 return new PrintServerWatcherWin();
731 } 611 }
732 612
733 PrintSystem::PrinterWatcher* PrintSystemWin::CreatePrinterWatcher( 613 PrintSystem::PrinterWatcher* PrintSystemWin::CreatePrinterWatcher(
734 const std::string& printer_name) { 614 const std::string& printer_name) {
735 DCHECK(!printer_name.empty()); 615 DCHECK(!printer_name.empty());
736 return new PrinterWatcherWin(printer_name); 616 return new PrinterWatcherWin(printer_name);
737 } 617 }
(...skipping 15 matching lines...) Expand all
753 RpcStringFree(reinterpret_cast<RPC_WSTR *>(&proxy_id_as_string)); 633 RpcStringFree(reinterpret_cast<RPC_WSTR *>(&proxy_id_as_string));
754 return ret; 634 return ret;
755 } 635 }
756 636
757 scoped_refptr<PrintSystem> PrintSystem::CreateInstance( 637 scoped_refptr<PrintSystem> PrintSystem::CreateInstance(
758 const DictionaryValue* print_system_settings) { 638 const DictionaryValue* print_system_settings) {
759 return new PrintSystemWin; 639 return new PrintSystemWin;
760 } 640 }
761 641
762 } // namespace cloud_print 642 } // namespace cloud_print
763
OLDNEW
« no previous file with comments | « chrome/service/cloud_print/print_system_cups.cc ('k') | chrome/service/cloud_print/printer_job_handler.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698