OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #include "base/file_util.h" | |
6 #include "base/path_service.h" | |
7 #include "base/string_number_conversions.h" | |
8 #include "base/string_util.h" | |
9 #include "base/utf_string_conversions.h" | |
10 #include "chrome/browser/ui/browser.h" | |
11 #include "chrome/browser/ui/browser_window.h" | |
12 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" | |
13 #include "chrome/browser/ui/window_sizer.h" | |
14 #include "chrome/common/chrome_notification_types.h" | |
15 #include "chrome/common/chrome_paths.h" | |
16 #include "chrome/test/base/in_process_browser_test.h" | |
17 #include "chrome/test/base/ui_test_utils.h" | |
18 #include "content/browser/renderer_host/render_view_host.h" | |
19 #include "content/browser/tab_contents/tab_contents.h" | |
20 #include "content/common/notification_observer.h" | |
21 #include "net/test/test_server.h" | |
22 #include "ui/base/clipboard/clipboard.h" | |
23 #include "ui/gfx/codec/png_codec.h" | |
24 | |
25 namespace { | |
26 | |
27 // Include things like browser frame and scrollbar and make sure we're bigger | |
28 // than the test pdf document. | |
29 static const int kBrowserWidth = 1000; | |
30 static const int kBrowserHeight = 600; | |
31 | |
32 class PDFBrowserTest : public InProcessBrowserTest, | |
33 public NotificationObserver { | |
34 public: | |
35 PDFBrowserTest() | |
36 : snapshot_different_(true), | |
37 next_dummy_search_value_(0), | |
38 load_stop_notification_count_(0) { | |
39 EnableDOMAutomation(); | |
40 | |
41 pdf_test_server_.reset(new net::TestServer( | |
42 net::TestServer::TYPE_HTTP, | |
43 FilePath(FILE_PATH_LITERAL("pdf/test")))); | |
44 } | |
45 | |
46 protected: | |
47 // Use our own TestServer so that we can serve files from the pdf directory. | |
48 net::TestServer* pdf_test_server() { return pdf_test_server_.get(); } | |
49 | |
50 int load_stop_notification_count() const { | |
51 return load_stop_notification_count_; | |
52 } | |
53 | |
54 FilePath GetPDFTestDir() { | |
55 return FilePath(FilePath::kCurrentDirectory).AppendASCII(".."). | |
56 AppendASCII("..").AppendASCII("..").AppendASCII("pdf"). | |
57 AppendASCII("test"); | |
58 } | |
59 | |
60 void Load() { | |
61 // Make sure to set the window size before rendering, as otherwise rendering | |
62 // to a smaller window and then expanding leads to slight anti-aliasing | |
63 // differences of the text and the pixel comparison fails. | |
64 gfx::Rect bounds(gfx::Rect(0, 0, kBrowserWidth, kBrowserHeight)); | |
65 scoped_ptr<WindowSizer::MonitorInfoProvider> monitor_info( | |
66 WindowSizer::CreateDefaultMonitorInfoProvider()); | |
67 gfx::Rect screen_bounds = monitor_info->GetPrimaryMonitorBounds(); | |
68 ASSERT_GT(screen_bounds.width(), kBrowserWidth); | |
69 ASSERT_GT(screen_bounds.height(), kBrowserHeight); | |
70 browser()->window()->SetBounds(bounds); | |
71 | |
72 GURL url(ui_test_utils::GetTestUrl( | |
73 GetPDFTestDir(), | |
74 FilePath(FILE_PATH_LITERAL("pdf_browsertest.pdf")))); | |
75 ui_test_utils::NavigateToURL(browser(), url); | |
76 } | |
77 | |
78 void VerifySnapshot(const std::string& expected_filename) { | |
79 snapshot_different_ = true; | |
80 expected_filename_ = expected_filename; | |
81 TabContentsWrapper* wrapper = browser()->GetSelectedTabContentsWrapper(); | |
82 wrapper->CaptureSnapshot(); | |
83 ui_test_utils::RegisterAndWait(this, | |
84 chrome::NOTIFICATION_TAB_SNAPSHOT_TAKEN, | |
85 Source<TabContentsWrapper>(wrapper)); | |
86 ASSERT_FALSE(snapshot_different_) << "Rendering didn't match, see result " | |
87 "at " << snapshot_filename_.value().c_str(); | |
88 } | |
89 | |
90 void WaitForResponse() { | |
91 // Even if the plugin has loaded the data or scrolled, because of how | |
92 // pepper painting works, we might not have the data. One way to force this | |
93 // to be flushed is to do a find operation, since on this two-page test | |
94 // document, it'll wait for us to flush the renderer message loop twice and | |
95 // also the browser's once, at which point we're guaranteed to have updated | |
96 // the backingstore. Hacky, but it works. | |
97 // Note that we need to change the text each time, because if we don't the | |
98 // renderer code will think the second message is to go to next result, but | |
99 // there are none so the plugin will assert. | |
100 | |
101 string16 query = UTF8ToUTF16( | |
102 std::string("xyzxyz" + base::IntToString(next_dummy_search_value_++))); | |
103 ASSERT_EQ(0, ui_test_utils::FindInPage( | |
104 browser()->GetSelectedTabContentsWrapper(), query, true, false, NULL)); | |
105 } | |
106 | |
107 private: | |
108 // NotificationObserver | |
109 virtual void Observe(int type, | |
110 const NotificationSource& source, | |
111 const NotificationDetails& details) { | |
112 if (type == chrome::NOTIFICATION_TAB_SNAPSHOT_TAKEN) { | |
113 MessageLoopForUI::current()->Quit(); | |
114 FilePath reference = ui_test_utils::GetTestFilePath( | |
115 GetPDFTestDir(), | |
116 FilePath().AppendASCII(expected_filename_)); | |
117 base::PlatformFileInfo info; | |
118 ASSERT_TRUE(file_util::GetFileInfo(reference, &info)); | |
119 int size = static_cast<size_t>(info.size); | |
120 scoped_array<char> data(new char[size]); | |
121 ASSERT_EQ(size, file_util::ReadFile(reference, data.get(), size)); | |
122 | |
123 int w, h; | |
124 std::vector<unsigned char> decoded; | |
125 ASSERT_TRUE(gfx::PNGCodec::Decode( | |
126 reinterpret_cast<unsigned char*>(data.get()), size, | |
127 gfx::PNGCodec::FORMAT_BGRA, &decoded, &w, &h)); | |
128 int32* ref_pixels = reinterpret_cast<int32*>(&decoded[0]); | |
129 | |
130 const SkBitmap* bitmap = Details<const SkBitmap>(details).ptr(); | |
131 int32* pixels = static_cast<int32*>(bitmap->getPixels()); | |
132 | |
133 // Get the background color, and use it to figure out the x-offsets in | |
134 // each image. The reason is that depending on the theme in the OS, the | |
135 // same browser width can lead to slightly different plugin sizes, so the | |
136 // pdf content will start at different x offsets. | |
137 // Also note that the images we saved are cut off before the scrollbar, as | |
138 // that'll change depending on the theme, and also cut off vertically so | |
139 // that the ui controls don't show up, as those fade-in and so the timing | |
140 // will affect their transparency. | |
141 int32 bg_color = ref_pixels[0]; | |
142 int ref_x_offset, snapshot_x_offset; | |
143 for (ref_x_offset = 0; ref_x_offset < w; ++ref_x_offset) { | |
144 if (ref_pixels[ref_x_offset] != bg_color) | |
145 break; | |
146 } | |
147 | |
148 for (snapshot_x_offset = 0; snapshot_x_offset < bitmap->width(); | |
149 ++snapshot_x_offset) { | |
150 if (pixels[snapshot_x_offset] != bg_color) | |
151 break; | |
152 } | |
153 | |
154 int x_max = std::min( | |
155 w - ref_x_offset, bitmap->width() - snapshot_x_offset); | |
156 int y_max = std::min(h, bitmap->height()); | |
157 int stride = bitmap->rowBytes(); | |
158 snapshot_different_ = false; | |
159 for (int y = 0; y < y_max && !snapshot_different_; ++y) { | |
160 for (int x = 0; x < x_max && !snapshot_different_; ++x) { | |
161 if (pixels[y * stride / sizeof(int32) + x + snapshot_x_offset] != | |
162 ref_pixels[y * w + x + ref_x_offset]) | |
163 snapshot_different_ = true; | |
164 } | |
165 } | |
166 | |
167 if (snapshot_different_) { | |
168 std::vector<unsigned char> png_data; | |
169 gfx::PNGCodec::EncodeBGRASkBitmap(*bitmap, false, &png_data); | |
170 if (file_util::CreateTemporaryFile(&snapshot_filename_)) { | |
171 file_util::WriteFile(snapshot_filename_, | |
172 reinterpret_cast<char*>(&png_data[0]), png_data.size()); | |
173 } | |
174 } | |
175 } else if (type == content::NOTIFICATION_LOAD_STOP) { | |
176 load_stop_notification_count_++; | |
177 } | |
178 } | |
179 | |
180 // True if the snapshot differed from the expected value. | |
181 bool snapshot_different_; | |
182 // Internal variable used to synchronize to the renderer. | |
183 int next_dummy_search_value_; | |
184 // The filename of the bitmap to compare the snapshot to. | |
185 std::string expected_filename_; | |
186 // If the snapshot is different, holds the location where it's saved. | |
187 FilePath snapshot_filename_; | |
188 // How many times we've seen chrome::LOAD_STOP. | |
189 int load_stop_notification_count_; | |
190 | |
191 scoped_ptr<net::TestServer> pdf_test_server_; | |
192 }; | |
193 | |
194 #if defined(OS_CHROMEOS) | |
195 // TODO(sanjeevr): http://crbug.com/79837 | |
196 #define MAYBE_Basic DISABLED_Basic | |
197 #else | |
198 #define MAYBE_Basic Basic | |
199 #endif | |
200 // Tests basic PDF rendering. This can be broken depending on bad merges with | |
201 // the vendor, so it's important that we have basic sanity checking. | |
202 IN_PROC_BROWSER_TEST_F(PDFBrowserTest, MAYBE_Basic) { | |
203 ASSERT_NO_FATAL_FAILURE(Load()); | |
204 ASSERT_NO_FATAL_FAILURE(WaitForResponse()); | |
205 ASSERT_NO_FATAL_FAILURE(VerifySnapshot("pdf_browsertest.png")); | |
206 } | |
207 | |
208 #if defined(OS_CHROMEOS) | |
209 // TODO(sanjeevr): http://crbug.com/79837 | |
210 #define MAYBE_Scroll DISABLED_Scroll | |
211 #else | |
212 #define MAYBE_Scroll Scroll | |
213 #endif | |
214 // Tests that scrolling works. | |
215 IN_PROC_BROWSER_TEST_F(PDFBrowserTest, MAYBE_Scroll) { | |
216 ASSERT_NO_FATAL_FAILURE(Load()); | |
217 | |
218 // We use wheel mouse event since that's the only one we can easily push to | |
219 // the renderer. There's no way to push a cross-platform keyboard event at | |
220 // the moment. | |
221 WebKit::WebMouseWheelEvent wheel_event; | |
222 wheel_event.type = WebKit::WebInputEvent::MouseWheel; | |
223 wheel_event.deltaY = -200; | |
224 wheel_event.wheelTicksY = -2; | |
225 TabContents* tab_contents = browser()->GetSelectedTabContents(); | |
226 tab_contents->render_view_host()->ForwardWheelEvent(wheel_event); | |
227 ASSERT_NO_FATAL_FAILURE(WaitForResponse()); | |
228 | |
229 int y_offset = 0; | |
230 ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractInt( | |
231 browser()->GetSelectedTabContents()->render_view_host(), | |
232 std::wstring(), | |
233 L"window.domAutomationController.send(plugin.pageYOffset())", | |
234 &y_offset)); | |
235 ASSERT_GT(y_offset, 0); | |
236 } | |
237 | |
238 #if defined(OS_CHROMEOS) | |
239 // TODO(sanjeevr): http://crbug.com/79837 | |
240 #define MAYBE_FindAndCopy DISABLED_FindAndCopy | |
241 #else | |
242 #define MAYBE_FindAndCopy FindAndCopy | |
243 #endif | |
244 IN_PROC_BROWSER_TEST_F(PDFBrowserTest, MAYBE_FindAndCopy) { | |
245 ASSERT_NO_FATAL_FAILURE(Load()); | |
246 // Verifies that find in page works. | |
247 ASSERT_EQ(3, ui_test_utils::FindInPage( | |
248 browser()->GetSelectedTabContentsWrapper(), UTF8ToUTF16("adipiscing"), | |
249 true, false, NULL)); | |
250 | |
251 // Verify that copying selected text works. | |
252 ui::Clipboard clipboard; | |
253 // Reset the clipboard first. | |
254 ui::Clipboard::ObjectMap objects; | |
255 ui::Clipboard::ObjectMapParams params; | |
256 params.push_back(std::vector<char>()); | |
257 objects[ui::Clipboard::CBF_TEXT] = params; | |
258 clipboard.WriteObjects(objects); | |
259 | |
260 browser()->GetSelectedTabContents()->render_view_host()->Copy(); | |
261 ASSERT_NO_FATAL_FAILURE(WaitForResponse()); | |
262 | |
263 std::string text; | |
264 clipboard.ReadAsciiText(ui::Clipboard::BUFFER_STANDARD, &text); | |
265 ASSERT_EQ("adipiscing", text); | |
266 } | |
267 | |
268 // Tests that loading async pdfs works correctly (i.e. document fully loads). | |
269 // This also loads all documents that used to crash, to ensure we don't have | |
270 // regressions. | |
271 // Flaky as per http://crbug.com/74548. | |
272 IN_PROC_BROWSER_TEST_F(PDFBrowserTest, FLAKY_SLOW_Loading) { | |
273 ASSERT_TRUE(pdf_test_server()->Start()); | |
274 | |
275 NavigationController* controller = | |
276 &(browser()->GetSelectedTabContents()->controller()); | |
277 NotificationRegistrar registrar; | |
278 registrar.Add(this, | |
279 content::NOTIFICATION_LOAD_STOP, | |
280 Source<NavigationController>(controller)); | |
281 std::string base_url = std::string("files/"); | |
282 | |
283 file_util::FileEnumerator file_enumerator( | |
284 ui_test_utils::GetTestFilePath(GetPDFTestDir(), FilePath()), | |
285 false, | |
286 file_util::FileEnumerator::FILES, | |
287 FILE_PATH_LITERAL("*.pdf")); | |
288 for (FilePath file_path = file_enumerator.Next(); | |
289 !file_path.empty(); | |
290 file_path = file_enumerator.Next()) { | |
291 std::string filename = file_path.BaseName().MaybeAsASCII(); | |
292 ASSERT_FALSE(filename.empty()); | |
293 | |
294 #if defined(OS_POSIX) | |
295 if (filename == "sample.pdf") | |
296 continue; // Crashes on Mac and Linux. http://crbug.com/63549 | |
297 #endif | |
298 | |
299 LOG(WARNING) << "PDFBrowserTest.Loading: " << filename; | |
300 | |
301 GURL url = pdf_test_server()->GetURL(base_url + filename); | |
302 ui_test_utils::NavigateToURL(browser(), url); | |
303 | |
304 while (true) { | |
305 int last_count = load_stop_notification_count(); | |
306 // We might get extraneous chrome::LOAD_STOP notifications when | |
307 // doing async loading. This happens when the first loader is cancelled | |
308 // and before creating a byte-range request loader. | |
309 bool complete = false; | |
310 ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool( | |
311 browser()->GetSelectedTabContents()->render_view_host(), | |
312 std::wstring(), | |
313 L"window.domAutomationController.send(plugin.documentLoadComplete())", | |
314 &complete)); | |
315 if (complete) | |
316 break; | |
317 | |
318 // Check if the LOAD_STOP notification could have come while we run a | |
319 // nested message loop for the JS call. | |
320 if (last_count != load_stop_notification_count()) | |
321 continue; | |
322 ui_test_utils::WaitForLoadStop(browser()->GetSelectedTabContents()); | |
323 } | |
324 } | |
325 } | |
326 | |
327 // Flaky as per http://crbug.com/74549. | |
328 #if defined(OS_MACOSX) | |
329 #define MAYBE_OnLoadAndReload DISABLED_OnLoadAndReload | |
330 #else | |
331 #define MAYBE_OnLoadAndReload FLAKY_OnLoadAndReload | |
332 #endif | |
333 IN_PROC_BROWSER_TEST_F(PDFBrowserTest, MAYBE_OnLoadAndReload) { | |
334 ASSERT_TRUE(pdf_test_server()->Start()); | |
335 | |
336 GURL url = pdf_test_server()->GetURL("files/onload_reload.html"); | |
337 ui_test_utils::NavigateToURL(browser(), url); | |
338 | |
339 ASSERT_TRUE(ui_test_utils::ExecuteJavaScript( | |
340 browser()->GetSelectedTabContents()->render_view_host(), | |
341 std::wstring(), | |
342 L"reloadPDF();")); | |
343 | |
344 ASSERT_TRUE(ui_test_utils::WaitForNavigationInCurrentTab(browser())); | |
345 ASSERT_EQ("success", browser()->GetSelectedTabContents()->GetURL().query()); | |
346 } | |
347 | |
348 } // namespace | |
OLD | NEW |