summaryrefslogtreecommitdiffstats
path: root/chrome/browser/ui/cocoa/rwhvm_editcommand_helper.mm
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/browser/ui/cocoa/rwhvm_editcommand_helper.mm')
-rw-r--r--chrome/browser/ui/cocoa/rwhvm_editcommand_helper.mm227
1 files changed, 227 insertions, 0 deletions
diff --git a/chrome/browser/ui/cocoa/rwhvm_editcommand_helper.mm b/chrome/browser/ui/cocoa/rwhvm_editcommand_helper.mm
new file mode 100644
index 0000000..0aec09e
--- /dev/null
+++ b/chrome/browser/ui/cocoa/rwhvm_editcommand_helper.mm
@@ -0,0 +1,227 @@
+// 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/ui/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",
+ "showGuessPanel",
+ "subscript",
+ "superscript",
+ "swapWithMark",
+ "transpose",
+ "underline",
+ "unscript",
+ "yank",
+ "yankAndSelect"};
+
+
+// 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 =
+ RWHVMEditCommandHelper::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
+
+// 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* RWHVMEditCommandHelper::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];
+}
+
+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;
+}