Home | History | Annotate | Download | only in renderer
      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