diff options
author | jeremy@chromium.org <jeremy@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-06-19 21:10:08 +0000 |
---|---|---|
committer | jeremy@chromium.org <jeremy@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-06-19 21:10:08 +0000 |
commit | 578bba9eb889903735722645e56387cd1b9a87b9 (patch) | |
tree | b6ccdff95afab1930e1cbccadecf7a48e3bb8f1d /chrome | |
parent | ae0ba2c44fb60fc3abb3f36d0747dac6472e100d (diff) | |
download | chromium_src-578bba9eb889903735722645e56387cd1b9a87b9.zip chromium_src-578bba9eb889903735722645e56387cd1b9a87b9.tar.gz chromium_src-578bba9eb889903735722645e56387cd1b9a87b9.tar.bz2 |
This patch adds Cocoa editing selectors to the RenderViewWidgetHostMac class.
This makes us a better citizen in OSX text-editing land and is a first step in getting our text entry story to work more natively on OSX.
The selectors are added at runtime to the Cocoa class and invoking them causes the appropriate WebKit core command to be invoked on the currently focused WebFrame.
As a side-effect bug 10862 is fixed.
BUG=10862
TEST=Open a new tab and type some text into an input element, change to a Hebrew keyboard layout and hit command-a, all text should be selected.
Review URL: http://codereview.chromium.org/114070
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@18853 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r-- | chrome/browser/cocoa/rwhvm_editcommand_helper.h | 65 | ||||
-rw-r--r-- | chrome/browser/cocoa/rwhvm_editcommand_helper.mm | 224 | ||||
-rw-r--r-- | chrome/browser/cocoa/rwhvm_editcommand_helper_unittest.mm | 172 | ||||
-rw-r--r-- | chrome/browser/renderer_host/render_view_host.cc | 8 | ||||
-rw-r--r-- | chrome/browser/renderer_host/render_view_host.h | 2 | ||||
-rw-r--r-- | chrome/browser/renderer_host/render_widget_host.cc | 7 | ||||
-rw-r--r-- | chrome/browser/renderer_host/render_widget_host.h | 2 | ||||
-rw-r--r-- | chrome/browser/renderer_host/render_widget_host_view_mac.h | 10 | ||||
-rw-r--r-- | chrome/browser/renderer_host/render_widget_host_view_mac.mm | 15 | ||||
-rw-r--r-- | chrome/chrome.gyp | 3 | ||||
-rw-r--r-- | chrome/common/render_messages_internal.h | 5 | ||||
-rw-r--r-- | chrome/renderer/render_view.cc | 9 | ||||
-rw-r--r-- | chrome/renderer/render_view.h | 1 |
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..339ff0e --- /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 MockRenderWidgetHost : public RenderWidgetHost { + public: + MockRenderWidgetHost(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); + MockRenderWidgetHost 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 a18dd08..893c79d 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 75ed116..aae89c3 100644 --- a/chrome/chrome.gyp +++ b/chrome/chrome.gyp @@ -762,6 +762,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', @@ -3383,6 +3385,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 d96220d..539c36c 100644 --- a/chrome/common/render_messages_internal.h +++ b/chrome/common/render_messages_internal.h @@ -112,6 +112,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 5cf511a..8b225b9 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(); |