1 // Copyright (c) 2011 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.
5 #include "printing/printing_context_win.h"
10 #include "base/bind.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/win/scoped_handle.h"
13 #include "base/win/scoped_hdc.h"
14 #include "printing/backend/printing_info_win.h"
15 #include "printing/backend/win_helper.h"
16 #include "printing/print_settings.h"
17 #include "printing/printing_context_system_dialog_win.h"
18 #include "printing/printing_test.h"
19 #include "testing/gtest/include/gtest/gtest.h"
23 // This test is automatically disabled if no printer is available.
24 class PrintingContextTest : public PrintingTest<testing::Test>,
25 public PrintingContext::Delegate {
27 void PrintSettingsCallback(PrintingContext::Result result) {
31 // PrintingContext::Delegate methods.
32 gfx::NativeView GetParentView() override { return nullptr; }
33 std::string GetAppLocale() override { return std::string(); }
36 PrintingContext::Result result() const { return result_; }
39 PrintingContext::Result result_;
44 struct FreeHandleTraits {
45 typedef HANDLE Handle;
46 static void CloseHandle(HANDLE handle) { GlobalFree(handle); }
47 static bool IsHandleValid(HANDLE handle) { return handle != nullptr; }
48 static HANDLE NullHandle() { return nullptr; }
51 using ScopedGlobalAlloc =
52 base::win::GenericScopedHandle<FreeHandleTraits,
53 base::win::DummyVerifierTraits>;
57 class MockPrintingContextWin : public PrintingContextSystemDialogWin {
59 explicit MockPrintingContextWin(Delegate* delegate)
60 : PrintingContextSystemDialogWin(delegate) {}
63 // This is a fake PrintDlgEx implementation that sets the right fields in
64 // |lppd| to trigger a bug in older revisions of PrintingContext.
65 HRESULT ShowPrintDialog(PRINTDLGEX* lppd) override {
66 // The interesting bits:
67 // Pretend the user hit print
68 lppd->dwResultAction = PD_RESULT_PRINT;
70 // Pretend the page range is 1-5, but since lppd->Flags does not have
71 // PD_SELECTION set, this really shouldn't matter.
72 lppd->nPageRanges = 1;
73 lppd->lpPageRanges[0].nFromPage = 1;
74 lppd->lpPageRanges[0].nToPage = 5;
76 base::string16 printer_name = PrintingContextTest::GetDefaultPrinter();
77 ScopedPrinterHandle printer;
78 if (!printer.OpenPrinter(printer_name.c_str()))
81 const DEVMODE* dev_mode = nullptr;
83 lppd->hDevMode = nullptr;
84 lppd->hDevNames = nullptr;
87 if (info_2.Init(printer.Get()))
88 dev_mode = info_2.get()->pDevMode;
92 base::win::ScopedCreateDC hdc(
93 CreateDC(L"WINSPOOL", printer_name.c_str(), nullptr, dev_mode));
97 size_t dev_mode_size = dev_mode->dmSize + dev_mode->dmDriverExtra;
98 ScopedGlobalAlloc dev_mode_mem(GlobalAlloc(GMEM_MOVEABLE, dev_mode_size));
99 if (!dev_mode_mem.Get())
101 void* dev_mode_ptr = GlobalLock(dev_mode_mem.Get());
104 memcpy(dev_mode_ptr, dev_mode, dev_mode_size);
105 GlobalUnlock(dev_mode_mem.Get());
106 dev_mode_ptr = nullptr;
109 2 + sizeof(wchar_t) * lstrlen(info_2.get()->pDriverName);
110 size_t printer_size =
111 2 + sizeof(wchar_t) * lstrlen(info_2.get()->pPrinterName);
112 size_t port_size = 2 + sizeof(wchar_t) * lstrlen(info_2.get()->pPortName);
113 size_t dev_names_size =
114 sizeof(DEVNAMES) + driver_size + printer_size + port_size;
115 ScopedGlobalAlloc dev_names_mem(GlobalAlloc(GHND, dev_names_size));
116 if (!dev_names_mem.Get())
118 void* dev_names_ptr = GlobalLock(dev_names_mem.Get());
121 DEVNAMES* dev_names = reinterpret_cast<DEVNAMES*>(dev_names_ptr);
122 dev_names->wDefault = 1;
123 dev_names->wDriverOffset = sizeof(DEVNAMES) / sizeof(wchar_t);
124 memcpy(reinterpret_cast<uint8_t*>(dev_names_ptr) + dev_names->wDriverOffset,
125 info_2.get()->pDriverName, driver_size);
126 dev_names->wDeviceOffset = base::checked_cast<WORD>(
127 dev_names->wDriverOffset + driver_size / sizeof(wchar_t));
128 memcpy(reinterpret_cast<uint8_t*>(dev_names_ptr) + dev_names->wDeviceOffset,
129 info_2.get()->pPrinterName, printer_size);
130 dev_names->wOutputOffset = base::checked_cast<WORD>(
131 dev_names->wDeviceOffset + printer_size / sizeof(wchar_t));
132 memcpy(reinterpret_cast<uint8_t*>(dev_names_ptr) + dev_names->wOutputOffset,
133 info_2.get()->pPortName, port_size);
134 GlobalUnlock(dev_names_mem.Get());
135 dev_names_ptr = nullptr;
137 lppd->hDC = hdc.Take();
138 lppd->hDevMode = dev_mode_mem.Take();
139 lppd->hDevNames = dev_names_mem.Take();
144 TEST_F(PrintingContextTest, PrintAll) {
145 if (IsTestCaseDisabled())
148 base::MessageLoop message_loop;
149 MockPrintingContextWin context(this);
150 context.AskUserForSettings(
152 base::BindOnce(&PrintingContextTest::PrintSettingsCallback,
153 base::Unretained(this)));
154 EXPECT_EQ(PrintingContext::OK, result());
155 const PrintSettings& settings = context.settings();
156 EXPECT_EQ(0u, settings.ranges().size());
159 TEST_F(PrintingContextTest, Color) {
160 if (IsTestCaseDisabled())
163 base::MessageLoop message_loop;
164 MockPrintingContextWin context(this);
165 context.AskUserForSettings(
167 base::BindOnce(&PrintingContextTest::PrintSettingsCallback,
168 base::Unretained(this)));
169 EXPECT_EQ(PrintingContext::OK, result());
170 const PrintSettings& settings = context.settings();
171 EXPECT_NE(settings.color(), UNKNOWN_COLOR_MODEL);
174 TEST_F(PrintingContextTest, Base) {
175 if (IsTestCaseDisabled())
178 PrintSettings settings;
179 settings.set_device_name(GetDefaultPrinter());
181 PrintingContextWin context(this);
182 EXPECT_EQ(PrintingContext::OK, context.InitWithSettingsForTest(settings));
184 // The print may lie to use and may not support world transformation.
186 XFORM random_matrix = { 1, 0.1f, 0, 1.5f, 0, 1 };
187 EXPECT_TRUE(SetWorldTransform(context.context(), &random_matrix));
188 EXPECT_TRUE(ModifyWorldTransform(context.context(), nullptr, MWT_IDENTITY));
191 } // namespace printing