blob: 3f089d75a05573c689de886c52cbbd21f8bed920 [file] [log] [blame]
// Copyright (c) 2012 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 "content/browser/renderer_host/render_widget_host_view_mac_editcommand_helper.h"
#import <objc/runtime.h>
#include <stddef.h>
#include "base/macros.h"
#include "content/browser/renderer_host/render_widget_host_impl.h"
#import "content/browser/renderer_host/render_widget_host_view_mac.h"
namespace content {
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/ .
const char* const kEditCommands[] = {
// This function is installed via the objc runtime as the implementation of all
// the various editing selectors.
// The objc runtime hookup occurs in
// RenderWidgetHostViewMacEditCommandHelper::AddEditingSelectorsToClass().
// self - the object we're attached to; it must implement the
// RenderWidgetHostNSViewClientOwner 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.
[self conformsToProtocol:@protocol(RenderWidgetHostNSViewClientOwner)]);
// SEL -> command name string.
NSString* command_name_ns =
std::string command([command_name_ns UTF8String]);
// Forward the edit command string down the pipeline.
mojom::RenderWidgetHostNSViewClient* client = [(
id<RenderWidgetHostNSViewClientOwner>)self renderWidgetHostNSViewClient];
} // 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/ .
// Capitalized names are returned from this function, but that's simply
// matching
NSString* RenderWidgetHostViewMacEditCommandHelper::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";
if (selector == @selector(showGuessPanel:))
return @"ToggleSpellPanel";
// Remove the trailing colon.
NSString* selector_str = NSStringFromSelector(selector);
int selector_len = [selector_str length];
return [selector_str substringToIndex:selector_len - 1];
RenderWidgetHostViewMacEditCommandHelper() {
for (size_t i = 0; i < arraysize(kEditCommands); ++i) {
~RenderWidgetHostViewMacEditCommandHelper() {}
// Dynamically adds Selectors to the aformentioned class.
void RenderWidgetHostViewMacEditCommandHelper::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 RenderWidgetHostViewMacEditCommandHelper::IsMenuItemEnabled(
SEL item_action,
id<RenderWidgetHostNSViewClientOwner> 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) !=
return ret;
NSArray* RenderWidgetHostViewMacEditCommandHelper::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;
} // namespace content