| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "base/strings/string16.h" |
| #include "base/strings/string_util.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "content/public/browser/native_web_keyboard_event.h" |
| #include "content/public/common/web_preferences.h" |
| #include "content/public/test/render_view_test.h" |
| #include "content/renderer/render_view_impl.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "third_party/WebKit/public/web/WebLocalFrame.h" |
| |
| #include <Carbon/Carbon.h> // for the kVK_* constants. |
| #include <Cocoa/Cocoa.h> |
| |
| namespace content { |
| |
| NSEvent* CmdDeadKeyEvent(NSEventType type, unsigned short code) { |
| UniChar uniChar = 0; |
| switch(code) { |
| case kVK_UpArrow: |
| uniChar = NSUpArrowFunctionKey; |
| break; |
| case kVK_DownArrow: |
| uniChar = NSDownArrowFunctionKey; |
| break; |
| default: |
| CHECK(false); |
| } |
| NSString* s = [NSString stringWithFormat:@"%C", uniChar]; |
| |
| return [NSEvent keyEventWithType:type |
| location:NSZeroPoint |
| modifierFlags:NSCommandKeyMask |
| timestamp:0.0 |
| windowNumber:0 |
| context:nil |
| characters:s |
| charactersIgnoringModifiers:s |
| isARepeat:NO |
| keyCode:code]; |
| } |
| |
| // Test that cmd-up/down scrolls the page exactly if it is not intercepted by |
| // javascript. |
| TEST_F(RenderViewTest, MacTestCmdUp) { |
| // Some preprocessor trickery so that we can have literal html in our source, |
| // makes it easier to copy html to and from an html file for testing (the |
| // preprocessor will remove the newlines at the line ends, turning this into |
| // a single long line). |
| #define HTML(s) #s |
| const char* kRawHtml = HTML( |
| <!DOCTYPE html> |
| <style> |
| /* Add a vertical scrollbar */ |
| body { height: 10128px; } |
| </style> |
| <div id='keydown'></div> |
| <div id='scroll'></div> |
| <script> |
| var allowKeyEvents = true; |
| var scroll = document.getElementById('scroll'); |
| var result = document.getElementById('keydown'); |
| onkeydown = function(event) { |
| result.textContent = |
| event.keyCode + ',' + |
| event.shiftKey + ',' + |
| event.ctrlKey + ',' + |
| event.metaKey + ',' + |
| event.altKey; |
| return allowKeyEvents; |
| } |
| </script> |
| <!-- |
| TODO(esprehn): For some strange reason we need a non-empty document for |
| scrolling to work. This is not the case in a real browser only in the test. |
| --> |
| <p>p1 |
| ); |
| #undef HTML |
| |
| WebPreferences prefs; |
| prefs.enable_scroll_animator = false; |
| |
| RenderViewImpl* view = static_cast<RenderViewImpl*>(view_); |
| view->OnUpdateWebPreferences(prefs); |
| |
| const int kMaxOutputCharacters = 1024; |
| base::string16 output; |
| |
| NSEvent* arrowDownKeyDown = CmdDeadKeyEvent(NSKeyDown, kVK_DownArrow); |
| NSEvent* arrowUpKeyDown = CmdDeadKeyEvent(NSKeyDown, kVK_UpArrow); |
| |
| // First test when javascript does not eat keypresses -- should scroll. |
| view->set_send_content_state_immediately(true); |
| LoadHTML(kRawHtml); |
| render_thread_->sink().ClearMessages(); |
| |
| const char* kArrowDownScrollDown = "40,false,false,true,false\n10144\np1"; |
| view->OnSetEditCommandsForNextKeyEvent( |
| EditCommands(1, EditCommand("moveToEndOfDocument", ""))); |
| SendNativeKeyEvent(NativeWebKeyboardEvent(arrowDownKeyDown)); |
| ProcessPendingMessages(); |
| ExecuteJavaScript("scroll.textContent = window.pageYOffset"); |
| output = GetMainFrame()->contentAsText(kMaxOutputCharacters); |
| EXPECT_EQ(kArrowDownScrollDown, base::UTF16ToASCII(output)); |
| |
| const char* kArrowUpScrollUp = "38,false,false,true,false\n0\np1"; |
| view->OnSetEditCommandsForNextKeyEvent( |
| EditCommands(1, EditCommand("moveToBeginningOfDocument", ""))); |
| SendNativeKeyEvent(NativeWebKeyboardEvent(arrowUpKeyDown)); |
| ProcessPendingMessages(); |
| ExecuteJavaScript("scroll.textContent = window.pageYOffset"); |
| output = GetMainFrame()->contentAsText(kMaxOutputCharacters); |
| EXPECT_EQ(kArrowUpScrollUp, base::UTF16ToASCII(output)); |
| |
| // Now let javascript eat the key events -- no scrolling should happen. |
| // Set a scroll position slightly down the page to ensure that it does not |
| // move. |
| ExecuteJavaScript("allowKeyEvents = false; window.scrollTo(0, 100)"); |
| |
| const char* kArrowDownNoScroll = "40,false,false,true,false\n100\np1"; |
| view->OnSetEditCommandsForNextKeyEvent( |
| EditCommands(1, EditCommand("moveToEndOfDocument", ""))); |
| SendNativeKeyEvent(NativeWebKeyboardEvent(arrowDownKeyDown)); |
| ProcessPendingMessages(); |
| ExecuteJavaScript("scroll.textContent = window.pageYOffset"); |
| output = GetMainFrame()->contentAsText(kMaxOutputCharacters); |
| EXPECT_EQ(kArrowDownNoScroll, base::UTF16ToASCII(output)); |
| |
| const char* kArrowUpNoScroll = "38,false,false,true,false\n100\np1"; |
| view->OnSetEditCommandsForNextKeyEvent( |
| EditCommands(1, EditCommand("moveToBeginningOfDocument", ""))); |
| SendNativeKeyEvent(NativeWebKeyboardEvent(arrowUpKeyDown)); |
| ProcessPendingMessages(); |
| ExecuteJavaScript("scroll.textContent = window.pageYOffset"); |
| output = GetMainFrame()->contentAsText(kMaxOutputCharacters); |
| EXPECT_EQ(kArrowUpNoScroll, base::UTF16ToASCII(output)); |
| } |
| |
| } // namespace content |