Commit f9d0c0ca authored by vitalybuka's avatar vitalybuka Committed by Commit bot

Restored printing windows context for builds without preview.

This is code placed into separate file that was removed in https://codereview.chromium.org/478183005

Code is still used by CEF.

BUG=374321
NOTRY=true

Review URL: https://codereview.chromium.org/557663002

Cr-Commit-Position: refs/heads/master@{#293992}
parent 75844fdb
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
'backend/print_backend_consts.cc', 'backend/print_backend_consts.cc',
'backend/print_backend_consts.h', 'backend/print_backend_consts.h',
'backend/print_backend_dummy.cc', 'backend/print_backend_dummy.cc',
'backend/print_backend_win.cc',
'backend/printing_info_win.cc', 'backend/printing_info_win.cc',
'backend/printing_info_win.h', 'backend/printing_info_win.h',
'emf_win.cc', 'emf_win.cc',
...@@ -78,6 +79,10 @@ ...@@ -78,6 +79,10 @@
'printed_pages_source.h', 'printed_pages_source.h',
'printing_context.cc', 'printing_context.cc',
'printing_context.h', 'printing_context.h',
'printing_context_system_dialog_win.cc',
'printing_context_system_dialog_win.h',
'printing_context_win.cc',
'printing_context_win.h',
'printing_utils.cc', 'printing_utils.cc',
'printing_utils.h', 'printing_utils.h',
'units.cc', 'units.cc',
...@@ -120,9 +125,6 @@ ...@@ -120,9 +125,6 @@
'sources': [ 'sources': [
'backend/win_helper.cc', 'backend/win_helper.cc',
'backend/win_helper.h', 'backend/win_helper.h',
'backend/print_backend_win.cc',
'printing_context_win.cc',
'printing_context_win.h',
], ],
}], }],
['chromeos==1',{ ['chromeos==1',{
......
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "printing/printing_context_system_dialog_win.h"
#include "base/message_loop/message_loop.h"
#include "printing/backend/win_helper.h"
#include "printing/print_settings_initializer_win.h"
#include "skia/ext/platform_device.h"
namespace printing {
PrintingContextSytemDialogWin::PrintingContextSytemDialogWin(Delegate* delegate)
: PrintingContextWin(delegate), dialog_box_(NULL) {
}
PrintingContextSytemDialogWin::~PrintingContextSytemDialogWin() {
}
void PrintingContextSytemDialogWin::AskUserForSettings(
int max_pages,
bool has_selection,
const PrintSettingsCallback& callback) {
DCHECK(!in_print_job_);
dialog_box_dismissed_ = false;
HWND window = GetRootWindow(delegate_->GetParentView());
DCHECK(window);
// Show the OS-dependent dialog box.
// If the user press
// - OK, the settings are reset and reinitialized with the new settings. OK
// is
// returned.
// - Apply then Cancel, the settings are reset and reinitialized with the
// new
// settings. CANCEL is returned.
// - Cancel, the settings are not changed, the previous setting, if it was
// initialized before, are kept. CANCEL is returned.
// On failure, the settings are reset and FAILED is returned.
PRINTDLGEX dialog_options = {sizeof(PRINTDLGEX)};
dialog_options.hwndOwner = window;
// Disable options we don't support currently.
// TODO(maruel): Reuse the previously loaded settings!
dialog_options.Flags = PD_RETURNDC | PD_USEDEVMODECOPIESANDCOLLATE |
PD_NOCURRENTPAGE | PD_HIDEPRINTTOFILE;
if (!has_selection)
dialog_options.Flags |= PD_NOSELECTION;
PRINTPAGERANGE ranges[32];
dialog_options.nStartPage = START_PAGE_GENERAL;
if (max_pages) {
// Default initialize to print all the pages.
memset(ranges, 0, sizeof(ranges));
ranges[0].nFromPage = 1;
ranges[0].nToPage = max_pages;
dialog_options.nPageRanges = 1;
dialog_options.nMaxPageRanges = arraysize(ranges);
dialog_options.nMinPage = 1;
dialog_options.nMaxPage = max_pages;
dialog_options.lpPageRanges = ranges;
} else {
// No need to bother, we don't know how many pages are available.
dialog_options.Flags |= PD_NOPAGENUMS;
}
if (ShowPrintDialog(&dialog_options) != S_OK) {
ResetSettings();
callback.Run(FAILED);
}
// TODO(maruel): Support PD_PRINTTOFILE.
callback.Run(ParseDialogResultEx(dialog_options));
}
void PrintingContextSytemDialogWin::Cancel() {
PrintingContextWin::Cancel();
if (dialog_box_) {
DestroyWindow(dialog_box_);
dialog_box_dismissed_ = true;
}
}
HRESULT PrintingContextSytemDialogWin::ShowPrintDialog(PRINTDLGEX* options) {
// Note that this cannot use ui::BaseShellDialog as the print dialog is
// system modal: opening it from a background thread can cause Windows to
// get the wrong Z-order which will make the print dialog appear behind the
// browser frame (but still being modal) so neither the browser frame nor
// the print dialog will get any input. See http://crbug.com/342697
// http://crbug.com/180997 for details.
base::MessageLoop::ScopedNestableTaskAllower allow(
base::MessageLoop::current());
return PrintDlgEx(options);
}
bool PrintingContextSytemDialogWin::InitializeSettings(
const DEVMODE& dev_mode,
const std::wstring& new_device_name,
const PRINTPAGERANGE* ranges,
int number_ranges,
bool selection_only) {
DCHECK(GetDeviceCaps(context(), CLIPCAPS));
DCHECK(GetDeviceCaps(context(), RASTERCAPS) & RC_STRETCHDIB);
DCHECK(GetDeviceCaps(context(), RASTERCAPS) & RC_BITMAP64);
// Some printers don't advertise these.
// DCHECK(GetDeviceCaps(context(), RASTERCAPS) & RC_SCALING);
// DCHECK(GetDeviceCaps(context(), SHADEBLENDCAPS) & SB_CONST_ALPHA);
// DCHECK(GetDeviceCaps(context(), SHADEBLENDCAPS) & SB_PIXEL_ALPHA);
// StretchDIBits() support is needed for printing.
if (!(GetDeviceCaps(context(), RASTERCAPS) & RC_STRETCHDIB) ||
!(GetDeviceCaps(context(), RASTERCAPS) & RC_BITMAP64)) {
NOTREACHED();
ResetSettings();
return false;
}
DCHECK(!in_print_job_);
DCHECK(context());
PageRanges ranges_vector;
if (!selection_only) {
// Convert the PRINTPAGERANGE array to a PrintSettings::PageRanges vector.
ranges_vector.reserve(number_ranges);
for (int i = 0; i < number_ranges; ++i) {
PageRange range;
// Transfer from 1-based to 0-based.
range.from = ranges[i].nFromPage - 1;
range.to = ranges[i].nToPage - 1;
ranges_vector.push_back(range);
}
}
settings_.set_ranges(ranges_vector);
settings_.set_device_name(new_device_name);
settings_.set_selection_only(selection_only);
PrintSettingsInitializerWin::InitPrintSettings(
context(), dev_mode, &settings_);
return true;
}
PrintingContext::Result PrintingContextSytemDialogWin::ParseDialogResultEx(
const PRINTDLGEX& dialog_options) {
// If the user clicked OK or Apply then Cancel, but not only Cancel.
if (dialog_options.dwResultAction != PD_RESULT_CANCEL) {
// Start fresh.
ResetSettings();
DEVMODE* dev_mode = NULL;
if (dialog_options.hDevMode) {
dev_mode =
reinterpret_cast<DEVMODE*>(GlobalLock(dialog_options.hDevMode));
DCHECK(dev_mode);
}
std::wstring device_name;
if (dialog_options.hDevNames) {
DEVNAMES* dev_names =
reinterpret_cast<DEVNAMES*>(GlobalLock(dialog_options.hDevNames));
DCHECK(dev_names);
if (dev_names) {
device_name = reinterpret_cast<const wchar_t*>(dev_names) +
dev_names->wDeviceOffset;
GlobalUnlock(dialog_options.hDevNames);
}
}
bool success = false;
if (dev_mode && !device_name.empty()) {
set_context(dialog_options.hDC);
PRINTPAGERANGE* page_ranges = NULL;
DWORD num_page_ranges = 0;
bool print_selection_only = false;
if (dialog_options.Flags & PD_PAGENUMS) {
page_ranges = dialog_options.lpPageRanges;
num_page_ranges = dialog_options.nPageRanges;
}
if (dialog_options.Flags & PD_SELECTION) {
print_selection_only = true;
}
success = InitializeSettings(*dev_mode,
device_name,
page_ranges,
num_page_ranges,
print_selection_only);
}
if (!success && dialog_options.hDC) {
DeleteDC(dialog_options.hDC);
set_context(NULL);
}
if (dev_mode) {
GlobalUnlock(dialog_options.hDevMode);
}
} else {
if (dialog_options.hDC) {
DeleteDC(dialog_options.hDC);
}
}
if (dialog_options.hDevMode != NULL)
GlobalFree(dialog_options.hDevMode);
if (dialog_options.hDevNames != NULL)
GlobalFree(dialog_options.hDevNames);
switch (dialog_options.dwResultAction) {
case PD_RESULT_PRINT:
return context() ? OK : FAILED;
case PD_RESULT_APPLY:
return context() ? CANCEL : FAILED;
case PD_RESULT_CANCEL:
return CANCEL;
default:
return FAILED;
}
}
PrintingContext::Result PrintingContextSytemDialogWin::ParseDialogResult(
const PRINTDLG& dialog_options) {
// If the user clicked OK or Apply then Cancel, but not only Cancel.
// Start fresh.
ResetSettings();
DEVMODE* dev_mode = NULL;
if (dialog_options.hDevMode) {
dev_mode = reinterpret_cast<DEVMODE*>(GlobalLock(dialog_options.hDevMode));
DCHECK(dev_mode);
}
std::wstring device_name;
if (dialog_options.hDevNames) {
DEVNAMES* dev_names =
reinterpret_cast<DEVNAMES*>(GlobalLock(dialog_options.hDevNames));
DCHECK(dev_names);
if (dev_names) {
device_name = reinterpret_cast<const wchar_t*>(
reinterpret_cast<const wchar_t*>(dev_names) +
dev_names->wDeviceOffset);
GlobalUnlock(dialog_options.hDevNames);
}
}
bool success = false;
if (dev_mode && !device_name.empty()) {
set_context(dialog_options.hDC);
success = InitializeSettings(*dev_mode, device_name, NULL, 0, false);
}
if (!success && dialog_options.hDC) {
DeleteDC(dialog_options.hDC);
set_context(NULL);
}
if (dev_mode) {
GlobalUnlock(dialog_options.hDevMode);
}
if (dialog_options.hDevMode != NULL)
GlobalFree(dialog_options.hDevMode);
if (dialog_options.hDevNames != NULL)
GlobalFree(dialog_options.hDevNames);
return context() ? OK : FAILED;
}
} // namespace printing
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef PRINTING_PRINTING_CONTEXT_SYSTEM_DIALOG_WIN_H_
#define PRINTING_PRINTING_CONTEXT_SYSTEM_DIALOG_WIN_H_
#include <ocidl.h>
#include <commdlg.h>
#include <string>
#include "printing/printing_context_win.h"
#include "ui/gfx/native_widget_types.h"
namespace printing {
class PRINTING_EXPORT PrintingContextSytemDialogWin
: public PrintingContextWin {
public:
explicit PrintingContextSytemDialogWin(Delegate* delegate);
virtual ~PrintingContextSytemDialogWin();
// PrintingContext implementation.
virtual void AskUserForSettings(
int max_pages,
bool has_selection,
const PrintSettingsCallback& callback) OVERRIDE;
virtual void Cancel() OVERRIDE;
private:
friend class MockPrintingContextWin;
virtual HRESULT ShowPrintDialog(PRINTDLGEX* options);
// Reads the settings from the selected device context. Updates settings_ and
// its margins.
bool InitializeSettings(const DEVMODE& dev_mode,
const std::wstring& new_device_name,
const PRINTPAGERANGE* ranges,
int number_ranges,
bool selection_only);
// Parses the result of a PRINTDLGEX result.
Result ParseDialogResultEx(const PRINTDLGEX& dialog_options);
Result ParseDialogResult(const PRINTDLG& dialog_options);
// The dialog box for the time it is shown.
volatile HWND dialog_box_;
DISALLOW_COPY_AND_ASSIGN(PrintingContextSytemDialogWin);
};
} // namespace printing
#endif // PRINTING_PRINTING_CONTEXT_SYSTEM_DIALOG_WIN_H_
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "printing/backend/win_helper.h" #include "printing/backend/win_helper.h"
#include "printing/print_settings_initializer_win.h" #include "printing/print_settings_initializer_win.h"
#include "printing/printed_document.h" #include "printing/printed_document.h"
#include "printing/printing_context_system_dialog_win.h"
#include "printing/printing_utils.h" #include "printing/printing_utils.h"
#include "printing/units.h" #include "printing/units.h"
#include "skia/ext/platform_device.h" #include "skia/ext/platform_device.h"
...@@ -21,32 +22,16 @@ ...@@ -21,32 +22,16 @@
#include "ui/aura/window.h" #include "ui/aura/window.h"
#endif #endif
namespace {
HWND GetRootWindow(gfx::NativeView view) {
HWND window = NULL;
#if defined(USE_AURA)
if (view)
window = view->GetHost()->GetAcceleratedWidget();
#else
if (view && IsWindow(view)) {
window = GetAncestor(view, GA_ROOTOWNER);
}
#endif
if (!window) {
// TODO(maruel): bug 1214347 Get the right browser window instead.
return GetDesktopWindow();
}
return window;
}
} // anonymous namespace
namespace printing { namespace printing {
// static // static
scoped_ptr<PrintingContext> PrintingContext::Create(Delegate* delegate) { scoped_ptr<PrintingContext> PrintingContext::Create(Delegate* delegate) {
#if defined(DISABLE_BASIC_PRINTING)
return make_scoped_ptr<PrintingContext>(new PrintingContextWin(delegate)); return make_scoped_ptr<PrintingContext>(new PrintingContextWin(delegate));
#else // DISABLE_BASIC_PRINTING
return make_scoped_ptr<PrintingContext>(
new PrintingContextSytemDialogWin(delegate));
#endif // DISABLE_BASIC_PRINTING
} }
PrintingContextWin::PrintingContextWin(Delegate* delegate) PrintingContextWin::PrintingContextWin(Delegate* delegate)
...@@ -364,6 +349,23 @@ PrintingContext::Result PrintingContextWin::InitializeSettings( ...@@ -364,6 +349,23 @@ PrintingContext::Result PrintingContextWin::InitializeSettings(
return OK; return OK;
} }
HWND PrintingContextWin::GetRootWindow(gfx::NativeView view) {
HWND window = NULL;
#if defined(USE_AURA)
if (view)
window = view->GetHost()->GetAcceleratedWidget();
#else
if (view && IsWindow(view)) {
window = GetAncestor(view, GA_ROOTOWNER);
}
#endif
if (!window) {
// TODO(maruel): crbug.com/1214347 Get the right browser window instead.
return GetDesktopWindow();
}
return window;
}
scoped_ptr<DEVMODE, base::FreeDeleter> PrintingContextWin::ShowPrintDialog( scoped_ptr<DEVMODE, base::FreeDeleter> PrintingContextWin::ShowPrintDialog(
HANDLE printer, HANDLE printer,
gfx::NativeView parent_view, gfx::NativeView parent_view,
......
...@@ -5,18 +5,16 @@ ...@@ -5,18 +5,16 @@
#ifndef PRINTING_PRINTING_CONTEXT_WIN_H_ #ifndef PRINTING_PRINTING_CONTEXT_WIN_H_
#define PRINTING_PRINTING_CONTEXT_WIN_H_ #define PRINTING_PRINTING_CONTEXT_WIN_H_
#include <ocidl.h>
#include <commdlg.h>
#include <string> #include <string>
#include "base/memory/scoped_ptr.h" #include "base/memory/scoped_ptr.h"
#include "build/build_config.h"
#include "printing/printing_context.h" #include "printing/printing_context.h"
#include "ui/gfx/native_widget_types.h" #include "ui/gfx/native_widget_types.h"
namespace printing { namespace printing {
class PrintSettings;
class PRINTING_EXPORT PrintingContextWin : public PrintingContext { class PRINTING_EXPORT PrintingContextWin : public PrintingContext {
public: public:
explicit PrintingContextWin(Delegate* delegate); explicit PrintingContextWin(Delegate* delegate);
...@@ -41,20 +39,26 @@ class PRINTING_EXPORT PrintingContextWin : public PrintingContext { ...@@ -41,20 +39,26 @@ class PRINTING_EXPORT PrintingContextWin : public PrintingContext {
virtual gfx::NativeDrawingContext context() const OVERRIDE; virtual gfx::NativeDrawingContext context() const OVERRIDE;
protected: protected:
static HWND GetRootWindow(gfx::NativeView view);
// Reads the settings from the selected device context. Updates settings_ and
// its margins.
virtual Result InitializeSettings(const base::string16& device_name,
DEVMODE* dev_mode);
HDC contest() const { return context_; }
void set_context(HDC context) { context_ = context; }
private:
virtual scoped_ptr<DEVMODE, base::FreeDeleter> ShowPrintDialog( virtual scoped_ptr<DEVMODE, base::FreeDeleter> ShowPrintDialog(
HANDLE printer, HANDLE printer,
gfx::NativeView parent_view, gfx::NativeView parent_view,
DEVMODE* dev_mode); DEVMODE* dev_mode);
private:
// Used in response to the user canceling the printing. // Used in response to the user canceling the printing.
static BOOL CALLBACK AbortProc(HDC hdc, int nCode); static BOOL CALLBACK AbortProc(HDC hdc, int nCode);
// Reads the settings from the selected device context. Updates settings_ and
// its margins.
virtual Result InitializeSettings(const base::string16& device_name,
DEVMODE* dev_mode);
// The selected printer context. // The selected printer context.
HDC context_; HDC context_;
......
...@@ -4,8 +4,13 @@ ...@@ -4,8 +4,13 @@
#include "printing/printing_context_win.h" #include "printing/printing_context_win.h"
#include "printing/printing_test.h" #include "base/bind.h"
#include "base/message_loop/message_loop.h"
#include "printing/backend/printing_info_win.h"
#include "printing/backend/win_helper.h"
#include "printing/print_settings.h" #include "printing/print_settings.h"
#include "printing/printing_context_system_dialog_win.h"
#include "printing/printing_test.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
namespace printing { namespace printing {
...@@ -29,6 +34,140 @@ class PrintingContextTest : public PrintingTest<testing::Test>, ...@@ -29,6 +34,140 @@ class PrintingContextTest : public PrintingTest<testing::Test>,
PrintingContext::Result result_; PrintingContext::Result result_;
}; };
class MockPrintingContextWin : public PrintingContextSytemDialogWin {
public:
MockPrintingContextWin(Delegate* delegate)
: PrintingContextSytemDialogWin(delegate) {}
protected:
// This is a fake PrintDlgEx implementation that sets the right fields in
// |lppd| to trigger a bug in older revisions of PrintingContext.
HRESULT ShowPrintDialog(PRINTDLGEX* lppd) OVERRIDE {
// The interesting bits:
// Pretend the user hit print
lppd->dwResultAction = PD_RESULT_PRINT;
// Pretend the page range is 1-5, but since lppd->Flags does not have
// PD_SELECTION set, this really shouldn't matter.
lppd->nPageRanges = 1;
lppd->lpPageRanges[0].nFromPage = 1;
lppd->lpPageRanges[0].nToPage = 5;
base::string16 printer_name = PrintingContextTest::GetDefaultPrinter();
ScopedPrinterHandle printer;
if (!printer.OpenPrinter(printer_name.c_str()))
return E_FAIL;
scoped_ptr<uint8[]> buffer;
const DEVMODE* dev_mode = NULL;
HRESULT result = S_OK;
lppd->hDC = NULL;
lppd->hDevMode = NULL;
lppd->hDevNames = NULL;
PrinterInfo2 info_2;
if (info_2.Init(printer)) {
dev_mode = info_2.get()->pDevMode;
}
if (!dev_mode) {
result = E_FAIL;
goto Cleanup;
}
lppd->hDC = CreateDC(L"WINSPOOL", printer_name.c_str(), NULL, dev_mode);
if (!lppd->hDC) {
result = E_FAIL;
goto Cleanup;
}
size_t dev_mode_size = dev_mode->dmSize + dev_mode->dmDriverExtra;
lppd->hDevMode = GlobalAlloc(GMEM_MOVEABLE, dev_mode_size);
if (!lppd->hDevMode) {
result = E_FAIL;
goto Cleanup;
}
void* dev_mode_ptr = GlobalLock(lppd->hDevMode);
if (!dev_mode_ptr) {
result = E_FAIL;
goto Cleanup;
}
memcpy(dev_mode_ptr, dev_mode, dev_mode_size);
GlobalUnlock(lppd->hDevMode);
dev_mode_ptr = NULL;
size_t driver_size =
2 + sizeof(wchar_t) * lstrlen(info_2.get()->pDriverName);
size_t printer_size =
2 + sizeof(wchar_t) * lstrlen(info_2.get()->pPrinterName);
size_t port_size = 2 + sizeof(wchar_t) * lstrlen(info_2.get()->pPortName);
size_t dev_names_size =
sizeof(DEVNAMES) + driver_size + printer_size + port_size;
lppd->hDevNames = GlobalAlloc(GHND, dev_names_size);
if (!lppd->hDevNames) {
result = E_FAIL;
goto Cleanup;
}
void* dev_names_ptr = GlobalLock(lppd->hDevNames);
if (!dev_names_ptr) {
result = E_FAIL;
goto Cleanup;
}
DEVNAMES* dev_names = reinterpret_cast<DEVNAMES*>(dev_names_ptr);
dev_names->wDefault = 1;
dev_names->wDriverOffset = sizeof(DEVNAMES) / sizeof(wchar_t);
memcpy(reinterpret_cast<uint8*>(dev_names_ptr) + dev_names->wDriverOffset,
info_2.get()->pDriverName,
driver_size);
dev_names->wDeviceOffset =
dev_names->wDriverOffset + driver_size / sizeof(wchar_t);
memcpy(reinterpret_cast<uint8*>(dev_names_ptr) + dev_names->wDeviceOffset,
info_2.get()->pPrinterName,
printer_size);
dev_names->wOutputOffset =
dev_names->wDeviceOffset + printer_size / sizeof(wchar_t);
memcpy(reinterpret_cast<uint8*>(dev_names_ptr) + dev_names->wOutputOffset,
info_2.get()->pPortName,
port_size);
GlobalUnlock(lppd->hDevNames);
dev_names_ptr = NULL;
Cleanup:
// Note: This section does proper deallocation/free of DC/global handles. We
// did not use ScopedHGlobal or ScopedHandle because they did not
// perform what we need. Goto's are used based on Windows programming
// idiom, to avoid deeply nested if's, and try-catch-finally is not
// allowed in Chromium.
if (FAILED(result)) {
if (lppd->hDC) {
DeleteDC(lppd->hDC);
}
if (lppd->hDevMode) {
GlobalFree(lppd->hDevMode);
}
if (lppd->hDevNames) {
GlobalFree(lppd->hDevNames);
}
}
return result;
}
};
TEST_F(PrintingContextTest, PrintAll) {
base::MessageLoop message_loop;
if (IsTestCaseDisabled())
return;
MockPrintingContextWin context(this);
context.AskUserForSettings(
123,
false,
base::Bind(&PrintingContextTest::PrintSettingsCallback,
base::Unretained(this)));
EXPECT_EQ(PrintingContext::OK, result());
PrintSettings settings = context.settings();
EXPECT_EQ(settings.ranges().size(), 0);
}
TEST_F(PrintingContextTest, Base) { TEST_F(PrintingContextTest, Base) {
if (IsTestCaseDisabled()) if (IsTestCaseDisabled())
return; return;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment