diff options
-rw-r--r-- | chrome/service/cloud_print/cdd_conversion_win.cc | 31 | ||||
-rw-r--r-- | chrome/service/cloud_print/print_system_win.cc | 77 | ||||
-rw-r--r-- | printing/backend/print_backend_win.cc | 21 | ||||
-rw-r--r-- | printing/backend/win_helper.cc | 134 | ||||
-rw-r--r-- | printing/backend/win_helper.h | 16 | ||||
-rw-r--r-- | printing/printing_context_win.cc | 86 |
6 files changed, 215 insertions, 150 deletions
diff --git a/chrome/service/cloud_print/cdd_conversion_win.cc b/chrome/service/cloud_print/cdd_conversion_win.cc index 4965309..f71ed64 100644 --- a/chrome/service/cloud_print/cdd_conversion_win.cc +++ b/chrome/service/cloud_print/cdd_conversion_win.cc @@ -17,6 +17,7 @@ bool IsValidCjt(const std::string& print_ticket_data) { scoped_ptr<DEVMODE[]> CjtToDevMode(const base::string16& printer_name, const std::string& print_ticket) { + using namespace cloud_devices::printer; cloud_devices::CloudDeviceDescription description; if (!description.InitFromString(print_ticket)) return scoped_ptr<DEVMODE[]>(); @@ -25,21 +26,22 @@ scoped_ptr<DEVMODE[]> CjtToDevMode(const base::string16& printer_name, if (!printer.OpenPrinter(printer_name.c_str())) return scoped_ptr<DEVMODE[]>(); - wchar_t* mutable_name = const_cast<wchar_t*>(printer_name.c_str()); - LONG buffer_size = - DocumentProperties(NULL, printer, mutable_name, NULL, NULL, 0); - if (buffer_size <= 0) + scoped_ptr<DEVMODE[]> scoped_dev_mode; + { + ColorTicketItem color; + if (color.LoadFrom(description)) { + bool is_color = color.value().type == STANDARD_COLOR; + scoped_dev_mode = CreateDevModeWithColor(printer, printer_name, is_color); + } else { + scoped_dev_mode = printing::CreateDevMode(printer, NULL); + } + } + + if (!scoped_dev_mode) return scoped_ptr<DEVMODE[]>(); - scoped_ptr<DEVMODE[]> scoped_dev_mode( - reinterpret_cast<DEVMODE*>(new uint8[buffer_size])); DEVMODE* dev_mode = scoped_dev_mode.get(); - if (DocumentProperties(NULL, printer, mutable_name, dev_mode, NULL, - DM_OUT_BUFFER) != IDOK) { - return scoped_ptr<DEVMODE[]>(); - } - using namespace cloud_devices::printer; ColorTicketItem color; DuplexTicketItem duplex; OrientationTicketItem orientation; @@ -120,12 +122,7 @@ scoped_ptr<DEVMODE[]> CjtToDevMode(const base::string16& printer_name, } } - if (DocumentProperties(NULL, printer, mutable_name, dev_mode, dev_mode, - DM_OUT_BUFFER | DM_IN_BUFFER) != IDOK) { - return scoped_ptr<DEVMODE[]>(); - } - - return scoped_dev_mode.Pass(); + return printing::CreateDevMode(printer, dev_mode); } std::string CapabilitiesToCdd( diff --git a/chrome/service/cloud_print/print_system_win.cc b/chrome/service/cloud_print/print_system_win.cc index 765ea0f..82d1c72 100644 --- a/chrome/service/cloud_print/print_system_win.cc +++ b/chrome/service/cloud_print/print_system_win.cc @@ -27,73 +27,6 @@ namespace cloud_print { namespace { -HRESULT StreamFromPrintTicket(const std::string& print_ticket, - IStream** stream) { - DCHECK(stream); - HRESULT hr = CreateStreamOnHGlobal(NULL, TRUE, stream); - if (FAILED(hr)) { - return hr; - } - ULONG bytes_written = 0; - (*stream)->Write(print_ticket.c_str(), print_ticket.length(), &bytes_written); - DCHECK(bytes_written == print_ticket.length()); - LARGE_INTEGER pos = {0}; - ULARGE_INTEGER new_pos = {0}; - (*stream)->Seek(pos, STREAM_SEEK_SET, &new_pos); - return S_OK; -} - -scoped_ptr<DEVMODE[]> XpsTicketToDevMode(const base::string16& printer_name, - const std::string& print_ticket) { - scoped_ptr<DEVMODE[]> scoped_dev_mode; - printing::ScopedXPSInitializer xps_initializer; - if (!xps_initializer.initialized()) { - // TODO(sanjeevr): Handle legacy proxy case (with no prntvpt.dll) - return scoped_dev_mode.Pass(); - } - - printing::ScopedPrinterHandle printer; - if (!printer.OpenPrinter(printer_name.c_str())) - return scoped_dev_mode.Pass(); - - base::win::ScopedComPtr<IStream> pt_stream; - HRESULT hr = StreamFromPrintTicket(print_ticket, pt_stream.Receive()); - if (FAILED(hr)) - return scoped_dev_mode.Pass(); - - HPTPROVIDER provider = NULL; - hr = printing::XPSModule::OpenProvider(printer_name, 1, &provider); - if (SUCCEEDED(hr)) { - ULONG size = 0; - DEVMODE* dm = NULL; - // Use kPTJobScope, because kPTDocumentScope breaks duplex. - hr = printing::XPSModule::ConvertPrintTicketToDevMode(provider, - pt_stream, - kUserDefaultDevmode, - kPTJobScope, - &size, - &dm, - NULL); - if (SUCCEEDED(hr)) { - // Correct DEVMODE using DocumentProperties. See documentation for - // PTConvertPrintTicketToDevMode. - wchar_t* mutable_name = const_cast<wchar_t*>(printer_name.c_str()); - LONG buffer_size = DocumentProperties(NULL, printer, mutable_name, NULL, - dm, DM_IN_BUFFER); - if (buffer_size <= 0) - return scoped_ptr<DEVMODE[]>(); - scoped_dev_mode.reset(reinterpret_cast<DEVMODE*>(new uint8[buffer_size])); - if (DocumentProperties(NULL, printer, mutable_name, scoped_dev_mode.get(), - dm, DM_OUT_BUFFER | DM_IN_BUFFER) != IDOK) { - scoped_dev_mode.reset(); - } - printing::XPSModule::ReleaseMemory(dm); - } - printing::XPSModule::CloseProvider(provider); - } - return scoped_dev_mode.Pass(); -} - class PrintSystemWatcherWin : public base::win::ObjectWatcher::Delegate { public: PrintSystemWatcherWin() @@ -331,16 +264,16 @@ class JobSpoolerWin : public PrintSystem::JobSpooler { NOTREACHED(); return false; } + base::string16 printer_wide = base::UTF8ToWide(printer_name); last_page_printed_ = -1; // We only support PDF and XPS documents for now. if (print_data_mime_type == kContentTypePDF) { scoped_ptr<DEVMODE[]> dev_mode; if (print_ticket_mime_type == kContentTypeJSON) { - dev_mode = CjtToDevMode(base::UTF8ToWide(printer_name), print_ticket); + dev_mode = CjtToDevMode(printer_wide, print_ticket); } else { DCHECK(print_ticket_mime_type == kContentTypeXML); - dev_mode = XpsTicketToDevMode(base::UTF8ToWide(printer_name), - print_ticket); + dev_mode = printing::XpsTicketToDevMode(printer_wide, print_ticket); } if (!dev_mode) { @@ -348,8 +281,8 @@ class JobSpoolerWin : public PrintSystem::JobSpooler { return false; } - HDC dc = CreateDC(L"WINSPOOL", base::UTF8ToWide(printer_name).c_str(), - NULL, dev_mode.get()); + HDC dc = CreateDC(L"WINSPOOL", printer_wide.c_str(), NULL, + dev_mode.get()); if (!dc) { NOTREACHED(); return false; diff --git a/printing/backend/print_backend_win.cc b/printing/backend/print_backend_win.cc index aaf8da1..bb7989f 100644 --- a/printing/backend/print_backend_win.cc +++ b/printing/backend/print_backend_win.cc @@ -314,27 +314,18 @@ bool PrintBackendWin::GetPrinterCapsAndDefaults( } ScopedPrinterHandle printer_handle; if (printer_handle.OpenPrinter(printer_name_wide.c_str())) { - LONG devmode_size = DocumentProperties( - NULL, printer_handle, const_cast<LPTSTR>(printer_name_wide.c_str()), - NULL, NULL, 0); - if (devmode_size <= 0) + scoped_ptr<DEVMODE[]> devmode_out(CreateDevMode(printer_handle, NULL)); + if (!devmode_out) return false; - scoped_ptr<BYTE[]> devmode_out_buffer(new BYTE[devmode_size]); - DEVMODE* devmode_out = - reinterpret_cast<DEVMODE*>(devmode_out_buffer.get()); - DocumentProperties( - NULL, printer_handle, const_cast<LPTSTR>(printer_name_wide.c_str()), - devmode_out, NULL, DM_OUT_BUFFER); base::win::ScopedComPtr<IStream> printer_defaults_stream; hr = CreateStreamOnHGlobal(NULL, TRUE, printer_defaults_stream.Receive()); DCHECK(SUCCEEDED(hr)); if (printer_defaults_stream) { - hr = XPSModule::ConvertDevModeToPrintTicket(provider, - devmode_size, - devmode_out, - kPTJobScope, - printer_defaults_stream); + DWORD dm_size = devmode_out.get()->dmSize + + devmode_out.get()->dmDriverExtra; + hr = XPSModule::ConvertDevModeToPrintTicket(provider, dm_size, + devmode_out.get(), kPTJobScope, printer_defaults_stream); DCHECK(SUCCEEDED(hr)); if (SUCCEEDED(hr)) { hr = StreamOnHGlobalToString(printer_defaults_stream.get(), diff --git a/printing/backend/win_helper.cc b/printing/backend/win_helper.cc index f7b3310..8a66720 100644 --- a/printing/backend/win_helper.cc +++ b/printing/backend/win_helper.cc @@ -10,7 +10,11 @@ #include "base/files/file_path.h" #include "base/logging.h" #include "base/memory/scoped_ptr.h" +#include "base/numerics/safe_conversions.h" +#include "base/strings/string_util.h" +#include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" +#include "base/win/scoped_comptr.h" #include "printing/backend/print_backend.h" #include "printing/backend/print_backend_consts.h" #include "printing/backend/printing_info_win.h" @@ -75,6 +79,42 @@ PTReleaseMemoryProc g_release_memory_proc = NULL; PTCloseProviderProc g_close_provider_proc = NULL; StartXpsPrintJobProc g_start_xps_print_job_proc = NULL; +HRESULT StreamFromPrintTicket(const std::string& print_ticket, + IStream** stream) { + DCHECK(stream); + HRESULT hr = CreateStreamOnHGlobal(NULL, TRUE, stream); + if (FAILED(hr)) { + return hr; + } + ULONG bytes_written = 0; + (*stream)->Write(print_ticket.c_str(), + base::checked_cast<ULONG>(print_ticket.length()), + &bytes_written); + DCHECK(bytes_written == print_ticket.length()); + LARGE_INTEGER pos = {0}; + ULARGE_INTEGER new_pos = {0}; + (*stream)->Seek(pos, STREAM_SEEK_SET, &new_pos); + return S_OK; +} + +const char kXpsTicketTemplate[] = + "<?xml version='1.0' encoding='UTF-8'?>" + "<psf:PrintTicket " + "xmlns:psf='" + "http://schemas.microsoft.com/windows/2003/08/printing/printschemaframework' " + "xmlns:psk=" + "'http://schemas.microsoft.com/windows/2003/08/printing/printschemakeywords' " + "version='1'>" + "<psf:Feature name='psk:PageOutputColor'>" + "<psf:Option name='psk:%s'>" + "</psf:Option>" + "</psf:Feature>" + "</psf:PrintTicket>"; + +const char kXpsTicketColor[] = "Color"; +const char kXpsTicketMonochrome[] = "Monochrome"; + + } // namespace @@ -345,4 +385,98 @@ std::string GetDriverInfo(HANDLE printer) { return driver_info; } +scoped_ptr<DEVMODE[]> XpsTicketToDevMode(const base::string16& printer_name, + const std::string& print_ticket) { + scoped_ptr<DEVMODE[]> scoped_dev_mode; + printing::ScopedXPSInitializer xps_initializer; + if (!xps_initializer.initialized()) { + // TODO(sanjeevr): Handle legacy proxy case (with no prntvpt.dll) + return scoped_dev_mode.Pass(); + } + + printing::ScopedPrinterHandle printer; + if (!printer.OpenPrinter(printer_name.c_str())) + return scoped_dev_mode.Pass(); + + base::win::ScopedComPtr<IStream> pt_stream; + HRESULT hr = StreamFromPrintTicket(print_ticket, pt_stream.Receive()); + if (FAILED(hr)) + return scoped_dev_mode.Pass(); + + HPTPROVIDER provider = NULL; + hr = printing::XPSModule::OpenProvider(printer_name, 1, &provider); + if (SUCCEEDED(hr)) { + ULONG size = 0; + DEVMODE* dm = NULL; + // Use kPTJobScope, because kPTDocumentScope breaks duplex. + hr = printing::XPSModule::ConvertPrintTicketToDevMode(provider, + pt_stream, + kUserDefaultDevmode, + kPTJobScope, + &size, + &dm, + NULL); + if (SUCCEEDED(hr)) { + // Correct DEVMODE using DocumentProperties. See documentation for + // PTConvertPrintTicketToDevMode. + scoped_dev_mode = CreateDevMode(printer, dm); + printing::XPSModule::ReleaseMemory(dm); + } + printing::XPSModule::CloseProvider(provider); + } + return scoped_dev_mode.Pass(); +} + +scoped_ptr<DEVMODE[]> CreateDevModeWithColor(HANDLE printer, + const base::string16& printer_name, + bool color) { + scoped_ptr<DEVMODE[]> default = CreateDevMode(printer, NULL); + if (default && (default.get()->dmFields & DM_COLOR) && + (default.get()->dmColor == DMCOLOR_COLOR) == color) { + return default.Pass(); + } + + default.get()->dmFields |= DM_COLOR; + default.get()->dmColor = color ? DMCOLOR_COLOR : DMCOLOR_MONOCHROME; + + DriverInfo6 info_6; + if (!info_6.Init(printer)) + return default.Pass(); + + const DRIVER_INFO_6* p = info_6.get(); + + // Only HP known to have issues. + if (wcscmp(p->pszMfgName, L"HP") != 0) + return default.Pass(); + + // Need XPS for this workaround. + printing::ScopedXPSInitializer xps_initializer; + if (!xps_initializer.initialized()) + return default.Pass(); + + const char* xps_color = color ? kXpsTicketColor : kXpsTicketMonochrome; + std::string xps_ticket = base::StringPrintf(kXpsTicketTemplate, xps_color); + scoped_ptr<DEVMODE[]> ticket = printing::XpsTicketToDevMode(printer_name, + xps_ticket); + if (!ticket) + return default.Pass(); + + return ticket.Pass(); +} + +PRINTING_EXPORT scoped_ptr<DEVMODE[]> CreateDevMode(HANDLE printer, + DEVMODE* in) { + DWORD flags = in ? (DM_IN_BUFFER) : 0; + LONG buffer_size = DocumentProperties(NULL, printer, L"", NULL, in, flags); + if (buffer_size <= 0) + return scoped_ptr<DEVMODE[]>(); + scoped_ptr<DEVMODE[]> out( + reinterpret_cast<DEVMODE*>(new uint8[buffer_size])); + flags |= DM_OUT_BUFFER; + if (DocumentProperties(NULL, printer, L"", out.get(), in, flags) != IDOK) + return scoped_ptr<DEVMODE[]>(); + DCHECK_EQ(buffer_size, out.get()->dmSize + out.get()->dmDriverExtra); + return out.Pass(); +} + } // namespace printing diff --git a/printing/backend/win_helper.h b/printing/backend/win_helper.h index db66bf8..9b998d7 100644 --- a/printing/backend/win_helper.h +++ b/printing/backend/win_helper.h @@ -12,6 +12,7 @@ #include <string> +#include "base/memory/scoped_ptr.h" #include "base/strings/string16.h" #include "base/win/scoped_handle.h" #include "printing/printing_export.h" @@ -169,6 +170,21 @@ PRINTING_EXPORT bool InitBasicPrinterInfo(HANDLE printer, PRINTING_EXPORT std::string GetDriverInfo(HANDLE printer); +PRINTING_EXPORT scoped_ptr<DEVMODE[]> XpsTicketToDevMode( + const base::string16& printer_name, + const std::string& print_ticket); + +// Creates default DEVMODE and sets color option. Some devices need special +// workaround for color. +PRINTING_EXPORT scoped_ptr<DEVMODE[]> CreateDevModeWithColor( + HANDLE printer, + const base::string16& printer_name, + bool color); + +// Creates new DEVMODE. If |in| is not NULL copy settings from there. +PRINTING_EXPORT scoped_ptr<DEVMODE[]> CreateDevMode(HANDLE printer, + DEVMODE* in); + } // namespace printing #endif // PRINTING_BACKEND_WIN_HELPER_H_ diff --git a/printing/printing_context_win.cc b/printing/printing_context_win.cc index 973ef9f..7c381ca 100644 --- a/printing/printing_context_win.cc +++ b/printing/printing_context_win.cc @@ -343,61 +343,55 @@ PrintingContext::Result PrintingContextWin::UpdatePrinterSettings( // Make printer changes local to Chrome. // See MSDN documentation regarding DocumentProperties. - scoped_ptr<uint8[]> buffer; - DEVMODE* dev_mode = NULL; - LONG buffer_size = DocumentProperties(NULL, printer, device_name_wide, - NULL, NULL, 0); - if (buffer_size > 0) { - buffer.reset(new uint8[buffer_size]); - memset(buffer.get(), 0, buffer_size); - if (DocumentProperties(NULL, printer, device_name_wide, - reinterpret_cast<PDEVMODE>(buffer.get()), NULL, - DM_OUT_BUFFER) == IDOK) { - dev_mode = reinterpret_cast<PDEVMODE>(buffer.get()); - } - } - if (dev_mode == NULL) { - buffer.reset(); + scoped_ptr<DEVMODE[]> scoped_dev_mode = + CreateDevModeWithColor(printer, device_name_wide, + settings_.color() != GRAY); + if (!scoped_dev_mode) return OnError(); - } - if (settings_.color() == GRAY) - dev_mode->dmColor = DMCOLOR_MONOCHROME; - else - dev_mode->dmColor = DMCOLOR_COLOR; - - dev_mode->dmCopies = std::max(settings_.copies(), 1); - if (dev_mode->dmCopies > 1) { // do not change collate unless multiple copies - dev_mode->dmCollate = settings_.collate() ? DMCOLLATE_TRUE : - DMCOLLATE_FALSE; - } - switch (settings_.duplex_mode()) { - case LONG_EDGE: - dev_mode->dmDuplex = DMDUP_VERTICAL; - break; - case SHORT_EDGE: - dev_mode->dmDuplex = DMDUP_HORIZONTAL; - break; - case SIMPLEX: - dev_mode->dmDuplex = DMDUP_SIMPLEX; - break; - default: // UNKNOWN_DUPLEX_MODE - break; - } - dev_mode->dmOrientation = settings_.landscape() ? DMORIENT_LANDSCAPE : - DMORIENT_PORTRAIT; + { + DEVMODE* dev_mode = scoped_dev_mode.get(); + dev_mode->dmCopies = std::max(settings_.copies(), 1); + if (dev_mode->dmCopies > 1) { // do not change unless multiple copies + dev_mode->dmFields |= DM_COPIES; + dev_mode->dmCollate = settings_.collate() ? DMCOLLATE_TRUE : + DMCOLLATE_FALSE; + } + + switch (settings_.duplex_mode()) { + case LONG_EDGE: + dev_mode->dmFields |= DM_DUPLEX; + dev_mode->dmDuplex = DMDUP_VERTICAL; + break; + case SHORT_EDGE: + dev_mode->dmFields |= DM_DUPLEX; + dev_mode->dmDuplex = DMDUP_HORIZONTAL; + break; + case SIMPLEX: + dev_mode->dmFields |= DM_DUPLEX; + dev_mode->dmDuplex = DMDUP_SIMPLEX; + break; + default: // UNKNOWN_DUPLEX_MODE + break; + } + + dev_mode->dmFields |= DM_ORIENTATION; + dev_mode->dmOrientation = settings_.landscape() ? DMORIENT_LANDSCAPE : + DMORIENT_PORTRAIT; + } // Update data using DocumentProperties. - if (DocumentProperties(NULL, printer, device_name_wide, dev_mode, dev_mode, - DM_IN_BUFFER | DM_OUT_BUFFER) != IDOK) { + scoped_dev_mode = CreateDevMode(printer, scoped_dev_mode.get()); + if (!scoped_dev_mode) return OnError(); - } // Set printer then refresh printer settings. - if (!AllocateContext(settings_.device_name(), dev_mode, &context_)) { + if (!AllocateContext(settings_.device_name(), scoped_dev_mode.get(), + &context_)) { return OnError(); } - PrintSettingsInitializerWin::InitPrintSettings(context_, *dev_mode, + PrintSettingsInitializerWin::InitPrintSettings(context_, + *scoped_dev_mode.get(), &settings_); return OK; } |