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