| 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 |