1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "base/strings/string16.h" 6 #include "base/strings/string_util.h" 7 #include "base/strings/utf_string_conversions.h" 8 #include "content/public/browser/native_web_keyboard_event.h" 9 #include "content/public/common/web_preferences.h" 10 #include "content/public/test/render_view_test.h" 11 #include "content/renderer/render_view_impl.h" 12 #include "testing/gtest/include/gtest/gtest.h" 13 #include "third_party/WebKit/public/web/WebLocalFrame.h" 14 15 #include <Carbon/Carbon.h> // for the kVK_* constants. 16 #include <Cocoa/Cocoa.h> 17 18 namespace content { 19 20 NSEvent* CmdDeadKeyEvent(NSEventType type, unsigned short code) { 21 UniChar uniChar = 0; 22 switch(code) { 23 case kVK_UpArrow: 24 uniChar = NSUpArrowFunctionKey; 25 break; 26 case kVK_DownArrow: 27 uniChar = NSDownArrowFunctionKey; 28 break; 29 default: 30 CHECK(false); 31 } 32 NSString* s = [NSString stringWithFormat:@"%C", uniChar]; 33 34 return [NSEvent keyEventWithType:type 35 location:NSZeroPoint 36 modifierFlags:NSCommandKeyMask 37 timestamp:0.0 38 windowNumber:0 39 context:nil 40 characters:s 41 charactersIgnoringModifiers:s 42 isARepeat:NO 43 keyCode:code]; 44 } 45 46 // Test that cmd-up/down scrolls the page exactly if it is not intercepted by 47 // javascript. 48 TEST_F(RenderViewTest, MacTestCmdUp) { 49 // Some preprocessor trickery so that we can have literal html in our source, 50 // makes it easier to copy html to and from an html file for testing (the 51 // preprocessor will remove the newlines at the line ends, turning this into 52 // a single long line). 53 #define HTML(s) #s 54 const char* kRawHtml = HTML( 55 <!DOCTYPE html> 56 <style> 57 /* Add a vertical scrollbar */ 58 body { height: 10128px; } 59 </style> 60 <div id='keydown'></div> 61 <div id='scroll'></div> 62 <script> 63 var allowKeyEvents = true; 64 var scroll = document.getElementById('scroll'); 65 var result = document.getElementById('keydown'); 66 onkeydown = function(event) { 67 result.textContent = 68 event.keyCode + ',' + 69 event.shiftKey + ',' + 70 event.ctrlKey + ',' + 71 event.metaKey + ',' + 72 event.altKey; 73 return allowKeyEvents; 74 } 75 </script> 76 <!-- 77 TODO(esprehn): For some strange reason we need a non-empty document for 78 scrolling to work. This is not the case in a real browser only in the test. 79 --> 80 <p>p1 81 ); 82 #undef HTML 83 84 WebPreferences prefs; 85 prefs.enable_scroll_animator = false; 86 87 RenderViewImpl* view = static_cast<RenderViewImpl*>(view_); 88 view->OnUpdateWebPreferences(prefs); 89 90 const int kMaxOutputCharacters = 1024; 91 base::string16 output; 92 93 NSEvent* arrowDownKeyDown = CmdDeadKeyEvent(NSKeyDown, kVK_DownArrow); 94 NSEvent* arrowUpKeyDown = CmdDeadKeyEvent(NSKeyDown, kVK_UpArrow); 95 96 // First test when javascript does not eat keypresses -- should scroll. 97 view->set_send_content_state_immediately(true); 98 LoadHTML(kRawHtml); 99 render_thread_->sink().ClearMessages(); 100 101 const char* kArrowDownScrollDown = "40,false,false,true,false\n10144\np1"; 102 view->OnSetEditCommandsForNextKeyEvent( 103 EditCommands(1, EditCommand("moveToEndOfDocument", ""))); 104 SendNativeKeyEvent(NativeWebKeyboardEvent(arrowDownKeyDown)); 105 ProcessPendingMessages(); 106 ExecuteJavaScript("scroll.textContent = window.pageYOffset"); 107 output = GetMainFrame()->contentAsText(kMaxOutputCharacters); 108 EXPECT_EQ(kArrowDownScrollDown, base::UTF16ToASCII(output)); 109 110 const char* kArrowUpScrollUp = "38,false,false,true,false\n0\np1"; 111 view->OnSetEditCommandsForNextKeyEvent( 112 EditCommands(1, EditCommand("moveToBeginningOfDocument", ""))); 113 SendNativeKeyEvent(NativeWebKeyboardEvent(arrowUpKeyDown)); 114 ProcessPendingMessages(); 115 ExecuteJavaScript("scroll.textContent = window.pageYOffset"); 116 output = GetMainFrame()->contentAsText(kMaxOutputCharacters); 117 EXPECT_EQ(kArrowUpScrollUp, base::UTF16ToASCII(output)); 118 119 // Now let javascript eat the key events -- no scrolling should happen. 120 // Set a scroll position slightly down the page to ensure that it does not 121 // move. 122 ExecuteJavaScript("allowKeyEvents = false; window.scrollTo(0, 100)"); 123 124 const char* kArrowDownNoScroll = "40,false,false,true,false\n100\np1"; 125 view->OnSetEditCommandsForNextKeyEvent( 126 EditCommands(1, EditCommand("moveToEndOfDocument", ""))); 127 SendNativeKeyEvent(NativeWebKeyboardEvent(arrowDownKeyDown)); 128 ProcessPendingMessages(); 129 ExecuteJavaScript("scroll.textContent = window.pageYOffset"); 130 output = GetMainFrame()->contentAsText(kMaxOutputCharacters); 131 EXPECT_EQ(kArrowDownNoScroll, base::UTF16ToASCII(output)); 132 133 const char* kArrowUpNoScroll = "38,false,false,true,false\n100\np1"; 134 view->OnSetEditCommandsForNextKeyEvent( 135 EditCommands(1, EditCommand("moveToBeginningOfDocument", ""))); 136 SendNativeKeyEvent(NativeWebKeyboardEvent(arrowUpKeyDown)); 137 ProcessPendingMessages(); 138 ExecuteJavaScript("scroll.textContent = window.pageYOffset"); 139 output = GetMainFrame()->contentAsText(kMaxOutputCharacters); 140 EXPECT_EQ(kArrowUpNoScroll, base::UTF16ToASCII(output)); 141 } 142 143 } // namespace content 144