diff options
author | thakis@chromium.org <thakis@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-09-29 03:56:51 +0000 |
---|---|---|
committer | thakis@chromium.org <thakis@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-09-29 03:56:51 +0000 |
commit | 507b33eab2acbb4e360b5b6eb9f2e666079d0e3b (patch) | |
tree | 6fd3dd864e9da3e68efc7ded0dbaf96b597fcd3c | |
parent | 529338471fec2ab9b07bac9b07e3477b20e0ae28 (diff) | |
download | chromium_src-507b33eab2acbb4e360b5b6eb9f2e666079d0e3b.zip chromium_src-507b33eab2acbb4e360b5b6eb9f2e666079d0e3b.tar.gz chromium_src-507b33eab2acbb4e360b5b6eb9f2e666079d0e3b.tar.bz2 |
Fix cmd-up/cmd-down.
The approach is to special-case moveToBeginningOfDocument and moveToEndOfDocument in WebFrameImpl::executeCommand(). With this (and the cocoa keyboard bindings patch being landed), the special-case code in WebViewImpl::ScrollViewWithKeyboard() can be removed.
Also add a test for cmd-up/down.
Change chrome.gyp so that it supports osx-only unit tests (_unittest_mac.mm).
Move OnPrintPageAsBitmap to the other printing tests.
BUG=22585
TEST=Go to a page with both text box and scrollbar (e.g. http://en.wikipedia.org ). Pressing cmd-down should scroll to end of page, cmd-up back to start. Clicking the text box and trying some emacs shortcuts should work (ctrl-a jumps to start of line, cmd-h acts as backspace, etc).
Review URL: http://codereview.chromium.org/254002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@27464 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/chrome.gyp | 5 | ||||
-rw-r--r-- | chrome/renderer/render_view.cc | 7 | ||||
-rw-r--r-- | chrome/renderer/render_view.h | 3 | ||||
-rw-r--r-- | chrome/renderer/render_view_unittest.cc | 84 | ||||
-rw-r--r-- | chrome/renderer/render_view_unittest_mac.mm | 132 | ||||
-rw-r--r-- | chrome/test/render_view_test.cc | 23 | ||||
-rw-r--r-- | chrome/test/render_view_test.h | 4 | ||||
-rw-r--r-- | webkit/glue/webframe_impl.cc | 19 | ||||
-rw-r--r-- | webkit/glue/webview_impl.cc | 33 | ||||
-rw-r--r-- | webkit/glue/webview_impl.h | 5 |
10 files changed, 234 insertions, 81 deletions
diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp index 7b09ee6..0a39bce 100644 --- a/chrome/chrome.gyp +++ b/chrome/chrome.gyp @@ -166,7 +166,7 @@ 'target_defaults': { 'sources/': [ ['exclude', '/(cocoa|gtk|win)/'], - ['exclude', '_(cocoa|gtk|linux|mac|posix|skia|win|views|x)(_unittest)?\\.(cc|mm?)$'], + ['exclude', '_(cocoa|gtk|linux|mac|posix|skia|win|views|x)(_unittest)?(_mac)?\\.(cc|mm?)$'], ['exclude', '/(gtk|win|x11)_[^/]*\\.cc$'], ], 'conditions': [ @@ -177,7 +177,7 @@ ]}], ['OS=="mac"', {'sources/': [ ['include', '/cocoa/'], - ['include', '_(cocoa|mac|posix)(_unittest)?\\.(cc|mm?)$'], + ['include', '_(cocoa|mac|posix)(_unittest)?(_mac)?\\.(cc|mm?)$'], ]}, { # else: OS != "mac" 'sources/': [ ['exclude', '\\.mm?$'], @@ -4434,6 +4434,7 @@ 'renderer/render_process_unittest.cc', 'renderer/render_thread_unittest.cc', 'renderer/render_view_unittest.cc', + 'renderer/render_view_unittest_mac.mm', 'renderer/render_widget_unittest.cc', 'renderer/renderer_main_unittest.cc', 'test/browser_with_test_window_test.cc', diff --git a/chrome/renderer/render_view.cc b/chrome/renderer/render_view.cc index 66ac3bf..8d9b3dd 100644 --- a/chrome/renderer/render_view.cc +++ b/chrome/renderer/render_view.cc @@ -1511,13 +1511,18 @@ bool RenderView::handleCurrentKeyboardEvent() { EditCommands::iterator it = edit_commands_.begin(); EditCommands::iterator end = edit_commands_.end(); + bool did_execute_command = false; for (; it != end; ++it) { + // In gtk, it's possible to bind multiple edit commands to one key (but it's + // the exception). Once one edit command is not executed, it seems safest to + // not execute the rest. if (!frame->executeCommand(WebString::fromUTF8(it->name), WebString::fromUTF8(it->value))) break; + did_execute_command = true; } - return true; + return did_execute_command; } void RenderView::spellCheck( diff --git a/chrome/renderer/render_view.h b/chrome/renderer/render_view.h index decad59..ae0732a 100644 --- a/chrome/renderer/render_view.h +++ b/chrome/renderer/render_view.h @@ -448,6 +448,9 @@ class RenderView : public RenderWidget, FRIEND_TEST(RenderViewTest, PrintLayoutTest); FRIEND_TEST(RenderViewTest, OnHandleKeyboardEvent); FRIEND_TEST(RenderViewTest, InsertCharacters); +#if defined(OS_MACOSX) + FRIEND_TEST(RenderViewTest, MacTestCmdUp); +#endif explicit RenderView(RenderThreadBase* render_thread, const WebPreferences& webkit_preferences); diff --git a/chrome/renderer/render_view_unittest.cc b/chrome/renderer/render_view_unittest.cc index 5e10179..3119996 100644 --- a/chrome/renderer/render_view_unittest.cc +++ b/chrome/renderer/render_view_unittest.cc @@ -496,6 +496,48 @@ TEST_F(RenderViewTest, PrintLayoutTest) { #endif } +// Print page as bitmap test. +TEST_F(RenderViewTest, OnPrintPageAsBitmap) { +#if defined(OS_WIN) + // Lets simulate a print pages with Hello world. + LoadHTML("<body><p>Hello world!</p></body>"); + + // Grab the printer settings from the printer. + ViewMsg_Print_Params print_settings; + MockPrinter* printer(render_thread_.printer()); + printer->GetDefaultPrintSettings(&print_settings); + ViewMsg_PrintPage_Params page_params = ViewMsg_PrintPage_Params(); + page_params.params = print_settings; + page_params.page_number = 0; + + // Fetch the image data from the web frame. + std::vector<unsigned char> data; + view_->print_helper()->PrintPageAsJPEG(page_params, + view_->webview()->GetMainFrame(), + 1.0f, + &data); + std::vector<unsigned char> decoded; + int w, h; + EXPECT_TRUE(JPEGCodec::Decode(&data[0], data.size(), JPEGCodec::FORMAT_RGBA, + &decoded, &w, &h)); + + // Check if its not 100% white. + bool is_white = true; + for (int y = 0; y < h; y++) { + for (int x = 0; x < w; x++) { + unsigned char* px = &decoded[(y * w + x) * 4]; + if (px[0] != 0xFF && px[1] != 0xFF && px[2] != 0xFF) { + is_white = false; + break; + } + } + } + ASSERT_TRUE(!is_white); +#else + NOTIMPLEMENTED(); +#endif +} + // Test that we can receive correct DOM events when we send input events // through the RenderWidget::OnHandleInputEvent() function. TEST_F(RenderViewTest, OnHandleKeyboardEvent) { @@ -868,45 +910,3 @@ TEST_F(RenderViewTest, DidFailProvisionalLoadWithErrorForCancellation) { // Frame should stay in view-source mode. EXPECT_TRUE(web_frame->isViewSourceModeEnabled()); } - -// Print page as bitmap test. -TEST_F(RenderViewTest, OnPrintPageAsBitmap) { -#if defined(OS_WIN) - // Lets simulate a print pages with Hello world. - LoadHTML("<body><p>Hello world!</p></body>"); - - // Grab the printer settings from the printer. - ViewMsg_Print_Params print_settings; - MockPrinter* printer(render_thread_.printer()); - printer->GetDefaultPrintSettings(&print_settings); - ViewMsg_PrintPage_Params page_params = ViewMsg_PrintPage_Params(); - page_params.params = print_settings; - page_params.page_number = 0; - - // Fetch the image data from the web frame. - std::vector<unsigned char> data; - view_->print_helper()->PrintPageAsJPEG(page_params, - view_->webview()->GetMainFrame(), - 1.0f, - &data); - std::vector<unsigned char> decoded; - int w, h; - EXPECT_TRUE(JPEGCodec::Decode(&data[0], data.size(), JPEGCodec::FORMAT_RGBA, - &decoded, &w, &h)); - - // Check if its not 100% white. - bool is_white = true; - for (int y = 0; y < h; y++) { - for (int x = 0; x < w; x++) { - unsigned char* px = &decoded[(y * w + x) * 4]; - if (px[0] != 0xFF && px[1] != 0xFF && px[2] != 0xFF) { - is_white = false; - break; - } - } - } - ASSERT_TRUE(!is_white); -#else - NOTIMPLEMENTED(); -#endif -} diff --git a/chrome/renderer/render_view_unittest_mac.mm b/chrome/renderer/render_view_unittest_mac.mm new file mode 100644 index 0000000..e978626 --- /dev/null +++ b/chrome/renderer/render_view_unittest_mac.mm @@ -0,0 +1,132 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/common/native_web_keyboard_event.h" +#include "chrome/common/render_messages.h" +#include "chrome/test/render_view_test.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "webkit/api/public/WebString.h" + +#include <Cocoa/Cocoa.h> +#include <Carbon/Carbon.h> // for the kVK_* constants. + +NSEvent* CmdDeadKeyEvent(NSEventType type, unsigned short code) { + + UniChar uniChar; + switch(code) { + case kVK_UpArrow: uniChar = NSUpArrowFunctionKey; break; + case kVK_DownArrow: uniChar = NSDownArrowFunctionKey; break; + default: CHECK(false); + } + NSString* s = [NSString stringWithFormat:@"%C", uniChar]; + + return [NSEvent keyEventWithType:type + location:NSMakePoint(0, 0) + modifierFlags:NSCommandKeyMask + timestamp:0.0 + windowNumber:0 + context:nil + characters:s + charactersIgnoringModifiers:s + isARepeat:NO + keyCode:code]; +} + +// Test that cmd-up/down scrolls the page exactly if it is not intercepted by +// javascript. +TEST_F(RenderViewTest, MacTestCmdUp) { + + // Some preprocessor trickery so that we can have literal html in our source, + // makes it easier to copy html to and from an html file for testing (the + // preprocessor will remove the newlines at the line ends, turning this into + // a single long line). + #define HTML(s) #s + const char* kRawHtml = HTML( + <html> + <head><title></title> + <script type='text/javascript' language='javascript'> + function OnKeyEvent(ev) { + var result = document.getElementById(ev.type); + result.innerText = (ev.which || ev.keyCode) + ',' + + ev.shiftKey + ',' + + ev.ctrlKey + ',' + + ev.metaKey + ',' + + ev.altKey; + return %s; /* Replace with "return true;" when testing in an html file. */ + } + function OnScroll(ev) { + var result = document.getElementById("scroll"); + result.innerText = window.pageYOffset; + return true; + } + </script> + <style type="text/css"> + p { border-bottom:5000px solid black; } /* enforce vertical scroll bar */ + </style> + </head> + <body + onscroll='return OnScroll(event);' + onkeydown='return OnKeyEvent(event);'> + <div id='keydown' contenteditable='true'> </div> + <div id='scroll' contenteditable='true'> </div> + <p>p1 + <p>p2 + </body> + </html> + ); + #undef HTML + + const int kMaxOutputCharacters = 1024; + string16 output; + char htmlBuffer[2048]; + + NSEvent* arrowDownKeyDown = CmdDeadKeyEvent(NSKeyDown, kVK_DownArrow); + NSEvent* arrowUpKeyDown = CmdDeadKeyEvent(NSKeyDown, kVK_UpArrow); + + // First test when javascript does not eat keypresses -- should scroll. + sprintf(htmlBuffer, kRawHtml, "true"); + view_->set_delay_seconds_for_form_state_sync(0); + LoadHTML(htmlBuffer); + render_thread_.sink().ClearMessages(); + + const char* kArrowDownScrollDown = + "40,false,false,true,false\n1936\np1\n\np2"; + view_->OnSetEditCommandsForNextKeyEvent( + EditCommands(1, EditCommand("moveToEndOfDocument", ""))); + SendNativeKeyEvent(NativeWebKeyboardEvent(arrowDownKeyDown)); + output = GetMainFrame()->contentAsText(kMaxOutputCharacters); + EXPECT_EQ(kArrowDownScrollDown, UTF16ToASCII(output)); + + const char* kArrowUpScrollUp = + "38,false,false,true,false\n0\np1\n\np2"; + view_->OnSetEditCommandsForNextKeyEvent( + EditCommands(1, EditCommand("moveToBeginningOfDocument", ""))); + SendNativeKeyEvent(NativeWebKeyboardEvent(arrowUpKeyDown)); + output = GetMainFrame()->contentAsText(kMaxOutputCharacters); + EXPECT_EQ(kArrowUpScrollUp, UTF16ToASCII(output)); + + + // Now let javascript eat the key events -- no scrolling should happen + sprintf(htmlBuffer, kRawHtml, "false"); + view_->set_delay_seconds_for_form_state_sync(0); + LoadHTML(htmlBuffer); + render_thread_.sink().ClearMessages(); + + const char* kArrowDownNoScroll = + "40,false,false,true,false\np1\n\np2"; + view_->OnSetEditCommandsForNextKeyEvent( + EditCommands(1, EditCommand("moveToEndOfDocument", ""))); + SendNativeKeyEvent(NativeWebKeyboardEvent(arrowDownKeyDown)); + output = GetMainFrame()->contentAsText(kMaxOutputCharacters); + EXPECT_EQ(kArrowDownNoScroll, UTF16ToASCII(output)); + + const char* kArrowUpNoScroll = + "38,false,false,true,false\np1\n\np2"; + view_->OnSetEditCommandsForNextKeyEvent( + EditCommands(1, EditCommand("moveToBeginningOfDocument", ""))); + SendNativeKeyEvent(NativeWebKeyboardEvent(arrowUpKeyDown)); + output = GetMainFrame()->contentAsText(kMaxOutputCharacters); + EXPECT_EQ(kArrowUpNoScroll, UTF16ToASCII(output)); +} + diff --git a/chrome/test/render_view_test.cc b/chrome/test/render_view_test.cc index 2f12836..e0321c7 100644 --- a/chrome/test/render_view_test.cc +++ b/chrome/test/render_view_test.cc @@ -158,22 +158,13 @@ int RenderViewTest::SendKeyEvent(MockKeyboard::Layout layout, // WM_KEYDOWN and WM_KEYUP sends virtual-key codes. On the other hand, // WM_CHAR sends a composed Unicode character. NativeWebKeyboardEvent keydown_event(NULL, WM_KEYDOWN, key_code, 0); - scoped_ptr<IPC::Message> keydown_message(new ViewMsg_HandleInputEvent(0)); - keydown_message->WriteData(reinterpret_cast<const char*>(&keydown_event), - sizeof(WebKit::WebKeyboardEvent)); - view_->OnHandleInputEvent(*keydown_message); + SendNativeKeyEvent(keydown_event); NativeWebKeyboardEvent char_event(NULL, WM_CHAR, (*output)[0], 0); - scoped_ptr<IPC::Message> char_message(new ViewMsg_HandleInputEvent(0)); - char_message->WriteData(reinterpret_cast<const char*>(&char_event), - sizeof(WebKit::WebKeyboardEvent)); - view_->OnHandleInputEvent(*char_message); + SendNativeKeyEvent(char_event); NativeWebKeyboardEvent keyup_event(NULL, WM_KEYUP, key_code, 0); - scoped_ptr<IPC::Message> keyup_message(new ViewMsg_HandleInputEvent(0)); - keyup_message->WriteData(reinterpret_cast<const char*>(&keyup_event), - sizeof(WebKit::WebKeyboardEvent)); - view_->OnHandleInputEvent(*keyup_message); + SendNativeKeyEvent(keyup_event); return length; #else @@ -181,3 +172,11 @@ int RenderViewTest::SendKeyEvent(MockKeyboard::Layout layout, return L'\0'; #endif } + +void RenderViewTest::SendNativeKeyEvent( + const NativeWebKeyboardEvent& key_event) { + scoped_ptr<IPC::Message> input_message(new ViewMsg_HandleInputEvent(0)); + input_message->WriteData(reinterpret_cast<const char*>(&key_event), + sizeof(WebKit::WebKeyboardEvent)); + view_->OnHandleInputEvent(*input_message); +} diff --git a/chrome/test/render_view_test.h b/chrome/test/render_view_test.h index 5a9a78a..45f8369 100644 --- a/chrome/test/render_view_test.h +++ b/chrome/test/render_view_test.h @@ -11,6 +11,7 @@ #include "base/scoped_ptr.h" #include "chrome/common/main_function_params.h" #include "chrome/common/sandbox_init_wrapper.h" +#include "chrome/common/native_web_keyboard_event.h" #include "chrome/renderer/mock_keyboard.h" #include "chrome/renderer/mock_render_process.h" #include "chrome/renderer/mock_render_thread.h" @@ -45,6 +46,9 @@ class RenderViewTest : public testing::Test { MockKeyboard::Modifiers key_modifiers, std::wstring* output); + // Sends one native key event over IPC. + void SendNativeKeyEvent(const NativeWebKeyboardEvent& key_event); + // testing::Test virtual void SetUp(); diff --git a/webkit/glue/webframe_impl.cc b/webkit/glue/webframe_impl.cc index 68c6882..e49fed8 100644 --- a/webkit/glue/webframe_impl.cc +++ b/webkit/glue/webframe_impl.cc @@ -121,6 +121,7 @@ MSVC_PUSH_WARNING_LEVEL(0); #include "ScriptSourceCode.h" #include "ScriptValue.h" #include "ScrollbarTheme.h" +#include "ScrollTypes.h" #include "SelectionController.h" #include "Settings.h" #include "SkiaUtils.h" @@ -1011,8 +1012,22 @@ bool WebFrameImpl::executeCommand(const WebString& name) { bool WebFrameImpl::executeCommand(const WebString& name, const WebString& value) { ASSERT(frame()); - return frame()->editor()->command(webkit_glue::WebStringToString(name)). - execute(webkit_glue::WebStringToString(value)); + WebCore::String web_name = webkit_glue::WebStringToString(name); + + // moveToBeginningOfDocument and moveToEndfDocument are only handled by WebKit + // for editable nodes. + if (!frame()->editor()->canEdit() && + web_name == "moveToBeginningOfDocument") { + return GetWebViewImpl()->PropagateScroll(WebCore::ScrollUp, + WebCore::ScrollByDocument); + } else if (!frame()->editor()->canEdit() && + web_name == "moveToEndOfDocument") { + return GetWebViewImpl()->PropagateScroll(WebCore::ScrollDown, + WebCore::ScrollByDocument); + } else { + return frame()->editor()->command(web_name). + execute(webkit_glue::WebStringToString(value)); + } } bool WebFrameImpl::isCommandEnabled(const WebString& name) const { diff --git a/webkit/glue/webview_impl.cc b/webkit/glue/webview_impl.cc index 6900853..74a4c3f 100644 --- a/webkit/glue/webview_impl.cc +++ b/webkit/glue/webview_impl.cc @@ -862,10 +862,6 @@ bool WebViewImpl::KeyEventDefault(const WebKeyboardEvent& event) { } bool WebViewImpl::ScrollViewWithKeyboard(int key_code, int modifiers) { - Frame* frame = GetFocusedWebCoreFrame(); - if (!frame) - return false; - ScrollDirection scroll_direction; ScrollGranularity scroll_granularity; @@ -880,29 +876,11 @@ bool WebViewImpl::ScrollViewWithKeyboard(int key_code, int modifiers) { break; case VKEY_UP: scroll_direction = ScrollUp; -#if defined(OS_MACOSX) - // Many Mac applications (such as TextEdit, Safari, Firefox, etc.) scroll - // to the beginning of a page when typing command+up keys. It is better - // for Mac Chrome to emulate this behavior to improve compatibility with - // these applications. - scroll_granularity = (modifiers == WebInputEvent::MetaKey) ? - ScrollByDocument : ScrollByLine; -#else scroll_granularity = ScrollByLine; -#endif break; case VKEY_DOWN: scroll_direction = ScrollDown; -#if defined(OS_MACOSX) - // Many Mac applications (such as TextEdit, Safari, Firefox, etc.) scroll - // to the end of a page when typing command+down keys. It is better - // for Mac Chrome to emulate this behavior to improve compatibility with - // these applications. - scroll_granularity = (modifiers == WebInputEvent::MetaKey) ? - ScrollByDocument : ScrollByLine; -#else scroll_granularity = ScrollByLine; -#endif break; case VKEY_HOME: scroll_direction = ScrollUp; @@ -924,6 +902,17 @@ bool WebViewImpl::ScrollViewWithKeyboard(int key_code, int modifiers) { return false; } + return PropagateScroll(scroll_direction, scroll_granularity); +} + +bool WebViewImpl::PropagateScroll( + WebCore::ScrollDirection scroll_direction, + WebCore::ScrollGranularity scroll_granularity) { + + Frame* frame = GetFocusedWebCoreFrame(); + if (!frame) + return false; + bool scroll_handled = frame->eventHandler()->scrollOverflow(scroll_direction, scroll_granularity); diff --git a/webkit/glue/webview_impl.h b/webkit/glue/webview_impl.h index 5ecb4cc..bb9f077 100644 --- a/webkit/glue/webview_impl.h +++ b/webkit/glue/webview_impl.h @@ -256,6 +256,11 @@ class WebViewImpl : public WebView, public base::RefCounted<WebViewImpl> { WebKit::NotificationPresenterImpl* GetNotificationPresenter(); #endif + // Tries to scroll a frame or any parent of a frame. Returns true if the view + // was scrolled. + bool PropagateScroll(WebCore::ScrollDirection scroll_direction, + WebCore::ScrollGranularity scroll_granularity); + protected: friend class WebView; // So WebView::Create can call our constructor friend class base::RefCounted<WebViewImpl>; |