- add sources.
[platform/framework/web/crosswalk.git] / src / content / browser / renderer_host / render_widget_host_view_mac_editcommand_helper.mm
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #import "content/browser/renderer_host/render_widget_host_view_mac_editcommand_helper.h"
6
7 #import <objc/runtime.h>
8
9 #include "content/browser/renderer_host/render_widget_host_impl.h"
10 #import "content/browser/renderer_host/render_widget_host_view_mac.h"
11
12 namespace content {
13 namespace {
14
15 // The names of all the objc selectors w/o ':'s added to an object by
16 // AddEditingSelectorsToClass().
17 //
18 // This needs to be kept in Sync with WEB_COMMAND list in the WebKit tree at:
19 // WebKit/mac/WebView/WebHTMLView.mm .
20 const char* kEditCommands[] = {
21   "alignCenter",
22   "alignJustified",
23   "alignLeft",
24   "alignRight",
25   "copy",
26   "cut",
27   "delete",
28   "deleteBackward",
29   "deleteBackwardByDecomposingPreviousCharacter",
30   "deleteForward",
31   "deleteToBeginningOfLine",
32   "deleteToBeginningOfParagraph",
33   "deleteToEndOfLine",
34   "deleteToEndOfParagraph",
35   "deleteToMark",
36   "deleteWordBackward",
37   "deleteWordForward",
38   "ignoreSpelling",
39   "indent",
40   "insertBacktab",
41   "insertLineBreak",
42   "insertNewline",
43   "insertNewlineIgnoringFieldEditor",
44   "insertParagraphSeparator",
45   "insertTab",
46   "insertTabIgnoringFieldEditor",
47   "makeTextWritingDirectionLeftToRight",
48   "makeTextWritingDirectionNatural",
49   "makeTextWritingDirectionRightToLeft",
50   "moveBackward",
51   "moveBackwardAndModifySelection",
52   "moveDown",
53   "moveDownAndModifySelection",
54   "moveForward",
55   "moveForwardAndModifySelection",
56   "moveLeft",
57   "moveLeftAndModifySelection",
58   "moveParagraphBackwardAndModifySelection",
59   "moveParagraphForwardAndModifySelection",
60   "moveRight",
61   "moveRightAndModifySelection",
62   "moveToBeginningOfDocument",
63   "moveToBeginningOfDocumentAndModifySelection",
64   "moveToBeginningOfLine",
65   "moveToBeginningOfLineAndModifySelection",
66   "moveToBeginningOfParagraph",
67   "moveToBeginningOfParagraphAndModifySelection",
68   "moveToBeginningOfSentence",
69   "moveToBeginningOfSentenceAndModifySelection",
70   "moveToEndOfDocument",
71   "moveToEndOfDocumentAndModifySelection",
72   "moveToEndOfLine",
73   "moveToEndOfLineAndModifySelection",
74   "moveToEndOfParagraph",
75   "moveToEndOfParagraphAndModifySelection",
76   "moveToEndOfSentence",
77   "moveToEndOfSentenceAndModifySelection",
78   "moveUp",
79   "moveUpAndModifySelection",
80   "moveWordBackward",
81   "moveWordBackwardAndModifySelection",
82   "moveWordForward",
83   "moveWordForwardAndModifySelection",
84   "moveWordLeft",
85   "moveWordLeftAndModifySelection",
86   "moveWordRight",
87   "moveWordRightAndModifySelection",
88   "outdent",
89   "pageDown",
90   "pageDownAndModifySelection",
91   "pageUp",
92   "pageUpAndModifySelection",
93   "selectAll",
94   "selectLine",
95   "selectParagraph",
96   "selectSentence",
97   "selectToMark",
98   "selectWord",
99   "setMark",
100   "showGuessPanel",
101   "subscript",
102   "superscript",
103   "swapWithMark",
104   "transpose",
105   "underline",
106   "unscript",
107   "yank",
108   "yankAndSelect"};
109
110
111 // This function is installed via the objc runtime as the implementation of all
112 // the various editing selectors.
113 // The objc runtime hookup occurs in
114 // RenderWidgetHostViewMacEditCommandHelper::AddEditingSelectorsToClass().
115 //
116 // self - the object we're attached to; it must implement the
117 // RenderWidgetHostViewMacOwner protocol.
118 // _cmd - the selector that fired.
119 // sender - the id of the object that sent the message.
120 //
121 // The selector is translated into an edit comand and then forwarded down the
122 // pipeline to WebCore.
123 // The route the message takes is:
124 // RenderWidgetHostViewMac -> RenderViewHost ->
125 // | IPC | ->
126 // RenderView -> currently focused WebFrame.
127 // The WebFrame is in the Chrome glue layer and forwards the message to WebCore.
128 void EditCommandImp(id self, SEL _cmd, id sender) {
129   // Make sure |self| is the right type.
130   DCHECK([self conformsToProtocol:@protocol(RenderWidgetHostViewMacOwner)]);
131
132   // SEL -> command name string.
133   NSString* command_name_ns =
134       RenderWidgetHostViewMacEditCommandHelper::CommandNameForSelector(_cmd);
135   std::string command([command_name_ns UTF8String]);
136
137   // Forward the edit command string down the pipeline.
138   RenderWidgetHostViewMac* rwhv = [(id<RenderWidgetHostViewMacOwner>)self
139       renderWidgetHostViewMac];
140   DCHECK(rwhv);
141
142   RenderWidgetHostImpl* rwh =
143       RenderWidgetHostImpl::From(rwhv->GetRenderWidgetHost());
144   // The second parameter is the core command value which isn't used here.
145   rwh->ExecuteEditCommand(command, "");
146 }
147
148 }  // namespace
149
150 // Maps an objc-selector to a core command name.
151 //
152 // Returns the core command name (which is the selector name with the trailing
153 // ':' stripped in most cases).
154 //
155 // Adapted from a function by the same name in
156 // WebKit/mac/WebView/WebHTMLView.mm .
157 // Capitalized names are returned from this function, but that's simply
158 // matching WebHTMLView.mm.
159 NSString* RenderWidgetHostViewMacEditCommandHelper::CommandNameForSelector(
160     SEL selector) {
161   if (selector == @selector(insertParagraphSeparator:) ||
162       selector == @selector(insertNewlineIgnoringFieldEditor:))
163     return @"InsertNewline";
164   if (selector == @selector(insertTabIgnoringFieldEditor:))
165     return @"InsertTab";
166   if (selector == @selector(pageDown:))
167     return @"MovePageDown";
168   if (selector == @selector(pageDownAndModifySelection:))
169     return @"MovePageDownAndModifySelection";
170   if (selector == @selector(pageUp:))
171     return @"MovePageUp";
172   if (selector == @selector(pageUpAndModifySelection:))
173     return @"MovePageUpAndModifySelection";
174
175   // Remove the trailing colon.
176   NSString* selector_str = NSStringFromSelector(selector);
177   int selector_len = [selector_str length];
178   return [selector_str substringToIndex:selector_len - 1];
179 }
180
181 RenderWidgetHostViewMacEditCommandHelper::
182     RenderWidgetHostViewMacEditCommandHelper() {
183   for (size_t i = 0; i < arraysize(kEditCommands); ++i) {
184     edit_command_set_.insert(kEditCommands[i]);
185   }
186 }
187
188 RenderWidgetHostViewMacEditCommandHelper::
189     ~RenderWidgetHostViewMacEditCommandHelper() {}
190
191 // Dynamically adds Selectors to the aformentioned class.
192 void RenderWidgetHostViewMacEditCommandHelper::AddEditingSelectorsToClass(
193     Class klass) {
194   for (size_t i = 0; i < arraysize(kEditCommands); ++i) {
195     // Append trailing ':' to command name to get selector name.
196     NSString* sel_str = [NSString stringWithFormat: @"%s:", kEditCommands[i]];
197
198     SEL edit_selector = NSSelectorFromString(sel_str);
199     // May want to use @encode() for the last parameter to this method.
200     // If class_addMethod fails we assume that all the editing selectors where
201     // added to the class.
202     // If a certain class already implements a method then class_addMethod
203     // returns NO, which we can safely ignore.
204     class_addMethod(klass, edit_selector, (IMP)EditCommandImp, "v@:@");
205   }
206 }
207
208 bool RenderWidgetHostViewMacEditCommandHelper::IsMenuItemEnabled(
209     SEL item_action,
210     id<RenderWidgetHostViewMacOwner> owner) {
211   const char* selector_name = sel_getName(item_action);
212   // TODO(jeremy): The final form of this function will check state
213   // associated with the Browser.
214
215   // For now just mark all edit commands as enabled.
216   NSString* selector_name_ns = [NSString stringWithUTF8String:selector_name];
217
218   // Remove trailing ':'
219   size_t str_len = [selector_name_ns length];
220   selector_name_ns = [selector_name_ns substringToIndex:str_len - 1];
221   std::string edit_command_name([selector_name_ns UTF8String]);
222
223   // search for presence in set and return.
224   bool ret = edit_command_set_.find(edit_command_name) !=
225       edit_command_set_.end();
226   return ret;
227 }
228
229 NSArray* RenderWidgetHostViewMacEditCommandHelper::GetEditSelectorNames() {
230   size_t num_edit_commands = arraysize(kEditCommands);
231   NSMutableArray* ret = [NSMutableArray arrayWithCapacity:num_edit_commands];
232
233   for (size_t i = 0; i < num_edit_commands; ++i) {
234       [ret addObject:[NSString stringWithUTF8String:kEditCommands[i]]];
235   }
236
237   return ret;
238 }
239
240 }  // namespace content