summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authorjeremy@chromium.org <jeremy@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-06-23 16:00:25 +0000
committerjeremy@chromium.org <jeremy@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-06-23 16:00:25 +0000
commit68b1e92848aebead28f92118e698a1b644d6f572 (patch)
treeed7d70696afd92878d2637ab9bd47c7ab87a9f9f /chrome
parenteb888d2f99d7de22640caa2da7cd707261afc2e4 (diff)
downloadchromium_src-68b1e92848aebead28f92118e698a1b644d6f572.zip
chromium_src-68b1e92848aebead28f92118e698a1b644d6f572.tar.gz
chromium_src-68b1e92848aebead28f92118e698a1b644d6f572.tar.bz2
Re-land r18853
Review URL: http://codereview.chromium.org/141008 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@19023 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r--chrome/browser/cocoa/rwhvm_editcommand_helper.h65
-rw-r--r--chrome/browser/cocoa/rwhvm_editcommand_helper.mm224
-rw-r--r--chrome/browser/cocoa/rwhvm_editcommand_helper_unittest.mm172
-rw-r--r--chrome/browser/renderer_host/render_view_host.cc8
-rw-r--r--chrome/browser/renderer_host/render_view_host.h2
-rw-r--r--chrome/browser/renderer_host/render_widget_host.cc7
-rw-r--r--chrome/browser/renderer_host/render_widget_host.h2
-rw-r--r--chrome/browser/renderer_host/render_widget_host_view_mac.h10
-rw-r--r--chrome/browser/renderer_host/render_widget_host_view_mac.mm15
-rw-r--r--chrome/chrome.gyp3
-rw-r--r--chrome/common/render_messages_internal.h5
-rw-r--r--chrome/renderer/render_view.cc9
-rw-r--r--chrome/renderer/render_view.h1
13 files changed, 522 insertions, 1 deletions
diff --git a/chrome/browser/cocoa/rwhvm_editcommand_helper.h b/chrome/browser/cocoa/rwhvm_editcommand_helper.h
new file mode 100644
index 0000000..aa948db
--- /dev/null
+++ b/chrome/browser/cocoa/rwhvm_editcommand_helper.h
@@ -0,0 +1,65 @@
+// 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.
+
+#ifndef CHROME_BROWSER_COCOA_RWHVM_EDITCOMMAND_HELPER_H_
+#define CHROME_BROWSER_COCOA_RWHVM_EDITCOMMAND_HELPER_H_
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/hash_tables.h"
+#include "base/logging.h"
+#include "chrome/browser/renderer_host/render_widget_host_view_mac.h"
+#include "testing/gtest/include/gtest/gtest_prod.h"
+
+// RenderWidgetHostViewMacEditCommandHelper is the real name of this class
+// but that's too long, so we use a shorter version.
+//
+// This class mimics the behavior of WebKit's WebView class in a way that makes
+// sense for Chrome.
+//
+// WebCore has the concept of "core commands", basically named actions such as
+// "Select All" and "Move Cursor Left". The commands are executed using their
+// string value by WebCore.
+//
+// This class is responsible for 2 things:
+// 1. Provide an abstraction to determine the enabled/disabled state of menu
+// items that correspond to edit commands.
+// 2. Hook up a bunch of objc selectors to the RenderWidgetHostViewCocoa object.
+// (note that this is not a misspelling of RenderWidgetHostViewMac, it's in
+// fact a distinct object) When these selectors are called, the relevant
+// edit command is executed in WebCore.
+class RWHVMEditCommandHelper {
+ FRIEND_TEST(RWHVMEditCommandHelperTest, TestAddEditingSelectorsToClass);
+ FRIEND_TEST(RWHVMEditCommandHelperTest, TestEditingCommandDelivery);
+
+ public:
+ RWHVMEditCommandHelper();
+
+ // Adds editing selectors to the objc class using the objc runtime APIs.
+ // Each selector is connected to a single c method which forwards the message
+ // to WebCore's ExecuteCoreCommand() function.
+ // This method is idempotent.
+ // The class passed in must conform to the RenderWidgetHostViewMacOwner
+ // protocol.
+ void AddEditingSelectorsToClass(Class klass);
+
+ // Is a given menu item currently enabled?
+ // SEL - the objc selector currently associated with an NSMenuItem.
+ // owner - An object we can retrieve a RenderWidgetHostViewMac from to
+ // determine the command states.
+ bool IsMenuItemEnabled(SEL item_action,
+ id<RenderWidgetHostViewMacOwner> owner);
+
+ protected:
+ // Gets a list of all the selectors that AddEditingSelectorsToClass adds to
+ // the aforementioned class.
+ // returns an array of NSStrings WITHOUT the trailing ':'s.
+ NSArray* GetEditSelectorNames();
+
+ private:
+ base::hash_set<std::string> edit_command_set_;
+ DISALLOW_COPY_AND_ASSIGN(RWHVMEditCommandHelper);
+};
+
+#endif // CHROME_BROWSER_COCOA_RWHVM_EDITCOMMAND_HELPER_H_
diff --git a/chrome/browser/cocoa/rwhvm_editcommand_helper.mm b/chrome/browser/cocoa/rwhvm_editcommand_helper.mm
new file mode 100644
index 0000000..87956b0
--- /dev/null
+++ b/chrome/browser/cocoa/rwhvm_editcommand_helper.mm
@@ -0,0 +1,224 @@
+// 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.
+
+#import "chrome/browser/cocoa/rwhvm_editcommand_helper.h"
+
+#import <objc/runtime.h>
+
+#include "chrome/browser/renderer_host/render_widget_host.h"
+#import "chrome/browser/renderer_host/render_widget_host_view_mac.h"
+
+namespace {
+// The names of all the objc selectors w/o ':'s added to an object by
+// AddEditingSelectorsToClass().
+//
+// This needs to be kept in Sync with WEB_COMMAND list in the WebKit tree at:
+// WebKit/mac/WebView/WebHTMLView.mm .
+const char* kEditCommands[] = {
+ "alignCenter",
+ "alignJustified",
+ "alignLeft",
+ "alignRight",
+ "copy",
+ "cut",
+ "delete",
+ "deleteBackward",
+ "deleteBackwardByDecomposingPreviousCharacter",
+ "deleteForward",
+ "deleteToBeginningOfLine",
+ "deleteToBeginningOfParagraph",
+ "deleteToEndOfLine",
+ "deleteToEndOfParagraph",
+ "deleteToMark",
+ "deleteWordBackward",
+ "deleteWordForward",
+ "ignoreSpelling",
+ "indent",
+ "insertBacktab",
+ "insertLineBreak",
+ "insertNewline",
+ "insertNewlineIgnoringFieldEditor",
+ "insertParagraphSeparator",
+ "insertTab",
+ "insertTabIgnoringFieldEditor",
+ "makeTextWritingDirectionLeftToRight",
+ "makeTextWritingDirectionNatural",
+ "makeTextWritingDirectionRightToLeft",
+ "moveBackward",
+ "moveBackwardAndModifySelection",
+ "moveDown",
+ "moveDownAndModifySelection",
+ "moveForward",
+ "moveForwardAndModifySelection",
+ "moveLeft",
+ "moveLeftAndModifySelection",
+ "moveParagraphBackwardAndModifySelection",
+ "moveParagraphForwardAndModifySelection",
+ "moveRight",
+ "moveRightAndModifySelection",
+ "moveToBeginningOfDocument",
+ "moveToBeginningOfDocumentAndModifySelection",
+ "moveToBeginningOfLine",
+ "moveToBeginningOfLineAndModifySelection",
+ "moveToBeginningOfParagraph",
+ "moveToBeginningOfParagraphAndModifySelection",
+ "moveToBeginningOfSentence",
+ "moveToBeginningOfSentenceAndModifySelection",
+ "moveToEndOfDocument",
+ "moveToEndOfDocumentAndModifySelection",
+ "moveToEndOfLine",
+ "moveToEndOfLineAndModifySelection",
+ "moveToEndOfParagraph",
+ "moveToEndOfParagraphAndModifySelection",
+ "moveToEndOfSentence",
+ "moveToEndOfSentenceAndModifySelection",
+ "moveUp",
+ "moveUpAndModifySelection",
+ "moveWordBackward",
+ "moveWordBackwardAndModifySelection",
+ "moveWordForward",
+ "moveWordForwardAndModifySelection",
+ "moveWordLeft",
+ "moveWordLeftAndModifySelection",
+ "moveWordRight",
+ "moveWordRightAndModifySelection",
+ "outdent",
+ "pageDown",
+ "pageDownAndModifySelection",
+ "pageUp",
+ "pageUpAndModifySelection",
+ "selectAll",
+ "selectLine",
+ "selectParagraph",
+ "selectSentence",
+ "selectToMark",
+ "selectWord",
+ "setMark",
+ "subscript",
+ "superscript",
+ "swapWithMark",
+ "transpose",
+ "underline",
+ "unscript",
+ "yank",
+ "yankAndSelect"};
+
+// Maps an objc-selector to a core command name.
+//
+// Returns the core command name (which is the selector name with the trailing
+// ':' stripped in most cases).
+//
+// Adapted from a function by the same name in
+// WebKit/mac/WebView/WebHTMLView.mm .
+// Capitalized names are returned from this function, but that's simply
+// matching WebHTMLView.mm.
+NSString* CommandNameForSelector(SEL selector) {
+ if (selector == @selector(insertParagraphSeparator:) ||
+ selector == @selector(insertNewlineIgnoringFieldEditor:))
+ return @"InsertNewline";
+ if (selector == @selector(insertTabIgnoringFieldEditor:))
+ return @"InsertTab";
+ if (selector == @selector(pageDown:))
+ return @"MovePageDown";
+ if (selector == @selector(pageDownAndModifySelection:))
+ return @"MovePageDownAndModifySelection";
+ if (selector == @selector(pageUp:))
+ return @"MovePageUp";
+ if (selector == @selector(pageUpAndModifySelection:))
+ return @"MovePageUpAndModifySelection";
+
+ // Remove the trailing colon.
+ NSString* selector_str = NSStringFromSelector(selector);
+ int selector_len = [selector_str length];
+ return [selector_str substringToIndex:selector_len - 1];
+}
+
+// This function is installed via the objc runtime as the implementation of all
+// the various editing selectors.
+// The objc runtime hookup occurs in
+// RWHVMEditCommandHelper::AddEditingSelectorsToClass().
+//
+// self - the object we're attached to; it must implement the
+// RenderWidgetHostViewMacOwner protocol.
+// _cmd - the selector that fired.
+// sender - the id of the object that sent the message.
+//
+// The selector is translated into an edit comand and then forwarded down the
+// pipeline to WebCore.
+// The route the message takes is:
+// RenderWidgetHostViewMac -> RenderViewHost ->
+// | IPC | ->
+// RenderView -> currently focused WebFrame.
+// The WebFrame is in the Chrome glue layer and forwards the message to WebCore.
+void EditCommandImp(id self, SEL _cmd, id sender) {
+ // Make sure |self| is the right type.
+ DCHECK([self conformsToProtocol:@protocol(RenderWidgetHostViewMacOwner)]);
+
+ // SEL -> command name string.
+ NSString* command_name_ns = CommandNameForSelector(_cmd);
+ std::string edit_command([command_name_ns UTF8String]);
+
+ // Forward the edit command string down the pipeline.
+ RenderWidgetHostViewMac* rwhv = [(id<RenderWidgetHostViewMacOwner>)self
+ renderWidgetHostViewMac];
+ DCHECK(rwhv);
+
+ // The second parameter is the core command value which isn't used here.
+ rwhv->GetRenderWidgetHost()->ForwardEditCommand(edit_command, "");
+}
+
+} // namespace
+
+RWHVMEditCommandHelper::RWHVMEditCommandHelper() {
+ for (size_t i = 0; i < arraysize(kEditCommands); ++i) {
+ edit_command_set_.insert(kEditCommands[i]);
+ }
+}
+
+// Dynamically adds Selectors to the aformentioned class.
+void RWHVMEditCommandHelper::AddEditingSelectorsToClass(Class klass) {
+ for (size_t i = 0; i < arraysize(kEditCommands); ++i) {
+ // Append trailing ':' to command name to get selector name.
+ NSString* sel_str = [NSString stringWithFormat: @"%s:", kEditCommands[i]];
+
+ SEL edit_selector = NSSelectorFromString(sel_str);
+ // May want to use @encode() for the last parameter to this method.
+ // If class_addMethod fails we assume that all the editing selectors where
+ // added to the class.
+ // If a certain class already implements a method then class_addMethod
+ // returns NO, which we can safely ignore.
+ class_addMethod(klass, edit_selector, (IMP)EditCommandImp, "v@:@");
+ }
+}
+
+bool RWHVMEditCommandHelper::IsMenuItemEnabled(SEL item_action,
+ id<RenderWidgetHostViewMacOwner> owner) {
+ const char* selector_name = sel_getName(item_action);
+ // TODO(jeremy): The final form of this function will check state
+ // associated with the Browser.
+
+ // For now just mark all edit commands as enabled.
+ NSString* selector_name_ns = [NSString stringWithUTF8String:selector_name];
+
+ // Remove trailing ':'
+ size_t str_len = [selector_name_ns length];
+ selector_name_ns = [selector_name_ns substringToIndex:str_len - 1];
+ std::string edit_command_name([selector_name_ns UTF8String]);
+
+ // search for presence in set and return.
+ bool ret = edit_command_set_.find(edit_command_name) !=
+ edit_command_set_.end();
+ return ret;
+}
+
+NSArray* RWHVMEditCommandHelper::GetEditSelectorNames() {
+ size_t num_edit_commands = arraysize(kEditCommands);
+ NSMutableArray* ret = [NSMutableArray arrayWithCapacity:num_edit_commands];
+
+ for (size_t i = 0; i < num_edit_commands; ++i) {
+ [ret addObject:[NSString stringWithUTF8String:kEditCommands[i]]];
+ }
+
+ return ret;
+}
diff --git a/chrome/browser/cocoa/rwhvm_editcommand_helper_unittest.mm b/chrome/browser/cocoa/rwhvm_editcommand_helper_unittest.mm
new file mode 100644
index 0000000..4fd5452
--- /dev/null
+++ b/chrome/browser/cocoa/rwhvm_editcommand_helper_unittest.mm
@@ -0,0 +1,172 @@
+// 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.
+
+#import "chrome/browser/cocoa/rwhvm_editcommand_helper.h"
+
+#import <Cocoa/Cocoa.h>
+
+#include "chrome/browser/renderer_host/mock_render_process_host.h"
+#include "chrome/browser/renderer_host/render_widget_host.h"
+#include "chrome/test/testing_profile.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+class RWHVMEditCommandHelperTest : public PlatformTest {
+};
+
+// Bare bones obj-c class for testing purposes.
+@interface RWHVMEditCommandHelperTestClass : NSObject
+@end
+
+@implementation RWHVMEditCommandHelperTestClass
+@end
+
+// Class that owns a RenderWidgetHostViewMac.
+@interface RenderWidgetHostViewMacOwner :
+ NSObject<RenderWidgetHostViewMacOwner> {
+ RenderWidgetHostViewMac* rwhvm_;
+}
+
+- (id) initWithRenderWidgetHostViewMac:(RenderWidgetHostViewMac*)rwhvm;
+@end
+
+@implementation RenderWidgetHostViewMacOwner
+
+- (id)initWithRenderWidgetHostViewMac:(RenderWidgetHostViewMac*)rwhvm {
+ if ((self = [super init])) {
+ rwhvm_ = rwhvm;
+ }
+ return self;
+}
+
+- (RenderWidgetHostViewMac*)renderWidgetHostViewMac {
+ return rwhvm_;
+}
+
+@end
+
+
+namespace {
+ // Returns true if all the edit command names in the array are present
+ // in test_obj.
+ // edit_commands is a list of NSStrings, selector names are formed by
+ // appending a trailing ':' to the string.
+ bool CheckObjectRespondsToEditCommands(NSArray* edit_commands, id test_obj) {
+ for (NSString* edit_command_name in edit_commands) {
+ NSString* sel_str = [edit_command_name stringByAppendingString:@":"];
+ if (![test_obj respondsToSelector:NSSelectorFromString(sel_str)]) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+} // namespace
+
+// Create a Mock RenderWidget
+class MockRenderWidgetHostEditCommandCounter : public RenderWidgetHost {
+ public:
+ MockRenderWidgetHostEditCommandCounter(RenderProcessHost* process,
+ int routing_id) :
+ RenderWidgetHost(process, routing_id) {}
+
+ MOCK_METHOD2(ForwardEditCommand, void(const std::string&,
+ const std::string&));
+};
+
+
+// Tests that editing commands make it through the pipeline all the way to
+// RenderWidgetHost.
+TEST_F(RWHVMEditCommandHelperTest, TestEditingCommandDelivery) {
+ RWHVMEditCommandHelper helper;
+ NSArray* edit_command_strings = helper.GetEditSelectorNames();
+
+ // Set up a mock render widget and set expectations.
+ MessageLoopForUI message_loop;
+ TestingProfile profile;
+ MockRenderProcessHost mock_process(&profile);
+ MockRenderWidgetHostEditCommandCounter mock_render_widget(&mock_process, 0);
+
+ size_t num_edit_commands = [edit_command_strings count];
+ EXPECT_CALL(mock_render_widget,
+ ForwardEditCommand(testing::_, testing::_)).Times(num_edit_commands);
+
+// TODO(jeremy): Figure this out and reenable this test.
+// For some bizarre reason this code doesn't work, running the code in the
+// debugger confirms that the function is called with the correct parameters
+// however gmock appears not to be able to match up parameters correctly.
+// Disable for now till we can figure this out.
+#if 0
+ // Tell Mock object that we expect to recieve each edit command once.
+ std::string empty_str;
+ for (NSString* edit_command_name in edit_command_strings) {
+ std::string command([edit_command_name UTF8String]);
+ EXPECT_CALL(mock_render_widget,
+ ForwardEditCommand(command, empty_str)).Times(1);
+ }
+#endif // 0
+
+ // RenderWidgetHostViewMac self destructs (RenderWidgetHostViewMacCocoa
+ // takes ownership) so no need to delete it ourselves.
+ RenderWidgetHostViewMac* rwhvm = new RenderWidgetHostViewMac(
+ &mock_render_widget);
+
+ RenderWidgetHostViewMacOwner* rwhwvm_owner =
+ [[[RenderWidgetHostViewMacOwner alloc]
+ initWithRenderWidgetHostViewMac:rwhvm] autorelease];
+
+ helper.AddEditingSelectorsToClass([rwhwvm_owner class]);
+
+ for (NSString* edit_command_name in edit_command_strings) {
+ NSString* sel_str = [edit_command_name stringByAppendingString:@":"];
+ [rwhwvm_owner performSelector:NSSelectorFromString(sel_str) withObject:nil];
+ }
+}
+
+// Test RWHVMEditCommandHelper::AddEditingSelectorsToClass
+TEST_F(RWHVMEditCommandHelperTest, TestAddEditingSelectorsToClass) {
+ RWHVMEditCommandHelper helper;
+ NSArray* edit_command_strings = helper.GetEditSelectorNames();
+ ASSERT_GT([edit_command_strings count], 0U);
+
+ // Create a class instance and add methods to the class.
+ RWHVMEditCommandHelperTestClass* test_obj =
+ [[[RWHVMEditCommandHelperTestClass alloc] init] autorelease];
+
+ // Check that edit commands aren't already attached to the object.
+ ASSERT_FALSE(CheckObjectRespondsToEditCommands(edit_command_strings,
+ test_obj));
+
+ helper.AddEditingSelectorsToClass([test_obj class]);
+
+ // Check that all edit commands where added.
+ ASSERT_TRUE(CheckObjectRespondsToEditCommands(edit_command_strings,
+ test_obj));
+
+ // AddEditingSelectorsToClass() should be idempotent.
+ helper.AddEditingSelectorsToClass([test_obj class]);
+
+ // Check that all edit commands are still there.
+ ASSERT_TRUE(CheckObjectRespondsToEditCommands(edit_command_strings,
+ test_obj));
+}
+
+// Test RWHVMEditCommandHelper::IsMenuItemEnabled.
+TEST_F(RWHVMEditCommandHelperTest, TestMenuItemEnabling) {
+ RWHVMEditCommandHelper helper;
+ RenderWidgetHostViewMacOwner* rwhvm_owner =
+ [[[RenderWidgetHostViewMacOwner alloc] init] autorelease];
+
+ // The select all menu should always be enabled.
+ SEL select_all = NSSelectorFromString(@"selectAll:");
+ ASSERT_TRUE(helper.IsMenuItemEnabled(select_all, rwhvm_owner));
+
+ // Random selectors should be enabled by the function.
+ SEL garbage_selector = NSSelectorFromString(@"randomGarbageSelector:");
+ ASSERT_FALSE(helper.IsMenuItemEnabled(garbage_selector, rwhvm_owner));
+
+ // TODO(jeremy): Currently IsMenuItemEnabled just returns true for all edit
+ // selectors. Once we go past that we should do more extensive testing here.
+}
diff --git a/chrome/browser/renderer_host/render_view_host.cc b/chrome/browser/renderer_host/render_view_host.cc
index d5376f44..f486cb7 100644
--- a/chrome/browser/renderer_host/render_view_host.cc
+++ b/chrome/browser/renderer_host/render_view_host.cc
@@ -1445,6 +1445,14 @@ void RenderViewHost::ForwardMouseEvent(
}
}
+void RenderViewHost::ForwardEditCommand(const std::string& name,
+ const std::string& value) {
+ IPC::Message* message = new ViewMsg_HandleExecuteEditCommand(routing_id(),
+ name,
+ value);
+ Send(message);
+}
+
void RenderViewHost::OnDebugDisconnect() {
if (debugger_attached_) {
debugger_attached_ = false;
diff --git a/chrome/browser/renderer_host/render_view_host.h b/chrome/browser/renderer_host/render_view_host.h
index be31a607..101bc2b 100644
--- a/chrome/browser/renderer_host/render_view_host.h
+++ b/chrome/browser/renderer_host/render_view_host.h
@@ -424,6 +424,8 @@ class RenderViewHost : public RenderWidgetHost {
virtual void GotFocus();
virtual bool CanBlur() const;
virtual void ForwardMouseEvent(const WebKit::WebMouseEvent& mouse_event);
+ virtual void ForwardEditCommand(const std::string& name,
+ const std::string& value);
virtual gfx::Rect GetRootWindowResizerRect() const;
// Creates a new RenderView with the given route id.
diff --git a/chrome/browser/renderer_host/render_widget_host.cc b/chrome/browser/renderer_host/render_widget_host.cc
index 51d2b3b..9b18841 100644
--- a/chrome/browser/renderer_host/render_widget_host.cc
+++ b/chrome/browser/renderer_host/render_widget_host.cc
@@ -382,6 +382,13 @@ void RenderWidgetHost::ForwardInputEvent(const WebInputEvent& input_event,
StartHangMonitorTimeout(TimeDelta::FromMilliseconds(kHungRendererDelayMs));
}
+void RenderWidgetHost::ForwardEditCommand(const std::string& name,
+ const std::string& value) {
+ // We don't need an implementation of this function here since the
+ // only place we use this is for the case of dropdown menus and other
+ // edge cases for which edit commands don't make sense.
+}
+
void RenderWidgetHost::RendererExited() {
// Clearing this flag causes us to re-create the renderer when recovering
// from a crashed renderer.
diff --git a/chrome/browser/renderer_host/render_widget_host.h b/chrome/browser/renderer_host/render_widget_host.h
index c5913ef..783c147 100644
--- a/chrome/browser/renderer_host/render_widget_host.h
+++ b/chrome/browser/renderer_host/render_widget_host.h
@@ -239,6 +239,8 @@ class RenderWidgetHost : public IPC::Channel::Listener {
virtual void ForwardMouseEvent(const WebKit::WebMouseEvent& mouse_event);
void ForwardWheelEvent(const WebKit::WebMouseWheelEvent& wheel_event);
void ForwardKeyboardEvent(const NativeWebKeyboardEvent& key_event);
+ virtual void ForwardEditCommand(const std::string& name,
+ const std::string& value);
// Update the text direction of the focused input element and notify it to a
// renderer process.
diff --git a/chrome/browser/renderer_host/render_widget_host_view_mac.h b/chrome/browser/renderer_host/render_widget_host_view_mac.h
index ab97232..cdfee6a 100644
--- a/chrome/browser/renderer_host/render_widget_host_view_mac.h
+++ b/chrome/browser/renderer_host/render_widget_host_view_mac.h
@@ -8,25 +8,33 @@
#import <Cocoa/Cocoa.h>
#include "base/scoped_nsobject.h"
+#include "base/scoped_ptr.h"
#include "base/task.h"
#include "base/time.h"
#include "chrome/browser/cocoa/base_view.h"
#include "chrome/browser/renderer_host/render_widget_host_view.h"
+
#include "webkit/glue/webcursor.h"
class RenderWidgetHostViewMac;
+class RWHVMEditCommandHelper;
@class ToolTip;
+@protocol RenderWidgetHostViewMacOwner
+- (RenderWidgetHostViewMac*)renderWidgetHostViewMac;
+@end
+
// This is the view that lives in the Cocoa view hierarchy. In Windows-land,
// RenderWidgetHostViewWin is both the view and the delegate. We split the roles
// but that means that the view needs to own the delegate and will dispose of it
// when it's removed from the view system.
-@interface RenderWidgetHostViewCocoa : BaseView {
+@interface RenderWidgetHostViewCocoa : BaseView <RenderWidgetHostViewMacOwner> {
@private
RenderWidgetHostViewMac* renderWidgetHostView_;
BOOL canBeKeyView_;
BOOL closeOnDeactivate_;
+ scoped_ptr<RWHVMEditCommandHelper> editCommand_helper_;
}
- (void)setCanBeKeyView:(BOOL)can;
diff --git a/chrome/browser/renderer_host/render_widget_host_view_mac.mm b/chrome/browser/renderer_host/render_widget_host_view_mac.mm
index 377e073..bf01fd0 100644
--- a/chrome/browser/renderer_host/render_widget_host_view_mac.mm
+++ b/chrome/browser/renderer_host/render_widget_host_view_mac.mm
@@ -7,6 +7,7 @@
#include "base/histogram.h"
#include "base/sys_string_conversions.h"
#include "chrome/browser/browser_trial.h"
+#import "chrome/browser/cocoa/rwhvm_editcommand_helper.h"
#include "chrome/browser/renderer_host/backing_store.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/browser/renderer_host/render_widget_host.h"
@@ -362,6 +363,9 @@ void RenderWidgetHostViewMac::ShutdownHost() {
- (id)initWithRenderWidgetHostViewMac:(RenderWidgetHostViewMac*)r {
self = [super initWithFrame:NSZeroRect];
if (self != nil) {
+ editCommand_helper_.reset(new RWHVMEditCommandHelper);
+ editCommand_helper_->AddEditingSelectorsToClass([self class]);
+
renderWidgetHostView_ = r;
canBeKeyView_ = YES;
closeOnDeactivate_ = NO;
@@ -509,4 +513,15 @@ void RenderWidgetHostViewMac::ShutdownHost() {
return YES;
}
+- (BOOL)validateUserInterfaceItem:(id<NSValidatedUserInterfaceItem>)item {
+ SEL action = [item action];
+
+ return editCommand_helper_->IsMenuItemEnabled(action, self);
+}
+
+- (RenderWidgetHostViewMac*)renderWidgetHostViewMac {
+ return renderWidgetHostView_;
+}
+
@end
+
diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp
index 89c6006..d62389d 100644
--- a/chrome/chrome.gyp
+++ b/chrome/chrome.gyp
@@ -764,6 +764,8 @@
'browser/cocoa/preferences_localizer.mm',
'browser/cocoa/preferences_window_controller.h',
'browser/cocoa/preferences_window_controller.mm',
+ 'browser/cocoa/rwhvm_editcommand_helper.h',
+ 'browser/cocoa/rwhvm_editcommand_helper.mm',
'browser/cocoa/sad_tab_view.h',
'browser/cocoa/sad_tab_view.mm',
'browser/cocoa/search_engine_list_model.h',
@@ -3392,6 +3394,7 @@
'browser/cocoa/gradient_button_cell_unittest.mm',
'browser/cocoa/grow_box_view_unittest.mm',
'browser/cocoa/preferences_window_controller_unittest.mm',
+ 'browser/cocoa/rwhvm_editcommand_helper_unittest.mm',
'browser/cocoa/sad_tab_view_unittest.mm',
'browser/cocoa/search_engine_list_model_unittest.mm',
'browser/cocoa/status_bubble_mac_unittest.mm',
diff --git a/chrome/common/render_messages_internal.h b/chrome/common/render_messages_internal.h
index 5debd5f..7743244 100644
--- a/chrome/common/render_messages_internal.h
+++ b/chrome/common/render_messages_internal.h
@@ -113,6 +113,11 @@ IPC_BEGIN_MESSAGES(View)
// Message payload is a blob that should be cast to WebInputEvent
IPC_MESSAGE_ROUTED0(ViewMsg_HandleInputEvent)
+ // Message payload is the name/value of a core command to execute.
+ IPC_MESSAGE_ROUTED2(ViewMsg_HandleExecuteEditCommand,
+ std::string, /* name */
+ std::string /* value */)
+
IPC_MESSAGE_ROUTED0(ViewMsg_MouseCaptureLost)
// TODO(darin): figure out how this meshes with RestoreFocus
diff --git a/chrome/renderer/render_view.cc b/chrome/renderer/render_view.cc
index 9ea36fb..6376ee7 100644
--- a/chrome/renderer/render_view.cc
+++ b/chrome/renderer/render_view.cc
@@ -354,6 +354,7 @@ void RenderView::OnMessageReceived(const IPC::Message& message) {
IPC_MESSAGE_HANDLER(ViewMsg_Delete, OnDelete)
IPC_MESSAGE_HANDLER(ViewMsg_SelectAll, OnSelectAll)
IPC_MESSAGE_HANDLER(ViewMsg_CopyImageAt, OnCopyImageAt)
+ IPC_MESSAGE_HANDLER(ViewMsg_HandleExecuteEditCommand, OnExecuteEditCommand)
IPC_MESSAGE_HANDLER(ViewMsg_Find, OnFind)
IPC_MESSAGE_HANDLER(ViewMsg_Zoom, OnZoom)
IPC_MESSAGE_HANDLER(ViewMsg_InsertText, OnInsertText)
@@ -717,6 +718,14 @@ void RenderView::OnCopyImageAt(int x, int y) {
webview()->CopyImageAt(x, y);
}
+void RenderView::OnExecuteEditCommand(const std::string& name,
+ const std::string& value) {
+ if (!webview() || !webview()->GetFocusedFrame())
+ return;
+
+ webview()->GetFocusedFrame()->ExecuteCoreCommandByName(name, value);
+}
+
void RenderView::OnInspectElement(int x, int y) {
webview()->InspectElement(x, y);
}
diff --git a/chrome/renderer/render_view.h b/chrome/renderer/render_view.h
index 19f3c43..3ab950a 100644
--- a/chrome/renderer/render_view.h
+++ b/chrome/renderer/render_view.h
@@ -481,6 +481,7 @@ class RenderView : public RenderWidget,
void OnDelete();
void OnSelectAll();
void OnCopyImageAt(int x, int y);
+ void OnExecuteEditCommand(const std::string& name, const std::string& value);
void OnInspectElement(int x, int y);
void OnShowJavaScriptConsole();
void OnSetupDevToolsClient();