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

Side by Side Diff: chrome/browser/printing/printing_layout_browsertest.cc

Issue 2812263002: clean up printing::Image and printing::Metafile (Closed)
Patch Set: definition matches declaration Created 3 years, 8 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
« no previous file with comments | « no previous file | chrome/service/cloud_print/print_system_win.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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 "base/command_line.h"
6 #include "base/files/file_enumerator.h"
7 #include "base/files/file_path.h"
8 #include "base/files/file_util.h"
9 #include "base/location.h"
10 #include "base/macros.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/path_service.h"
13 #include "base/process/process_handle.h"
14 #include "base/single_thread_task_runner.h"
15 #include "base/strings/string_util.h"
16 #include "base/strings/utf_string_conversions.h"
17 #include "base/test/test_file_util.h"
18 #include "base/threading/simple_thread.h"
19 #include "base/threading/thread_task_runner_handle.h"
20 #include "chrome/browser/chrome_notification_types.h"
21 #include "chrome/browser/printing/print_job.h"
22 #include "chrome/browser/printing/print_view_manager.h"
23 #include "chrome/browser/ui/browser.h"
24 #include "chrome/browser/ui/browser_commands.h"
25 #include "chrome/browser/ui/tabs/tab_strip_model.h"
26 #include "chrome/common/chrome_paths.h"
27 #include "chrome/common/chrome_switches.h"
28 #include "chrome/test/base/in_process_browser_test.h"
29 #include "chrome/test/base/ui_test_utils.h"
30 #include "content/public/browser/notification_observer.h"
31 #include "content/public/browser/notification_registrar.h"
32 #include "content/public/browser/notification_service.h"
33 #include "net/test/embedded_test_server/embedded_test_server.h"
34 #include "printing/image.h"
35 #include "printing/printing_test.h"
36
37 namespace {
38
39 using printing::Image;
40
41 const char kGenerateSwitch[] = "print-layout-generate";
42
43 class PrintingLayoutTest : public PrintingTest<InProcessBrowserTest>,
44 public content::NotificationObserver {
45 public:
46 PrintingLayoutTest() {
47 base::FilePath browser_directory;
48 PathService::Get(chrome::DIR_APP, &browser_directory);
49 emf_path_ = browser_directory.AppendASCII("metafile_dumps");
50 }
51
52 void SetUp() override {
53 // Make sure there is no left overs.
54 CleanupDumpDirectory();
55 InProcessBrowserTest::SetUp();
56 }
57
58 void TearDown() override {
59 InProcessBrowserTest::TearDown();
60 base::DeleteFile(emf_path_, true);
61 }
62
63 void SetUpCommandLine(base::CommandLine* command_line) override {
64 command_line->AppendSwitchPath(switches::kDebugPrint, emf_path_);
65 }
66
67 protected:
68 void PrintNowTab() {
69 registrar_.Add(this, chrome::NOTIFICATION_PRINT_JOB_EVENT,
70 content::NotificationService::AllSources());
71
72 content::WebContents* web_contents =
73 browser()->tab_strip_model()->GetActiveWebContents();
74 printing::PrintViewManager::FromWebContents(web_contents)->PrintNow();
75 content::RunMessageLoop();
76 registrar_.RemoveAll();
77 }
78
79 virtual void Observe(int type,
80 const content::NotificationSource& source,
81 const content::NotificationDetails& details) {
82 ASSERT_EQ(chrome::NOTIFICATION_PRINT_JOB_EVENT, type);
83 switch (content::Details<printing::JobEventDetails>(details)->type()) {
84 case printing::JobEventDetails::JOB_DONE: {
85 // Succeeded.
86 base::ThreadTaskRunnerHandle::Get()->PostTask(
87 FROM_HERE, base::MessageLoop::QuitWhenIdleClosure());
88 break;
89 }
90 case printing::JobEventDetails::USER_INIT_CANCELED:
91 case printing::JobEventDetails::FAILED: {
92 // Failed.
93 ASSERT_TRUE(false);
94 base::ThreadTaskRunnerHandle::Get()->PostTask(
95 FROM_HERE, base::MessageLoop::QuitWhenIdleClosure());
96 break;
97 }
98 case printing::JobEventDetails::NEW_DOC:
99 case printing::JobEventDetails::USER_INIT_DONE:
100 case printing::JobEventDetails::DEFAULT_INIT_DONE:
101 case printing::JobEventDetails::NEW_PAGE:
102 case printing::JobEventDetails::PAGE_DONE:
103 case printing::JobEventDetails::DOC_DONE:
104 case printing::JobEventDetails::ALL_PAGES_REQUESTED: {
105 // Don't care.
106 break;
107 }
108 default: {
109 NOTREACHED();
110 break;
111 }
112 }
113 }
114
115 // Finds the dump for the last print job and compares it to the data named
116 // |verification_name|. Compares the saved printed job pixels with the test
117 // data pixels and returns the percentage of different pixels; 0 for success,
118 // [0, 100] for failure.
119 double CompareWithResult(const std::wstring& verification_name) {
120 base::FilePath test_result(ScanFiles(verification_name));
121 if (test_result.value().empty()) {
122 // 100% different, the print job buffer is not there.
123 return 100.;
124 }
125
126 base::FilePath base_path(ui_test_utils::GetTestFilePath(
127 base::FilePath().AppendASCII("printing"), base::FilePath()));
128 base::FilePath emf(base_path.Append(verification_name + L".emf"));
129 base::FilePath png(base_path.Append(verification_name + L".png"));
130
131 base::FilePath cleartype(
132 base_path.Append(verification_name + L"_cleartype.png"));
133 // Looks for Cleartype override.
134 if (base::PathExists(cleartype) && IsClearTypeEnabled())
135 png = cleartype;
136
137 if (GenerateFiles()) {
138 // Copy the .emf and generate an .png.
139 base::CopyFile(test_result, emf);
140 Image emf_content(emf);
141 emf_content.SaveToPng(png);
142 // Saving is always fine.
143 return 0;
144 } else {
145 // File compare between test and result.
146 Image emf_content(emf);
147 Image test_content(test_result);
148 Image png_content(png);
149 double diff_emf = emf_content.PercentageDifferent(test_content);
150
151 EXPECT_EQ(0., diff_emf) << base::WideToUTF8(verification_name) <<
152 " original size:" << emf_content.size().ToString() <<
153 " result size:" << test_content.size().ToString();
154 if (diff_emf) {
155 // Backup the result emf file.
156 base::FilePath failed(
157 base_path.Append(verification_name + L"_failed.emf"));
158 base::CopyFile(test_result, failed);
159 }
160
161 // This verification is only to know that the EMF rendering stays
162 // immutable.
163 double diff_png = emf_content.PercentageDifferent(png_content);
164 EXPECT_EQ(0., diff_png) << base::WideToUTF8(verification_name) <<
165 " original size:" << emf_content.size().ToString() <<
166 " result size:" << test_content.size().ToString();
167 if (diff_png) {
168 // Backup the rendered emf file to detect the rendering difference.
169 base::FilePath rendering(
170 base_path.Append(verification_name + L"_rendering.png"));
171 emf_content.SaveToPng(rendering);
172 }
173 return std::max(diff_png, diff_emf);
174 }
175 }
176
177 // Makes sure the directory exists and is empty.
178 void CleanupDumpDirectory() {
179 EXPECT_TRUE(base::DieFileDie(emf_path_, true));
180 EXPECT_TRUE(base::CreateDirectory(emf_path_));
181 }
182
183 // Returns if Clear Type is currently enabled.
184 static bool IsClearTypeEnabled() {
185 BOOL ct_enabled = 0;
186 if (SystemParametersInfo(SPI_GETCLEARTYPE, 0, &ct_enabled, 0) && ct_enabled)
187 return true;
188 UINT smoothing = 0;
189 if (SystemParametersInfo(SPI_GETFONTSMOOTHINGTYPE, 0, &smoothing, 0) &&
190 smoothing == FE_FONTSMOOTHINGCLEARTYPE)
191 return true;
192 return false;
193 }
194
195 private:
196 // Verifies that there is one .emf and one .prn file in the dump directory.
197 // Returns the path of the .emf file and deletes the .prn file.
198 std::wstring ScanFiles(const std::wstring& verification_name) {
199 // Try to 10 seconds.
200 std::wstring emf_file;
201 std::wstring prn_file;
202 bool found_emf = false;
203 bool found_prn = false;
204 for (int i = 0; i < 100; ++i) {
205 base::FileEnumerator enumerator(emf_path_, false,
206 base::FileEnumerator::FILES);
207 emf_file.clear();
208 prn_file.clear();
209 found_emf = false;
210 found_prn = false;
211 base::FilePath file;
212 while (!(file = enumerator.Next()).empty()) {
213 std::wstring ext = file.Extension();
214 if (base::EqualsCaseInsensitiveASCII(base::WideToUTF8(ext), ".emf")) {
215 EXPECT_FALSE(found_emf) << "Found a leftover .EMF file: \"" <<
216 emf_file << "\" and \"" << file.value() <<
217 "\" when looking for \"" << verification_name << "\"";
218 found_emf = true;
219 emf_file = file.value();
220 continue;
221 }
222 if (base::EqualsCaseInsensitiveASCII(base::WideToUTF8(ext), ".prn")) {
223 EXPECT_FALSE(found_prn) << "Found a leftover .PRN file: \"" <<
224 prn_file << "\" and \"" << file.value() <<
225 "\" when looking for \"" << verification_name << "\"";
226 prn_file = file.value();
227 found_prn = true;
228 base::DeleteFile(file, false);
229 continue;
230 }
231 EXPECT_TRUE(false);
232 }
233 if (found_emf && found_prn)
234 break;
235 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100));
236 }
237 EXPECT_TRUE(found_emf) << ".PRN file is: " << prn_file;
238 EXPECT_TRUE(found_prn) << ".EMF file is: " << emf_file;
239 return emf_file;
240 }
241
242 static bool GenerateFiles() {
243 return base::CommandLine::ForCurrentProcess()->HasSwitch(kGenerateSwitch);
244 }
245
246 base::FilePath emf_path_;
247 content::NotificationRegistrar registrar_;
248
249 DISALLOW_COPY_AND_ASSIGN(PrintingLayoutTest);
250 };
251
252 class PrintingLayoutTextTest : public PrintingLayoutTest {
253 typedef PrintingLayoutTest Parent;
254 public:
255 // Returns if the test is disabled.
256 // http://crbug.com/64869 Until the issue is fixed, disable the test if
257 // ClearType is enabled.
258 static bool IsTestCaseDisabled() {
259 return Parent::IsTestCaseDisabled() || IsClearTypeEnabled();
260 }
261 };
262
263 // Finds the first dialog window owned by owner_process.
264 HWND FindDialogWindow(DWORD owner_process) {
265 HWND dialog_window(NULL);
266 for (;;) {
267 dialog_window = FindWindowEx(NULL,
268 dialog_window,
269 MAKEINTATOM(32770),
270 NULL);
271 if (!dialog_window)
272 break;
273
274 // The dialog must be owned by our target process.
275 DWORD process_id = 0;
276 GetWindowThreadProcessId(dialog_window, &process_id);
277 if (process_id == owner_process)
278 break;
279 }
280 return dialog_window;
281 }
282
283 // Tries to close a dialog window.
284 bool CloseDialogWindow(HWND dialog_window) {
285 LRESULT res = SendMessage(dialog_window, DM_GETDEFID, 0, 0);
286 if (!res)
287 return false;
288 EXPECT_EQ(DC_HASDEFID, HIWORD(res));
289 WORD print_button_id = LOWORD(res);
290 res = SendMessage(
291 dialog_window,
292 WM_COMMAND,
293 print_button_id,
294 reinterpret_cast<LPARAM>(GetDlgItem(dialog_window, print_button_id)));
295 return res == 0;
296 }
297
298 // Dismiss the first dialog box owned by owner_process by "executing" the
299 // default button.
300 class DismissTheWindow : public base::DelegateSimpleThread::Delegate {
301 public:
302 DismissTheWindow()
303 : owner_process_(base::GetCurrentProcId()) {
304 }
305
306 virtual void Run() {
307 HWND dialog_window;
308 for (;;) {
309 // First enumerate the windows.
310 dialog_window = FindDialogWindow(owner_process_);
311
312 // Try to close it.
313 if (dialog_window) {
314 if (CloseDialogWindow(dialog_window)) {
315 break;
316 }
317 }
318 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(10));
319 }
320
321 // Now verify that it indeed closed itself.
322 while (IsWindow(dialog_window)) {
323 CloseDialogWindow(dialog_window);
324 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(10));
325 }
326 }
327
328 DWORD owner_process() { return owner_process_; }
329
330 private:
331 DWORD owner_process_;
332 };
333
334 } // namespace
335
336 // Fails, see http://crbug.com/7721.
337 IN_PROC_BROWSER_TEST_F(PrintingLayoutTextTest, DISABLED_Complex) {
338 if (IsTestCaseDisabled())
339 return;
340
341 DismissTheWindow dismisser;
342 base::DelegateSimpleThread close_printdlg_thread(&dismisser,
343 "close_printdlg_thread");
344
345 // Print a document, check its output.
346 ASSERT_TRUE(embedded_test_server()->Start());
347
348 ui_test_utils::NavigateToURL(
349 browser(), embedded_test_server()->GetURL("/printing/test1.html"));
350 close_printdlg_thread.Start();
351 PrintNowTab();
352 close_printdlg_thread.Join();
353 EXPECT_EQ(0., CompareWithResult(L"test1"));
354 }
355
356 struct TestPool {
357 const char* source;
358 const wchar_t* result;
359 };
360
361 const TestPool kTestPool[] = {
362 // ImagesB&W
363 "/printing/test2.html", L"test2",
364 // ImagesTransparent
365 "/printing/test3.html", L"test3",
366 // ImageColor
367 "/printing/test4.html", L"test4",
368 };
369
370 // http://crbug.com/7721
371 IN_PROC_BROWSER_TEST_F(PrintingLayoutTest, DISABLED_ManyTimes) {
372 if (IsTestCaseDisabled())
373 return;
374
375 ASSERT_TRUE(embedded_test_server()->Start());
376
377 DismissTheWindow dismisser;
378
379 ASSERT_GT(arraysize(kTestPool), 0u);
380 for (int i = 0; i < arraysize(kTestPool); ++i) {
381 if (i)
382 CleanupDumpDirectory();
383 const TestPool& test = kTestPool[i % arraysize(kTestPool)];
384 ui_test_utils::NavigateToURL(browser(),
385 embedded_test_server()->GetURL(test.source));
386 base::DelegateSimpleThread close_printdlg_thread1(&dismisser,
387 "close_printdlg_thread");
388 EXPECT_EQ(NULL, FindDialogWindow(dismisser.owner_process()));
389 close_printdlg_thread1.Start();
390 PrintNowTab();
391 close_printdlg_thread1.Join();
392 EXPECT_EQ(0., CompareWithResult(test.result)) << test.result;
393 CleanupDumpDirectory();
394 base::DelegateSimpleThread close_printdlg_thread2(&dismisser,
395 "close_printdlg_thread");
396 EXPECT_EQ(NULL, FindDialogWindow(dismisser.owner_process()));
397 close_printdlg_thread2.Start();
398 PrintNowTab();
399 close_printdlg_thread2.Join();
400 EXPECT_EQ(0., CompareWithResult(test.result)) << test.result;
401 CleanupDumpDirectory();
402 base::DelegateSimpleThread close_printdlg_thread3(&dismisser,
403 "close_printdlg_thread");
404 EXPECT_EQ(NULL, FindDialogWindow(dismisser.owner_process()));
405 close_printdlg_thread3.Start();
406 PrintNowTab();
407 close_printdlg_thread3.Join();
408 EXPECT_EQ(0., CompareWithResult(test.result)) << test.result;
409 CleanupDumpDirectory();
410 base::DelegateSimpleThread close_printdlg_thread4(&dismisser,
411 "close_printdlg_thread");
412 EXPECT_EQ(NULL, FindDialogWindow(dismisser.owner_process()));
413 close_printdlg_thread4.Start();
414 PrintNowTab();
415 close_printdlg_thread4.Join();
416 EXPECT_EQ(0., CompareWithResult(test.result)) << test.result;
417 }
418 }
419
420 // Prints a popup and immediately closes it. Disabled because it crashes.
421 IN_PROC_BROWSER_TEST_F(PrintingLayoutTest, DISABLED_Delayed) {
422 if (IsTestCaseDisabled())
423 return;
424
425 ASSERT_TRUE(embedded_test_server()->Start());
426
427 {
428 bool is_timeout = true;
429 GURL url =
430 embedded_test_server()->GetURL("/printing/popup_delayed_print.htm");
431 ui_test_utils::NavigateToURL(browser(), url);
432
433 DismissTheWindow dismisser;
434 base::DelegateSimpleThread close_printdlg_thread(&dismisser,
435 "close_printdlg_thread");
436 close_printdlg_thread.Start();
437 close_printdlg_thread.Join();
438
439 // Force a navigation elsewhere to verify that it's fine with it.
440 url = embedded_test_server()->GetURL("/printing/test1.html");
441 ui_test_utils::NavigateToURL(browser(), url);
442 }
443 chrome::CloseWindow(browser());
444 content::RunAllPendingInMessageLoop();
445
446 EXPECT_EQ(0., CompareWithResult(L"popup_delayed_print"))
447 << L"popup_delayed_print";
448 }
449
450 // Prints a popup and immediately closes it. http://crbug.com/7721
451 IN_PROC_BROWSER_TEST_F(PrintingLayoutTest, DISABLED_IFrame) {
452 if (IsTestCaseDisabled())
453 return;
454
455 ASSERT_TRUE(embedded_test_server()->Start());
456
457 {
458 GURL url = embedded_test_server()->GetURL("/printing/iframe.htm");
459 ui_test_utils::NavigateToURL(browser(), url);
460
461 DismissTheWindow dismisser;
462 base::DelegateSimpleThread close_printdlg_thread(&dismisser,
463 "close_printdlg_thread");
464 close_printdlg_thread.Start();
465 close_printdlg_thread.Join();
466
467 // Force a navigation elsewhere to verify that it's fine with it.
468 url = embedded_test_server()->GetURL("/printing/test1.html");
469 ui_test_utils::NavigateToURL(browser(), url);
470 }
471 chrome::CloseWindow(browser());
472 content::RunAllPendingInMessageLoop();
473
474 EXPECT_EQ(0., CompareWithResult(L"iframe")) << L"iframe";
475 }
OLDNEW
« no previous file with comments | « no previous file | chrome/service/cloud_print/print_system_win.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698