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   <html>
     54   <head><title></title>
     55   <script type='text/javascript' language='javascript'>
     56   function OnKeyEvent(ev) {
     57     var result = document.getElementById(ev.type);
     58     result.innerText = (ev.which || ev.keyCode) + ',' +
     59       ev.shiftKey + ',' +
     60       ev.ctrlKey + ',' +
     61       ev.metaKey + ',' +
     62       ev.altKey;
     63     return %s;  /* Replace with "return true;" when testing in an html file. */
     64   }
     65   function OnScroll(ev) {
     66     var result = document.getElementById("scroll");
     67     result.innerText = window.pageYOffset;
     68     return true;
     69   }
     70   </script>
     71   <style type="text/css">
     72   p { border-bottom:5000px solid black; } /* enforce vertical scroll bar */
     73   </style>
     74   </head>
     75   <body
     76     onscroll='return OnScroll(event);'
     77     onkeydown='return OnKeyEvent(event);'>
     78   <div id='keydown' contenteditable='true'> </div>
     79   <div id='scroll' contenteditable='true'> </div>
     80   <p>p1
     81   <p>p2
     82   </body>
     83   </html>
     84   );
     85   #undef HTML
     86 
     87   WebPreferences prefs;
     88   prefs.enable_scroll_animator = false;
     89 
     90   RenderViewImpl* view = static_cast<RenderViewImpl*>(view_);
     91   view->OnUpdateWebPreferences(prefs);
     92 
     93   const int kMaxOutputCharacters = 1024;
     94   string16 output;
     95   char htmlBuffer[2048];
     96 
     97   NSEvent* arrowDownKeyDown = CmdDeadKeyEvent(NSKeyDown, kVK_DownArrow);
     98   NSEvent* arrowUpKeyDown = CmdDeadKeyEvent(NSKeyDown, kVK_UpArrow);
     99 
    100   // First test when javascript does not eat keypresses -- should scroll.
    101   sprintf(htmlBuffer, kRawHtml, "true");
    102   view->set_send_content_state_immediately(true);
    103   LoadHTML(htmlBuffer);
    104   render_thread_->sink().ClearMessages();
    105 
    106   const char* kArrowDownScrollDown =
    107       "40,false,false,true,false\n10128\np1\n\np2";
    108   view->OnSetEditCommandsForNextKeyEvent(
    109       EditCommands(1, EditCommand("moveToEndOfDocument", "")));
    110   SendNativeKeyEvent(NativeWebKeyboardEvent(arrowDownKeyDown));
    111   ProcessPendingMessages();
    112   output = GetMainFrame()->contentAsText(kMaxOutputCharacters);
    113   EXPECT_EQ(kArrowDownScrollDown, UTF16ToASCII(output));
    114 
    115   const char* kArrowUpScrollUp =
    116       "38,false,false,true,false\n0\np1\n\np2";
    117   view->OnSetEditCommandsForNextKeyEvent(
    118       EditCommands(1, EditCommand("moveToBeginningOfDocument", "")));
    119   SendNativeKeyEvent(NativeWebKeyboardEvent(arrowUpKeyDown));
    120   ProcessPendingMessages();
    121   output = GetMainFrame()->contentAsText(kMaxOutputCharacters);
    122   EXPECT_EQ(kArrowUpScrollUp, UTF16ToASCII(output));
    123 
    124 
    125   // Now let javascript eat the key events -- no scrolling should happen
    126   sprintf(htmlBuffer, kRawHtml, "false");
    127   view->set_send_content_state_immediately(true);
    128   LoadHTML(htmlBuffer);
    129   render_thread_->sink().ClearMessages();
    130 
    131   const char* kArrowDownNoScroll =
    132       "40,false,false,true,false\np1\n\np2";
    133   view->OnSetEditCommandsForNextKeyEvent(
    134       EditCommands(1, EditCommand("moveToEndOfDocument", "")));
    135   SendNativeKeyEvent(NativeWebKeyboardEvent(arrowDownKeyDown));
    136   ProcessPendingMessages();
    137   output = GetMainFrame()->contentAsText(kMaxOutputCharacters);
    138   EXPECT_EQ(kArrowDownNoScroll, UTF16ToASCII(output));
    139 
    140   const char* kArrowUpNoScroll =
    141       "38,false,false,true,false\np1\n\np2";
    142   view->OnSetEditCommandsForNextKeyEvent(
    143       EditCommands(1, EditCommand("moveToBeginningOfDocument", "")));
    144   SendNativeKeyEvent(NativeWebKeyboardEvent(arrowUpKeyDown));
    145   ProcessPendingMessages();
    146   output = GetMainFrame()->contentAsText(kMaxOutputCharacters);
    147   EXPECT_EQ(kArrowUpNoScroll, UTF16ToASCII(output));
    148 }
    149 
    150 }  // namespace content
    151