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