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