OLD | NEW |
| (Empty) |
1 // Copyright (c) 2010 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/basictypes.h" | |
6 | |
7 #include "base/file_util.h" | |
8 #include "base/keyboard_codes.h" | |
9 #include "base/shared_memory.h" | |
10 #include "base/utf_string_conversions.h" | |
11 #include "chrome/common/content_settings.h" | |
12 #include "chrome/common/native_web_keyboard_event.h" | |
13 #include "chrome/common/render_messages.h" | |
14 #include "chrome/common/render_messages_params.h" | |
15 #include "chrome/renderer/print_web_view_helper.h" | |
16 #include "chrome/test/render_view_test.h" | |
17 #include "gfx/codec/jpeg_codec.h" | |
18 #include "net/base/net_errors.h" | |
19 #include "printing/image.h" | |
20 #include "printing/native_metafile.h" | |
21 #include "testing/gtest/include/gtest/gtest.h" | |
22 #include "third_party/WebKit/WebKit/chromium/public/WebDocument.h" | |
23 #include "third_party/WebKit/WebKit/chromium/public/WebInputElement.h" | |
24 #include "third_party/WebKit/WebKit/chromium/public/WebString.h" | |
25 #include "third_party/WebKit/WebKit/chromium/public/WebURLError.h" | |
26 #include "third_party/WebKit/WebKit/chromium/public/WebView.h" | |
27 #include "webkit/glue/form_data.h" | |
28 #include "webkit/glue/form_field.h" | |
29 | |
30 using WebKit::WebDocument; | |
31 using WebKit::WebFrame; | |
32 using WebKit::WebInputElement; | |
33 using WebKit::WebString; | |
34 using WebKit::WebTextDirection; | |
35 using WebKit::WebURLError; | |
36 using webkit_glue::FormData; | |
37 using webkit_glue::FormField; | |
38 | |
39 // Test that we get form state change notifications when input fields change. | |
40 TEST_F(RenderViewTest, OnNavStateChanged) { | |
41 // Don't want any delay for form state sync changes. This will still post a | |
42 // message so updates will get coalesced, but as soon as we spin the message | |
43 // loop, it will generate an update. | |
44 view_->set_send_content_state_immediately(true); | |
45 | |
46 LoadHTML("<input type=\"text\" id=\"elt_text\"></input>"); | |
47 | |
48 // We should NOT have gotten a form state change notification yet. | |
49 EXPECT_FALSE(render_thread_.sink().GetFirstMessageMatching( | |
50 ViewHostMsg_UpdateState::ID)); | |
51 render_thread_.sink().ClearMessages(); | |
52 | |
53 // Change the value of the input. We should have gotten an update state | |
54 // notification. We need to spin the message loop to catch this update. | |
55 ExecuteJavaScript("document.getElementById('elt_text').value = 'foo';"); | |
56 ProcessPendingMessages(); | |
57 EXPECT_TRUE(render_thread_.sink().GetUniqueMessageMatching( | |
58 ViewHostMsg_UpdateState::ID)); | |
59 } | |
60 | |
61 // Test that our IME backend sends a notification message when the input focus | |
62 // changes. | |
63 TEST_F(RenderViewTest, OnImeStateChanged) { | |
64 // Enable our IME backend code. | |
65 view_->OnSetInputMethodActive(true); | |
66 | |
67 // Load an HTML page consisting of two input fields. | |
68 view_->set_send_content_state_immediately(true); | |
69 LoadHTML("<html>" | |
70 "<head>" | |
71 "</head>" | |
72 "<body>" | |
73 "<input id=\"test1\" type=\"text\"></input>" | |
74 "<input id=\"test2\" type=\"password\"></input>" | |
75 "</body>" | |
76 "</html>"); | |
77 render_thread_.sink().ClearMessages(); | |
78 | |
79 const int kRepeatCount = 10; | |
80 for (int i = 0; i < kRepeatCount; i++) { | |
81 // Move the input focus to the first <input> element, where we should | |
82 // activate IMEs. | |
83 ExecuteJavaScript("document.getElementById('test1').focus();"); | |
84 ProcessPendingMessages(); | |
85 render_thread_.sink().ClearMessages(); | |
86 | |
87 // Update the IME status and verify if our IME backend sends an IPC message | |
88 // to activate IMEs. | |
89 view_->UpdateInputMethod(); | |
90 const IPC::Message* msg = render_thread_.sink().GetMessageAt(0); | |
91 EXPECT_TRUE(msg != NULL); | |
92 EXPECT_EQ(ViewHostMsg_ImeUpdateTextInputState::ID, msg->type()); | |
93 ViewHostMsg_ImeUpdateTextInputState::Param params; | |
94 ViewHostMsg_ImeUpdateTextInputState::Read(msg, ¶ms); | |
95 EXPECT_EQ(params.a, WebKit::WebTextInputTypeText); | |
96 EXPECT_TRUE(params.b.x() > 0 && params.b.y() > 0); | |
97 | |
98 // Move the input focus to the second <input> element, where we should | |
99 // de-activate IMEs. | |
100 ExecuteJavaScript("document.getElementById('test2').focus();"); | |
101 ProcessPendingMessages(); | |
102 render_thread_.sink().ClearMessages(); | |
103 | |
104 // Update the IME status and verify if our IME backend sends an IPC message | |
105 // to de-activate IMEs. | |
106 view_->UpdateInputMethod(); | |
107 msg = render_thread_.sink().GetMessageAt(0); | |
108 EXPECT_TRUE(msg != NULL); | |
109 EXPECT_EQ(ViewHostMsg_ImeUpdateTextInputState::ID, msg->type()); | |
110 ViewHostMsg_ImeUpdateTextInputState::Read(msg, ¶ms); | |
111 EXPECT_EQ(params.a, WebKit::WebTextInputTypePassword); | |
112 } | |
113 } | |
114 | |
115 // Test that our IME backend can compose CJK words. | |
116 // Our IME front-end sends many platform-independent messages to the IME backend | |
117 // while it composes CJK words. This test sends the minimal messages captured | |
118 // on my local environment directly to the IME backend to verify if the backend | |
119 // can compose CJK words without any problems. | |
120 // This test uses an array of command sets because an IME composotion does not | |
121 // only depends on IME events, but also depends on window events, e.g. moving | |
122 // the window focus while composing a CJK text. To handle such complicated | |
123 // cases, this test should not only call IME-related functions in the | |
124 // RenderWidget class, but also call some RenderWidget members, e.g. | |
125 // ExecuteJavaScript(), RenderWidget::OnSetFocus(), etc. | |
126 TEST_F(RenderViewTest, ImeComposition) { | |
127 enum ImeCommand { | |
128 IME_INITIALIZE, | |
129 IME_SETINPUTMODE, | |
130 IME_SETFOCUS, | |
131 IME_SETCOMPOSITION, | |
132 IME_CONFIRMCOMPOSITION, | |
133 IME_CANCELCOMPOSITION | |
134 }; | |
135 struct ImeMessage { | |
136 ImeCommand command; | |
137 bool enable; | |
138 int selection_start; | |
139 int selection_end; | |
140 const wchar_t* ime_string; | |
141 const wchar_t* result; | |
142 }; | |
143 static const ImeMessage kImeMessages[] = { | |
144 // Scenario 1: input a Chinese word with Microsoft IME (on Vista). | |
145 {IME_INITIALIZE, true, 0, 0, NULL, NULL}, | |
146 {IME_SETINPUTMODE, true, 0, 0, NULL, NULL}, | |
147 {IME_SETFOCUS, true, 0, 0, NULL, NULL}, | |
148 {IME_SETCOMPOSITION, false, 1, 1, L"n", L"n"}, | |
149 {IME_SETCOMPOSITION, false, 2, 2, L"ni", L"ni"}, | |
150 {IME_SETCOMPOSITION, false, 3, 3, L"nih", L"nih"}, | |
151 {IME_SETCOMPOSITION, false, 4, 4, L"niha", L"niha"}, | |
152 {IME_SETCOMPOSITION, false, 5, 5, L"nihao", L"nihao"}, | |
153 {IME_SETCOMPOSITION, false, 2, 2, L"\x4F60\x597D", L"\x4F60\x597D"}, | |
154 {IME_CONFIRMCOMPOSITION, false, -1, -1, NULL, L"\x4F60\x597D"}, | |
155 {IME_CANCELCOMPOSITION, false, -1, -1, L"", L"\x4F60\x597D"}, | |
156 // Scenario 2: input a Japanese word with Microsoft IME (on Vista). | |
157 {IME_INITIALIZE, true, 0, 0, NULL, NULL}, | |
158 {IME_SETINPUTMODE, true, 0, 0, NULL, NULL}, | |
159 {IME_SETFOCUS, true, 0, 0, NULL, NULL}, | |
160 {IME_SETCOMPOSITION, false, 0, 1, L"\xFF4B", L"\xFF4B"}, | |
161 {IME_SETCOMPOSITION, false, 0, 1, L"\x304B", L"\x304B"}, | |
162 {IME_SETCOMPOSITION, false, 0, 2, L"\x304B\xFF4E", L"\x304B\xFF4E"}, | |
163 {IME_SETCOMPOSITION, false, 0, 3, L"\x304B\x3093\xFF4A", | |
164 L"\x304B\x3093\xFF4A"}, | |
165 {IME_SETCOMPOSITION, false, 0, 3, L"\x304B\x3093\x3058", | |
166 L"\x304B\x3093\x3058"}, | |
167 {IME_SETCOMPOSITION, false, 0, 2, L"\x611F\x3058", L"\x611F\x3058"}, | |
168 {IME_SETCOMPOSITION, false, 0, 2, L"\x6F22\x5B57", L"\x6F22\x5B57"}, | |
169 {IME_CONFIRMCOMPOSITION, false, -1, -1, NULL, L"\x6F22\x5B57"}, | |
170 {IME_CANCELCOMPOSITION, false, -1, -1, L"", L"\x6F22\x5B57"}, | |
171 // Scenario 3: input a Korean word with Microsot IME (on Vista). | |
172 {IME_INITIALIZE, true, 0, 0, NULL, NULL}, | |
173 {IME_SETINPUTMODE, true, 0, 0, NULL, NULL}, | |
174 {IME_SETFOCUS, true, 0, 0, NULL, NULL}, | |
175 {IME_SETCOMPOSITION, false, 0, 1, L"\x3147", L"\x3147"}, | |
176 {IME_SETCOMPOSITION, false, 0, 1, L"\xC544", L"\xC544"}, | |
177 {IME_SETCOMPOSITION, false, 0, 1, L"\xC548", L"\xC548"}, | |
178 {IME_CONFIRMCOMPOSITION, false, -1, -1, NULL, L"\xC548"}, | |
179 {IME_SETCOMPOSITION, false, 0, 1, L"\x3134", L"\xC548\x3134"}, | |
180 {IME_SETCOMPOSITION, false, 0, 1, L"\xB140", L"\xC548\xB140"}, | |
181 {IME_SETCOMPOSITION, false, 0, 1, L"\xB155", L"\xC548\xB155"}, | |
182 {IME_CANCELCOMPOSITION, false, -1, -1, L"", L"\xC548"}, | |
183 {IME_SETCOMPOSITION, false, 0, 1, L"\xB155", L"\xC548\xB155"}, | |
184 {IME_CONFIRMCOMPOSITION, false, -1, -1, NULL, L"\xC548\xB155"}, | |
185 }; | |
186 | |
187 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kImeMessages); i++) { | |
188 const ImeMessage* ime_message = &kImeMessages[i]; | |
189 switch (ime_message->command) { | |
190 case IME_INITIALIZE: | |
191 // Load an HTML page consisting of a content-editable <div> element, | |
192 // and move the input focus to the <div> element, where we can use | |
193 // IMEs. | |
194 view_->OnSetInputMethodActive(ime_message->enable); | |
195 view_->set_send_content_state_immediately(true); | |
196 LoadHTML("<html>" | |
197 "<head>" | |
198 "</head>" | |
199 "<body>" | |
200 "<div id=\"test1\" contenteditable=\"true\"></div>" | |
201 "</body>" | |
202 "</html>"); | |
203 ExecuteJavaScript("document.getElementById('test1').focus();"); | |
204 break; | |
205 | |
206 case IME_SETINPUTMODE: | |
207 // Activate (or deactivate) our IME back-end. | |
208 view_->OnSetInputMethodActive(ime_message->enable); | |
209 break; | |
210 | |
211 case IME_SETFOCUS: | |
212 // Update the window focus. | |
213 view_->OnSetFocus(ime_message->enable); | |
214 break; | |
215 | |
216 case IME_SETCOMPOSITION: | |
217 view_->OnImeSetComposition( | |
218 WideToUTF16Hack(ime_message->ime_string), | |
219 std::vector<WebKit::WebCompositionUnderline>(), | |
220 ime_message->selection_start, | |
221 ime_message->selection_end); | |
222 break; | |
223 | |
224 case IME_CONFIRMCOMPOSITION: | |
225 view_->OnImeConfirmComposition(); | |
226 break; | |
227 | |
228 case IME_CANCELCOMPOSITION: | |
229 view_->OnImeSetComposition(string16(), | |
230 std::vector<WebKit::WebCompositionUnderline>(), | |
231 0, 0); | |
232 break; | |
233 } | |
234 | |
235 // Update the status of our IME back-end. | |
236 // TODO(hbono): we should verify messages to be sent from the back-end. | |
237 view_->UpdateInputMethod(); | |
238 ProcessPendingMessages(); | |
239 render_thread_.sink().ClearMessages(); | |
240 | |
241 if (ime_message->result) { | |
242 // Retrieve the content of this page and compare it with the expected | |
243 // result. | |
244 const int kMaxOutputCharacters = 128; | |
245 std::wstring output = UTF16ToWideHack( | |
246 GetMainFrame()->contentAsText(kMaxOutputCharacters)); | |
247 EXPECT_EQ(output, ime_message->result); | |
248 } | |
249 } | |
250 } | |
251 | |
252 // Test that the RenderView::OnSetTextDirection() function can change the text | |
253 // direction of the selected input element. | |
254 TEST_F(RenderViewTest, OnSetTextDirection) { | |
255 // Load an HTML page consisting of a <textarea> element and a <div> element. | |
256 // This test changes the text direction of the <textarea> element, and | |
257 // writes the values of its 'dir' attribute and its 'direction' property to | |
258 // verify that the text direction is changed. | |
259 view_->set_send_content_state_immediately(true); | |
260 LoadHTML("<html>" | |
261 "<head>" | |
262 "</head>" | |
263 "<body>" | |
264 "<textarea id=\"test\"></textarea>" | |
265 "<div id=\"result\" contenteditable=\"true\"></div>" | |
266 "</body>" | |
267 "</html>"); | |
268 render_thread_.sink().ClearMessages(); | |
269 | |
270 static const struct { | |
271 WebTextDirection direction; | |
272 const wchar_t* expected_result; | |
273 } kTextDirection[] = { | |
274 { WebKit::WebTextDirectionRightToLeft, L"\x000A" L"rtl,rtl" }, | |
275 { WebKit::WebTextDirectionLeftToRight, L"\x000A" L"ltr,ltr" }, | |
276 }; | |
277 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTextDirection); ++i) { | |
278 // Set the text direction of the <textarea> element. | |
279 ExecuteJavaScript("document.getElementById('test').focus();"); | |
280 view_->OnSetTextDirection(kTextDirection[i].direction); | |
281 | |
282 // Write the values of its DOM 'dir' attribute and its CSS 'direction' | |
283 // property to the <div> element. | |
284 ExecuteJavaScript("var result = document.getElementById('result');" | |
285 "var node = document.getElementById('test');" | |
286 "var style = getComputedStyle(node, null);" | |
287 "result.innerText =" | |
288 " node.getAttribute('dir') + ',' +" | |
289 " style.getPropertyValue('direction');"); | |
290 | |
291 // Copy the document content to std::wstring and compare with the | |
292 // expected result. | |
293 const int kMaxOutputCharacters = 16; | |
294 std::wstring output = UTF16ToWideHack( | |
295 GetMainFrame()->contentAsText(kMaxOutputCharacters)); | |
296 EXPECT_EQ(output, kTextDirection[i].expected_result); | |
297 } | |
298 } | |
299 | |
300 // Tests that printing pages work and sending and receiving messages through | |
301 // that channel all works. | |
302 TEST_F(RenderViewTest, OnPrintPages) { | |
303 // Lets simulate a print pages with Hello world. | |
304 LoadHTML("<body><p>Hello World!</p></body>"); | |
305 view_->OnPrintPages(); | |
306 | |
307 VerifyPageCount(1); | |
308 VerifyPagesPrinted(); | |
309 } | |
310 | |
311 // Duplicate of OnPrintPagesTest only using javascript to print. | |
312 TEST_F(RenderViewTest, PrintWithJavascript) { | |
313 // HTML contains a call to window.print() | |
314 LoadHTML("<body>Hello<script>window.print()</script>World</body>"); | |
315 | |
316 VerifyPageCount(1); | |
317 VerifyPagesPrinted(); | |
318 } | |
319 | |
320 #if defined(OS_WIN) || defined(OS_MACOSX) | |
321 // TODO(estade): I don't think this test is worth porting to Linux. We will have | |
322 // to rip out and replace most of the IPC code if we ever plan to improve | |
323 // printing, and the comment below by sverrir suggests that it doesn't do much | |
324 // for us anyway. | |
325 TEST_F(RenderViewTest, PrintWithIframe) { | |
326 // Document that populates an iframe. | |
327 const char html[] = | |
328 "<html><body>Lorem Ipsum:" | |
329 "<iframe name=\"sub1\" id=\"sub1\"></iframe><script>" | |
330 " document.write(frames['sub1'].name);" | |
331 " frames['sub1'].document.write(" | |
332 " '<p>Cras tempus ante eu felis semper luctus!</p>');" | |
333 "</script></body></html>"; | |
334 | |
335 LoadHTML(html); | |
336 | |
337 // Find the frame and set it as the focused one. This should mean that that | |
338 // the printout should only contain the contents of that frame. | |
339 WebFrame* sub1_frame = | |
340 view_->webview()->findFrameByName(WebString::fromUTF8("sub1")); | |
341 ASSERT_TRUE(sub1_frame); | |
342 view_->webview()->setFocusedFrame(sub1_frame); | |
343 ASSERT_NE(view_->webview()->focusedFrame(), | |
344 view_->webview()->mainFrame()); | |
345 | |
346 // Initiate printing. | |
347 view_->OnPrintPages(); | |
348 | |
349 // Verify output through MockPrinter. | |
350 const MockPrinter* printer(render_thread_.printer()); | |
351 ASSERT_EQ(1, printer->GetPrintedPages()); | |
352 const printing::Image& image1(printer->GetPrintedPage(0)->image()); | |
353 | |
354 // TODO(sverrir): Figure out a way to improve this test to actually print | |
355 // only the content of the iframe. Currently image1 will contain the full | |
356 // page. | |
357 EXPECT_NE(0, image1.size().width()); | |
358 EXPECT_NE(0, image1.size().height()); | |
359 } | |
360 #endif | |
361 | |
362 // Tests if we can print a page and verify its results. | |
363 // This test prints HTML pages into a pseudo printer and check their outputs, | |
364 // i.e. a simplified version of the PrintingLayoutTextTest UI test. | |
365 namespace { | |
366 // Test cases used in this test. | |
367 struct TestPageData { | |
368 const char* page; | |
369 size_t printed_pages; | |
370 int width; | |
371 int height; | |
372 const char* checksum; | |
373 const wchar_t* file; | |
374 }; | |
375 | |
376 const TestPageData kTestPages[] = { | |
377 {"<html>" | |
378 "<head>" | |
379 "<meta" | |
380 " http-equiv=\"Content-Type\"" | |
381 " content=\"text/html; charset=utf-8\"/>" | |
382 "<title>Test 1</title>" | |
383 "</head>" | |
384 "<body style=\"background-color: white;\">" | |
385 "<p style=\"font-family: arial;\">Hello World!</p>" | |
386 "</body>", | |
387 #if defined(OS_MACOSX) | |
388 // Mac printing code compensates for the WebKit scale factor while generating | |
389 // the metafile, so we expect smaller pages. | |
390 1, 612, 792, | |
391 #else | |
392 1, 764, 972, | |
393 #endif | |
394 NULL, | |
395 NULL, | |
396 }, | |
397 }; | |
398 } // namespace | |
399 | |
400 // TODO(estade): need to port MockPrinter to get this on Linux. This involves | |
401 // hooking up Cairo to read a pdf stream, or accessing the cairo surface in the | |
402 // metafile directly. | |
403 #if defined(OS_WIN) || defined(OS_MACOSX) | |
404 TEST_F(RenderViewTest, PrintLayoutTest) { | |
405 bool baseline = false; | |
406 | |
407 EXPECT_TRUE(render_thread_.printer() != NULL); | |
408 for (size_t i = 0; i < arraysize(kTestPages); ++i) { | |
409 // Load an HTML page and print it. | |
410 LoadHTML(kTestPages[i].page); | |
411 view_->OnPrintPages(); | |
412 | |
413 // MockRenderThread::Send() just calls MockRenderThread::OnMsgReceived(). | |
414 // So, all IPC messages sent in the above RenderView::OnPrintPages() call | |
415 // has been handled by the MockPrinter object, i.e. this printing job | |
416 // has been already finished. | |
417 // So, we can start checking the output pages of this printing job. | |
418 // Retrieve the number of pages actually printed. | |
419 size_t pages = render_thread_.printer()->GetPrintedPages(); | |
420 EXPECT_EQ(kTestPages[i].printed_pages, pages); | |
421 | |
422 // Retrieve the width and height of the output page. | |
423 int width = render_thread_.printer()->GetWidth(0); | |
424 int height = render_thread_.printer()->GetHeight(0); | |
425 | |
426 // Check with margin for error. This has been failing with a one pixel | |
427 // offset on our buildbot. | |
428 const int kErrorMargin = 5; // 5% | |
429 EXPECT_GT(kTestPages[i].width * (100 + kErrorMargin) / 100, width); | |
430 EXPECT_LT(kTestPages[i].width * (100 - kErrorMargin) / 100, width); | |
431 EXPECT_GT(kTestPages[i].height * (100 + kErrorMargin) / 100, height); | |
432 EXPECT_LT(kTestPages[i].height* (100 - kErrorMargin) / 100, height); | |
433 | |
434 // Retrieve the checksum of the bitmap data from the pseudo printer and | |
435 // compare it with the expected result. | |
436 std::string bitmap_actual; | |
437 EXPECT_TRUE(render_thread_.printer()->GetBitmapChecksum(0, &bitmap_actual)); | |
438 if (kTestPages[i].checksum) | |
439 EXPECT_EQ(kTestPages[i].checksum, bitmap_actual); | |
440 | |
441 if (baseline) { | |
442 // Save the source data and the bitmap data into temporary files to | |
443 // create base-line results. | |
444 FilePath source_path; | |
445 file_util::CreateTemporaryFile(&source_path); | |
446 render_thread_.printer()->SaveSource(0, source_path); | |
447 | |
448 FilePath bitmap_path; | |
449 file_util::CreateTemporaryFile(&bitmap_path); | |
450 render_thread_.printer()->SaveBitmap(0, bitmap_path); | |
451 } | |
452 } | |
453 } | |
454 #endif | |
455 | |
456 // Print page as bitmap test. | |
457 TEST_F(RenderViewTest, OnPrintPageAsBitmap) { | |
458 // Lets simulate a print pages with Hello world. | |
459 LoadHTML("<body><p>Hello world!</p></body>"); | |
460 | |
461 // Grab the printer settings from the printer. | |
462 ViewMsg_Print_Params print_settings; | |
463 MockPrinter* printer(render_thread_.printer()); | |
464 printer->GetDefaultPrintSettings(&print_settings); | |
465 ViewMsg_PrintPage_Params page_params = ViewMsg_PrintPage_Params(); | |
466 page_params.params = print_settings; | |
467 page_params.page_number = 0; | |
468 | |
469 // Fetch the image data from the web frame. | |
470 std::vector<unsigned char> data; | |
471 view_->print_helper()->PrintPageAsJPEG(page_params, | |
472 view_->webview()->mainFrame(), | |
473 1.0f, | |
474 &data); | |
475 std::vector<unsigned char> decoded; | |
476 int w, h; | |
477 EXPECT_TRUE(gfx::JPEGCodec::Decode(&data[0], data.size(), | |
478 gfx::JPEGCodec::FORMAT_RGBA, | |
479 &decoded, &w, &h)); | |
480 | |
481 // Check if it's not 100% white. | |
482 bool is_white = true; | |
483 for (int y = 0; y < h; y++) { | |
484 for (int x = 0; x < w; x++) { | |
485 unsigned char* px = &decoded[(y * w + x) * 4]; | |
486 if (px[0] != 0xFF && px[1] != 0xFF && px[2] != 0xFF) { | |
487 is_white = false; | |
488 break; | |
489 } | |
490 } | |
491 } | |
492 ASSERT_TRUE(!is_white); | |
493 } | |
494 | |
495 // Test that we can receive correct DOM events when we send input events | |
496 // through the RenderWidget::OnHandleInputEvent() function. | |
497 // Crashy, http://crbug.com/52643. | |
498 TEST_F(RenderViewTest, DISABLED_OnHandleKeyboardEvent) { | |
499 #if defined(OS_WIN) || defined(OS_LINUX) | |
500 // Load an HTML page consisting of one <input> element and three | |
501 // contentediable <div> elements. | |
502 // The <input> element is used for sending keyboard events, and the <div> | |
503 // elements are used for writing DOM events in the following format: | |
504 // "<keyCode>,<shiftKey>,<controlKey>,<altKey>". | |
505 // TODO(hbono): <http://crbug.com/2215> Our WebKit port set |ev.metaKey| to | |
506 // true when pressing an alt key, i.e. the |ev.metaKey| value is not | |
507 // trustworthy. We will check the |ev.metaKey| value when this issue is fixed. | |
508 view_->set_send_content_state_immediately(true); | |
509 LoadHTML("<html>" | |
510 "<head>" | |
511 "<title></title>" | |
512 "<script type='text/javascript' language='javascript'>" | |
513 "function OnKeyEvent(ev) {" | |
514 " var result = document.getElementById(ev.type);" | |
515 " result.innerText =" | |
516 " (ev.which || ev.keyCode) + ',' +" | |
517 " ev.shiftKey + ',' +" | |
518 " ev.ctrlKey + ',' +" | |
519 " ev.altKey;" | |
520 " return true;" | |
521 "}" | |
522 "</script>" | |
523 "</head>" | |
524 "<body>" | |
525 "<input id='test' type='text'" | |
526 " onkeydown='return OnKeyEvent(event);'" | |
527 " onkeypress='return OnKeyEvent(event);'" | |
528 " onkeyup='return OnKeyEvent(event);'>" | |
529 "</input>" | |
530 "<div id='keydown' contenteditable='true'>" | |
531 "</div>" | |
532 "<div id='keypress' contenteditable='true'>" | |
533 "</div>" | |
534 "<div id='keyup' contenteditable='true'>" | |
535 "</div>" | |
536 "</body>" | |
537 "</html>"); | |
538 ExecuteJavaScript("document.getElementById('test').focus();"); | |
539 render_thread_.sink().ClearMessages(); | |
540 | |
541 static const MockKeyboard::Layout kLayouts[] = { | |
542 #if defined(OS_WIN) | |
543 // Since we ignore the mock keyboard layout on Linux and instead just use | |
544 // the screen's keyboard layout, these trivially pass. They are commented | |
545 // out to avoid the illusion that they work. | |
546 MockKeyboard::LAYOUT_ARABIC, | |
547 MockKeyboard::LAYOUT_CANADIAN_FRENCH, | |
548 MockKeyboard::LAYOUT_FRENCH, | |
549 MockKeyboard::LAYOUT_HEBREW, | |
550 MockKeyboard::LAYOUT_RUSSIAN, | |
551 #endif | |
552 MockKeyboard::LAYOUT_UNITED_STATES, | |
553 }; | |
554 | |
555 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kLayouts); ++i) { | |
556 // For each key code, we send three keyboard events. | |
557 // * we press only the key; | |
558 // * we press the key and a left-shift key, and; | |
559 // * we press the key and a right-alt (AltGr) key. | |
560 // For each modifiers, we need a string used for formatting its expected | |
561 // result. (See the above comment for its format.) | |
562 static const struct { | |
563 MockKeyboard::Modifiers modifiers; | |
564 const char* expected_result; | |
565 } kModifierData[] = { | |
566 {MockKeyboard::NONE, "false,false,false"}, | |
567 {MockKeyboard::LEFT_SHIFT, "true,false,false"}, | |
568 #if defined(OS_WIN) | |
569 {MockKeyboard::RIGHT_ALT, "false,false,true"}, | |
570 #endif | |
571 }; | |
572 | |
573 MockKeyboard::Layout layout = kLayouts[i]; | |
574 for (size_t j = 0; j < ARRAYSIZE_UNSAFE(kModifierData); ++j) { | |
575 // Virtual key codes used for this test. | |
576 static const int kKeyCodes[] = { | |
577 '0', '1', '2', '3', '4', '5', '6', '7', | |
578 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', | |
579 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', | |
580 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', | |
581 'W', 'X', 'Y', 'Z', | |
582 base::VKEY_OEM_1, | |
583 base::VKEY_OEM_PLUS, | |
584 base::VKEY_OEM_COMMA, | |
585 base::VKEY_OEM_MINUS, | |
586 base::VKEY_OEM_PERIOD, | |
587 base::VKEY_OEM_2, | |
588 base::VKEY_OEM_3, | |
589 base::VKEY_OEM_4, | |
590 base::VKEY_OEM_5, | |
591 base::VKEY_OEM_6, | |
592 base::VKEY_OEM_7, | |
593 #if defined(OS_WIN) | |
594 // Not sure how to handle this key on Linux. | |
595 base::VKEY_OEM_8, | |
596 #endif | |
597 }; | |
598 | |
599 MockKeyboard::Modifiers modifiers = kModifierData[j].modifiers; | |
600 for (size_t k = 0; k < ARRAYSIZE_UNSAFE(kKeyCodes); ++k) { | |
601 // Send a keyboard event to the RenderView object. | |
602 // We should test a keyboard event only when the given keyboard-layout | |
603 // driver is installed in a PC and the driver can assign a Unicode | |
604 // charcter for the given tuple (key-code and modifiers). | |
605 int key_code = kKeyCodes[k]; | |
606 std::wstring char_code; | |
607 if (SendKeyEvent(layout, key_code, modifiers, &char_code) < 0) | |
608 continue; | |
609 | |
610 // Create an expected result from the virtual-key code, the character | |
611 // code, and the modifier-key status. | |
612 // We format a string that emulates a DOM-event string produced hy | |
613 // our JavaScript function. (See the above comment for the format.) | |
614 static char expected_result[1024]; | |
615 expected_result[0] = NULL; | |
616 sprintf(&expected_result[0], | |
617 "\n" // texts in the <input> element | |
618 "%d,%s\n" // texts in the first <div> element | |
619 "%d,%s\n" // texts in the second <div> element | |
620 "%d,%s", // texts in the third <div> element | |
621 key_code, kModifierData[j].expected_result, | |
622 char_code[0], kModifierData[j].expected_result, | |
623 key_code, kModifierData[j].expected_result); | |
624 | |
625 // Retrieve the text in the test page and compare it with the expected | |
626 // text created from a virtual-key code, a character code, and the | |
627 // modifier-key status. | |
628 const int kMaxOutputCharacters = 1024; | |
629 std::string output = UTF16ToUTF8( | |
630 GetMainFrame()->contentAsText(kMaxOutputCharacters)); | |
631 EXPECT_EQ(expected_result, output); | |
632 } | |
633 } | |
634 } | |
635 #else | |
636 NOTIMPLEMENTED(); | |
637 #endif | |
638 } | |
639 | |
640 // Test that our EditorClientImpl class can insert characters when we send | |
641 // keyboard events through the RenderWidget::OnHandleInputEvent() function. | |
642 // This test is for preventing regressions caused only when we use non-US | |
643 // keyboards, such as Issue 10846. | |
644 TEST_F(RenderViewTest, InsertCharacters) { | |
645 #if defined(OS_WIN) || defined(OS_LINUX) | |
646 static const struct { | |
647 MockKeyboard::Layout layout; | |
648 const wchar_t* expected_result; | |
649 } kLayouts[] = { | |
650 #if 0 | |
651 // Disabled these keyboard layouts because buildbots do not have their | |
652 // keyboard-layout drivers installed. | |
653 {MockKeyboard::LAYOUT_ARABIC, | |
654 L"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037" | |
655 L"\x0038\x0039\x0634\x0624\x064a\x062b\x0628\x0644" | |
656 L"\x0627\x0647\x062a\x0646\x0645\x0629\x0649\x062e" | |
657 L"\x062d\x0636\x0642\x0633\x0641\x0639\x0631\x0635" | |
658 L"\x0621\x063a\x0626\x0643\x003d\x0648\x002d\x0632" | |
659 L"\x0638\x0630\x062c\x005c\x062f\x0637\x0028\x0021" | |
660 L"\x0040\x0023\x0024\x0025\x005e\x0026\x002a\x0029" | |
661 L"\x0650\x007d\x005d\x064f\x005b\x0623\x00f7\x0640" | |
662 L"\x060c\x002f\x2019\x0622\x00d7\x061b\x064e\x064c" | |
663 L"\x064d\x2018\x007b\x064b\x0652\x0625\x007e\x003a" | |
664 L"\x002b\x002c\x005f\x002e\x061f\x0651\x003c\x007c" | |
665 L"\x003e\x0022\x0030\x0031\x0032\x0033\x0034\x0035" | |
666 L"\x0036\x0037\x0038\x0039\x0634\x0624\x064a\x062b" | |
667 L"\x0628\x0644\x0627\x0647\x062a\x0646\x0645\x0629" | |
668 L"\x0649\x062e\x062d\x0636\x0642\x0633\x0641\x0639" | |
669 L"\x0631\x0635\x0621\x063a\x0626\x0643\x003d\x0648" | |
670 L"\x002d\x0632\x0638\x0630\x062c\x005c\x062f\x0637" | |
671 }, | |
672 {MockKeyboard::LAYOUT_HEBREW, | |
673 L"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037" | |
674 L"\x0038\x0039\x05e9\x05e0\x05d1\x05d2\x05e7\x05db" | |
675 L"\x05e2\x05d9\x05df\x05d7\x05dc\x05da\x05e6\x05de" | |
676 L"\x05dd\x05e4\x002f\x05e8\x05d3\x05d0\x05d5\x05d4" | |
677 L"\x0027\x05e1\x05d8\x05d6\x05e3\x003d\x05ea\x002d" | |
678 L"\x05e5\x002e\x003b\x005d\x005c\x005b\x002c\x0028" | |
679 L"\x0021\x0040\x0023\x0024\x0025\x005e\x0026\x002a" | |
680 L"\x0029\x0041\x0042\x0043\x0044\x0045\x0046\x0047" | |
681 L"\x0048\x0049\x004a\x004b\x004c\x004d\x004e\x004f" | |
682 L"\x0050\x0051\x0052\x0053\x0054\x0055\x0056\x0057" | |
683 L"\x0058\x0059\x005a\x003a\x002b\x003e\x005f\x003c" | |
684 L"\x003f\x007e\x007d\x007c\x007b\x0022\x0030\x0031" | |
685 L"\x0032\x0033\x0034\x0035\x0036\x0037\x0038\x0039" | |
686 L"\x05e9\x05e0\x05d1\x05d2\x05e7\x05db\x05e2\x05d9" | |
687 L"\x05df\x05d7\x05dc\x05da\x05e6\x05de\x05dd\x05e4" | |
688 L"\x002f\x05e8\x05d3\x05d0\x05d5\x05d4\x0027\x05e1" | |
689 L"\x05d8\x05d6\x05e3\x003d\x05ea\x002d\x05e5\x002e" | |
690 L"\x003b\x005d\x005c\x005b\x002c" | |
691 }, | |
692 #endif | |
693 #if defined(OS_WIN) | |
694 // On Linux, the only way to test alternate keyboard layouts is to change | |
695 // the keyboard layout of the whole screen. I'm worried about the side | |
696 // effects this may have on the buildbots. | |
697 {MockKeyboard::LAYOUT_CANADIAN_FRENCH, | |
698 L"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037" | |
699 L"\x0038\x0039\x0061\x0062\x0063\x0064\x0065\x0066" | |
700 L"\x0067\x0068\x0069\x006a\x006b\x006c\x006d\x006e" | |
701 L"\x006f\x0070\x0071\x0072\x0073\x0074\x0075\x0076" | |
702 L"\x0077\x0078\x0079\x007a\x003b\x003d\x002c\x002d" | |
703 L"\x002e\x00e9\x003c\x0029\x0021\x0022\x002f\x0024" | |
704 L"\x0025\x003f\x0026\x002a\x0028\x0041\x0042\x0043" | |
705 L"\x0044\x0045\x0046\x0047\x0048\x0049\x004a\x004b" | |
706 L"\x004c\x004d\x004e\x004f\x0050\x0051\x0052\x0053" | |
707 L"\x0054\x0055\x0056\x0057\x0058\x0059\x005a\x003a" | |
708 L"\x002b\x0027\x005f\x002e\x00c9\x003e\x0030\x0031" | |
709 L"\x0032\x0033\x0034\x0035\x0036\x0037\x0038\x0039" | |
710 L"\x0061\x0062\x0063\x0064\x0065\x0066\x0067\x0068" | |
711 L"\x0069\x006a\x006b\x006c\x006d\x006e\x006f\x0070" | |
712 L"\x0071\x0072\x0073\x0074\x0075\x0076\x0077\x0078" | |
713 L"\x0079\x007a\x003b\x003d\x002c\x002d\x002e\x00e9" | |
714 L"\x003c" | |
715 }, | |
716 {MockKeyboard::LAYOUT_FRENCH, | |
717 L"\x00e0\x0026\x00e9\x0022\x0027\x0028\x002d\x00e8" | |
718 L"\x005f\x00e7\x0061\x0062\x0063\x0064\x0065\x0066" | |
719 L"\x0067\x0068\x0069\x006a\x006b\x006c\x006d\x006e" | |
720 L"\x006f\x0070\x0071\x0072\x0073\x0074\x0075\x0076" | |
721 L"\x0077\x0078\x0079\x007a\x0024\x003d\x002c\x003b" | |
722 L"\x003a\x00f9\x0029\x002a\x0021\x0030\x0031\x0032" | |
723 L"\x0033\x0034\x0035\x0036\x0037\x0038\x0039\x0041" | |
724 L"\x0042\x0043\x0044\x0045\x0046\x0047\x0048\x0049" | |
725 L"\x004a\x004b\x004c\x004d\x004e\x004f\x0050\x0051" | |
726 L"\x0052\x0053\x0054\x0055\x0056\x0057\x0058\x0059" | |
727 L"\x005a\x00a3\x002b\x003f\x002e\x002f\x0025\x00b0" | |
728 L"\x00b5\x00e0\x0026\x00e9\x0022\x0027\x0028\x002d" | |
729 L"\x00e8\x005f\x00e7\x0061\x0062\x0063\x0064\x0065" | |
730 L"\x0066\x0067\x0068\x0069\x006a\x006b\x006c\x006d" | |
731 L"\x006e\x006f\x0070\x0071\x0072\x0073\x0074\x0075" | |
732 L"\x0076\x0077\x0078\x0079\x007a\x0024\x003d\x002c" | |
733 L"\x003b\x003a\x00f9\x0029\x002a\x0021" | |
734 }, | |
735 {MockKeyboard::LAYOUT_RUSSIAN, | |
736 L"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037" | |
737 L"\x0038\x0039\x0444\x0438\x0441\x0432\x0443\x0430" | |
738 L"\x043f\x0440\x0448\x043e\x043b\x0434\x044c\x0442" | |
739 L"\x0449\x0437\x0439\x043a\x044b\x0435\x0433\x043c" | |
740 L"\x0446\x0447\x043d\x044f\x0436\x003d\x0431\x002d" | |
741 L"\x044e\x002e\x0451\x0445\x005c\x044a\x044d\x0029" | |
742 L"\x0021\x0022\x2116\x003b\x0025\x003a\x003f\x002a" | |
743 L"\x0028\x0424\x0418\x0421\x0412\x0423\x0410\x041f" | |
744 L"\x0420\x0428\x041e\x041b\x0414\x042c\x0422\x0429" | |
745 L"\x0417\x0419\x041a\x042b\x0415\x0413\x041c\x0426" | |
746 L"\x0427\x041d\x042f\x0416\x002b\x0411\x005f\x042e" | |
747 L"\x002c\x0401\x0425\x002f\x042a\x042d\x0030\x0031" | |
748 L"\x0032\x0033\x0034\x0035\x0036\x0037\x0038\x0039" | |
749 L"\x0444\x0438\x0441\x0432\x0443\x0430\x043f\x0440" | |
750 L"\x0448\x043e\x043b\x0434\x044c\x0442\x0449\x0437" | |
751 L"\x0439\x043a\x044b\x0435\x0433\x043c\x0446\x0447" | |
752 L"\x043d\x044f\x0436\x003d\x0431\x002d\x044e\x002e" | |
753 L"\x0451\x0445\x005c\x044a\x044d" | |
754 }, | |
755 #endif // defined(OS_WIN) | |
756 {MockKeyboard::LAYOUT_UNITED_STATES, | |
757 L"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037" | |
758 L"\x0038\x0039\x0061\x0062\x0063\x0064\x0065\x0066" | |
759 L"\x0067\x0068\x0069\x006a\x006b\x006c\x006d\x006e" | |
760 L"\x006f\x0070\x0071\x0072\x0073\x0074\x0075\x0076" | |
761 L"\x0077\x0078\x0079\x007a\x003b\x003d\x002c\x002d" | |
762 L"\x002e\x002f\x0060\x005b\x005c\x005d\x0027\x0029" | |
763 L"\x0021\x0040\x0023\x0024\x0025\x005e\x0026\x002a" | |
764 L"\x0028\x0041\x0042\x0043\x0044\x0045\x0046\x0047" | |
765 L"\x0048\x0049\x004a\x004b\x004c\x004d\x004e\x004f" | |
766 L"\x0050\x0051\x0052\x0053\x0054\x0055\x0056\x0057" | |
767 L"\x0058\x0059\x005a\x003a\x002b\x003c\x005f\x003e" | |
768 L"\x003f\x007e\x007b\x007c\x007d\x0022" | |
769 #if defined(OS_WIN) | |
770 // This is ifdefed out for Linux to correspond to the fact that we don't | |
771 // test alt+keystroke for now. | |
772 L"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037" | |
773 L"\x0038\x0039\x0061\x0062\x0063\x0064\x0065\x0066" | |
774 L"\x0067\x0068\x0069\x006a\x006b\x006c\x006d\x006e" | |
775 L"\x006f\x0070\x0071\x0072\x0073\x0074\x0075\x0076" | |
776 L"\x0077\x0078\x0079\x007a\x003b\x003d\x002c\x002d" | |
777 L"\x002e\x002f\x0060\x005b\x005c\x005d\x0027" | |
778 #endif | |
779 }, | |
780 }; | |
781 | |
782 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kLayouts); ++i) { | |
783 // Load an HTML page consisting of one <div> element. | |
784 // This <div> element is used by the EditorClientImpl class to insert | |
785 // characters received through the RenderWidget::OnHandleInputEvent() | |
786 // function. | |
787 view_->set_send_content_state_immediately(true); | |
788 LoadHTML("<html>" | |
789 "<head>" | |
790 "<title></title>" | |
791 "</head>" | |
792 "<body>" | |
793 "<div id='test' contenteditable='true'>" | |
794 "</div>" | |
795 "</body>" | |
796 "</html>"); | |
797 ExecuteJavaScript("document.getElementById('test').focus();"); | |
798 render_thread_.sink().ClearMessages(); | |
799 | |
800 // For each key code, we send three keyboard events. | |
801 // * Pressing only the key; | |
802 // * Pressing the key and a left-shift key, and; | |
803 // * Pressing the key and a right-alt (AltGr) key. | |
804 static const MockKeyboard::Modifiers kModifiers[] = { | |
805 MockKeyboard::NONE, | |
806 MockKeyboard::LEFT_SHIFT, | |
807 #if defined(OS_WIN) | |
808 MockKeyboard::RIGHT_ALT, | |
809 #endif | |
810 }; | |
811 | |
812 MockKeyboard::Layout layout = kLayouts[i].layout; | |
813 for (size_t j = 0; j < ARRAYSIZE_UNSAFE(kModifiers); ++j) { | |
814 // Virtual key codes used for this test. | |
815 static const int kKeyCodes[] = { | |
816 '0', '1', '2', '3', '4', '5', '6', '7', | |
817 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', | |
818 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', | |
819 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', | |
820 'W', 'X', 'Y', 'Z', | |
821 base::VKEY_OEM_1, | |
822 base::VKEY_OEM_PLUS, | |
823 base::VKEY_OEM_COMMA, | |
824 base::VKEY_OEM_MINUS, | |
825 base::VKEY_OEM_PERIOD, | |
826 base::VKEY_OEM_2, | |
827 base::VKEY_OEM_3, | |
828 base::VKEY_OEM_4, | |
829 base::VKEY_OEM_5, | |
830 base::VKEY_OEM_6, | |
831 base::VKEY_OEM_7, | |
832 #if defined(OS_WIN) | |
833 // Unclear how to handle this on Linux. | |
834 base::VKEY_OEM_8, | |
835 #endif | |
836 }; | |
837 | |
838 MockKeyboard::Modifiers modifiers = kModifiers[j]; | |
839 for (size_t k = 0; k < ARRAYSIZE_UNSAFE(kKeyCodes); ++k) { | |
840 // Send a keyboard event to the RenderView object. | |
841 // We should test a keyboard event only when the given keyboard-layout | |
842 // driver is installed in a PC and the driver can assign a Unicode | |
843 // charcter for the given tuple (layout, key-code, and modifiers). | |
844 int key_code = kKeyCodes[k]; | |
845 std::wstring char_code; | |
846 if (SendKeyEvent(layout, key_code, modifiers, &char_code) < 0) | |
847 continue; | |
848 } | |
849 } | |
850 | |
851 // Retrieve the text in the test page and compare it with the expected | |
852 // text created from a virtual-key code, a character code, and the | |
853 // modifier-key status. | |
854 const int kMaxOutputCharacters = 4096; | |
855 std::wstring output = UTF16ToWideHack( | |
856 GetMainFrame()->contentAsText(kMaxOutputCharacters)); | |
857 EXPECT_EQ(kLayouts[i].expected_result, output); | |
858 } | |
859 #else | |
860 NOTIMPLEMENTED(); | |
861 #endif | |
862 } | |
863 | |
864 TEST_F(RenderViewTest, DidFailProvisionalLoadWithErrorForError) { | |
865 GetMainFrame()->enableViewSourceMode(true); | |
866 WebURLError error; | |
867 error.domain.fromUTF8("test_domain"); | |
868 error.reason = net::ERR_FILE_NOT_FOUND; | |
869 error.unreachableURL = GURL("http://foo"); | |
870 WebFrame* web_frame = GetMainFrame(); | |
871 // An error occurred. | |
872 view_->didFailProvisionalLoad(web_frame, error); | |
873 // Frame should exit view-source mode. | |
874 EXPECT_FALSE(web_frame->isViewSourceModeEnabled()); | |
875 } | |
876 | |
877 TEST_F(RenderViewTest, DidFailProvisionalLoadWithErrorForCancellation) { | |
878 GetMainFrame()->enableViewSourceMode(true); | |
879 WebURLError error; | |
880 error.domain.fromUTF8("test_domain"); | |
881 error.reason = net::ERR_ABORTED; | |
882 error.unreachableURL = GURL("http://foo"); | |
883 WebFrame* web_frame = GetMainFrame(); | |
884 // A cancellation occurred. | |
885 view_->didFailProvisionalLoad(web_frame, error); | |
886 // Frame should stay in view-source mode. | |
887 EXPECT_TRUE(web_frame->isViewSourceModeEnabled()); | |
888 } | |
889 | |
890 // Regression test for http://crbug.com/35011 | |
891 TEST_F(RenderViewTest, JSBlockSentAfterPageLoad) { | |
892 // 1. Load page with JS. | |
893 std::string html = "<html>" | |
894 "<head>" | |
895 "<script>document.createElement('div');</script>" | |
896 "</head>" | |
897 "<body>" | |
898 "</body>" | |
899 "</html>"; | |
900 render_thread_.sink().ClearMessages(); | |
901 LoadHTML(html.c_str()); | |
902 | |
903 // 2. Block JavaScript. | |
904 ContentSettings settings; | |
905 for (int i = 0; i < CONTENT_SETTINGS_NUM_TYPES; ++i) | |
906 settings.settings[i] = CONTENT_SETTING_ALLOW; | |
907 settings.settings[CONTENT_SETTINGS_TYPE_JAVASCRIPT] = CONTENT_SETTING_BLOCK; | |
908 view_->SetContentSettings(settings); | |
909 | |
910 // Make sure no pending messages are in the queue. | |
911 ProcessPendingMessages(); | |
912 render_thread_.sink().ClearMessages(); | |
913 | |
914 // 3. Reload page. | |
915 ViewMsg_Navigate_Params params = { 0 }; | |
916 std::string url_str = "data:text/html;charset=utf-8,"; | |
917 url_str.append(html); | |
918 GURL url(url_str); | |
919 params.url = url; | |
920 params.navigation_type = ViewMsg_Navigate_Params::RELOAD; | |
921 view_->OnNavigate(params); | |
922 ProcessPendingMessages(); | |
923 | |
924 // 4. Verify that the notification that javascript was blocked is sent after | |
925 // the navigation notifiction is sent. | |
926 int navigation_index = -1; | |
927 int block_index = -1; | |
928 for (size_t i = 0; i < render_thread_.sink().message_count(); ++i) { | |
929 const IPC::Message* msg = render_thread_.sink().GetMessageAt(i); | |
930 if (msg->type() == ViewHostMsg_FrameNavigate::ID) | |
931 navigation_index = i; | |
932 if (msg->type() == ViewHostMsg_ContentBlocked::ID) | |
933 block_index = i; | |
934 } | |
935 EXPECT_NE(-1, navigation_index); | |
936 EXPECT_NE(-1, block_index); | |
937 EXPECT_LT(navigation_index, block_index); | |
938 } | |
939 | |
940 // Regression test for http://crbug.com/41562 | |
941 TEST_F(RenderViewTest, UpdateTargetURLWithInvalidURL) { | |
942 const GURL invalid_gurl("http://"); | |
943 view_->setMouseOverURL(WebKit::WebURL(invalid_gurl)); | |
944 EXPECT_EQ(invalid_gurl, view_->target_url_); | |
945 } | |
946 | |
947 TEST_F(RenderViewTest, SendForms) { | |
948 // Don't want any delay for form state sync changes. This will still post a | |
949 // message so updates will get coalesced, but as soon as we spin the message | |
950 // loop, it will generate an update. | |
951 view_->set_send_content_state_immediately(true); | |
952 | |
953 LoadHTML("<form method=\"POST\">" | |
954 " <input type=\"text\" id=\"firstname\"/>" | |
955 " <input type=\"text\" id=\"middlename\" autoComplete=\"off\"/>" | |
956 " <input type=\"hidden\" id=\"lastname\"/>" | |
957 "</form>"); | |
958 | |
959 // Verify that "FormsSeen" sends the expected number of fields. | |
960 ProcessPendingMessages(); | |
961 const IPC::Message* message = render_thread_.sink().GetUniqueMessageMatching( | |
962 ViewHostMsg_FormsSeen::ID); | |
963 ASSERT_NE(static_cast<IPC::Message*>(NULL), message); | |
964 ViewHostMsg_FormsSeen::Param params; | |
965 ViewHostMsg_FormsSeen::Read(message, ¶ms); | |
966 const std::vector<FormData>& forms = params.a; | |
967 ASSERT_EQ(1UL, forms.size()); | |
968 ASSERT_EQ(3UL, forms[0].fields.size()); | |
969 EXPECT_TRUE(forms[0].fields[0].StrictlyEqualsHack( | |
970 FormField(string16(), | |
971 ASCIIToUTF16("firstname"), | |
972 string16(), | |
973 ASCIIToUTF16("text"), | |
974 20))) << forms[0].fields[0]; | |
975 EXPECT_TRUE(forms[0].fields[1].StrictlyEqualsHack( | |
976 FormField(string16(), | |
977 ASCIIToUTF16("middlename"), | |
978 string16(), | |
979 ASCIIToUTF16("text"), | |
980 20))) << forms[0].fields[1]; | |
981 EXPECT_TRUE(forms[0].fields[2].StrictlyEqualsHack( | |
982 FormField(string16(), | |
983 ASCIIToUTF16("lastname"), | |
984 string16(), | |
985 ASCIIToUTF16("hidden"), | |
986 0))) << forms[0].fields[2]; | |
987 | |
988 // Verify that |didAcceptAutoFillSuggestion()| sends the expected number of | |
989 // fields. | |
990 WebFrame* web_frame = GetMainFrame(); | |
991 WebDocument document = web_frame->document(); | |
992 WebInputElement firstname = | |
993 document.getElementById("firstname").to<WebInputElement>(); | |
994 | |
995 // Accept suggestion that contains a label. Labeled items indicate AutoFill | |
996 // as opposed to Autocomplete. We're testing this distinction below with | |
997 // the |ViewHostMsg_FillAutoFillFormData::ID| message. | |
998 view_->didAcceptAutoFillSuggestion(firstname, | |
999 WebKit::WebString::fromUTF8("Johnny"), | |
1000 WebKit::WebString::fromUTF8("Home"), | |
1001 1, | |
1002 -1); | |
1003 | |
1004 ProcessPendingMessages(); | |
1005 const IPC::Message* message2 = render_thread_.sink().GetUniqueMessageMatching( | |
1006 ViewHostMsg_FillAutoFillFormData::ID); | |
1007 ASSERT_NE(static_cast<IPC::Message*>(NULL), message2); | |
1008 ViewHostMsg_FillAutoFillFormData::Param params2; | |
1009 ViewHostMsg_FillAutoFillFormData::Read(message2, ¶ms2); | |
1010 const FormData& form2 = params2.b; | |
1011 ASSERT_EQ(3UL, form2.fields.size()); | |
1012 EXPECT_TRUE(form2.fields[0].StrictlyEqualsHack( | |
1013 FormField(string16(), | |
1014 ASCIIToUTF16("firstname"), | |
1015 string16(), | |
1016 ASCIIToUTF16("text"), | |
1017 20))) << form2.fields[0]; | |
1018 EXPECT_TRUE(form2.fields[1].StrictlyEqualsHack( | |
1019 FormField(string16(), | |
1020 ASCIIToUTF16("middlename"), | |
1021 string16(), | |
1022 ASCIIToUTF16("text"), | |
1023 20))) << form2.fields[1]; | |
1024 EXPECT_TRUE(form2.fields[2].StrictlyEqualsHack( | |
1025 FormField(string16(), | |
1026 ASCIIToUTF16("lastname"), | |
1027 string16(), | |
1028 ASCIIToUTF16("hidden"), | |
1029 0))) << form2.fields[2]; | |
1030 } | |
1031 | |
1032 TEST_F(RenderViewTest, FillFormElement) { | |
1033 // Don't want any delay for form state sync changes. This will still post a | |
1034 // message so updates will get coalesced, but as soon as we spin the message | |
1035 // loop, it will generate an update. | |
1036 view_->set_send_content_state_immediately(true); | |
1037 | |
1038 LoadHTML("<form method=\"POST\">" | |
1039 " <input type=\"text\" id=\"firstname\"/>" | |
1040 " <input type=\"text\" id=\"middlename\"/>" | |
1041 "</form>"); | |
1042 | |
1043 // Verify that "FormsSeen" sends the expected number of fields. | |
1044 ProcessPendingMessages(); | |
1045 const IPC::Message* message = render_thread_.sink().GetUniqueMessageMatching( | |
1046 ViewHostMsg_FormsSeen::ID); | |
1047 ASSERT_NE(static_cast<IPC::Message*>(NULL), message); | |
1048 ViewHostMsg_FormsSeen::Param params; | |
1049 ViewHostMsg_FormsSeen::Read(message, ¶ms); | |
1050 const std::vector<FormData>& forms = params.a; | |
1051 ASSERT_EQ(1UL, forms.size()); | |
1052 ASSERT_EQ(2UL, forms[0].fields.size()); | |
1053 EXPECT_TRUE(forms[0].fields[0].StrictlyEqualsHack( | |
1054 FormField(string16(), | |
1055 ASCIIToUTF16("firstname"), | |
1056 string16(), | |
1057 ASCIIToUTF16("text"), | |
1058 20))) << forms[0].fields[0]; | |
1059 EXPECT_TRUE(forms[0].fields[1].StrictlyEqualsHack( | |
1060 FormField(string16(), | |
1061 ASCIIToUTF16("middlename"), | |
1062 string16(), | |
1063 ASCIIToUTF16("text"), | |
1064 20))) << forms[0].fields[1]; | |
1065 | |
1066 // Verify that |didAcceptAutoFillSuggestion()| sets the value of the expected | |
1067 // field. | |
1068 WebFrame* web_frame = GetMainFrame(); | |
1069 WebDocument document = web_frame->document(); | |
1070 WebInputElement firstname = | |
1071 document.getElementById("firstname").to<WebInputElement>(); | |
1072 WebInputElement middlename = | |
1073 document.getElementById("middlename").to<WebInputElement>(); | |
1074 middlename.setAutofilled(true); | |
1075 | |
1076 // Accept a suggestion in a form that has been auto-filled. This triggers | |
1077 // the direct filling of the firstname element with value parameter. | |
1078 view_->didAcceptAutoFillSuggestion(firstname, | |
1079 WebKit::WebString::fromUTF8("David"), | |
1080 WebKit::WebString(), | |
1081 0, | |
1082 0); | |
1083 | |
1084 ProcessPendingMessages(); | |
1085 const IPC::Message* message2 = render_thread_.sink().GetUniqueMessageMatching( | |
1086 ViewHostMsg_FillAutoFillFormData::ID); | |
1087 | |
1088 // No message should be sent in this case. |firstname| is filled directly. | |
1089 ASSERT_EQ(static_cast<IPC::Message*>(NULL), message2); | |
1090 EXPECT_EQ(firstname.value(), WebKit::WebString::fromUTF8("David")); | |
1091 } | |
OLD | NEW |