Replace WTF::move with WTFMove
[WebKit-https.git] / Source / WebCore / editing / EditorCommand.cpp
1 /*
2  * Copyright (C) 2006, 2007, 2008, 2014 Apple Inc. All rights reserved.
3  * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
4  * Copyright (C) 2009 Igalia S.L.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
16  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
19  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
23  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
26  */
27
28 #include "config.h"
29 #include "Editor.h"
30
31 #include "CSSComputedStyleDeclaration.h"
32 #include "CSSValueList.h"
33 #include "Chrome.h"
34 #include "CreateLinkCommand.h"
35 #include "DocumentFragment.h"
36 #include "EditorClient.h"
37 #include "Event.h"
38 #include "EventHandler.h"
39 #include "ExceptionCodePlaceholder.h"
40 #include "FormatBlockCommand.h"
41 #include "Frame.h"
42 #include "FrameView.h"
43 #include "HTMLFontElement.h"
44 #include "HTMLHRElement.h"
45 #include "HTMLImageElement.h"
46 #include "HTMLNames.h"
47 #include "IndentOutdentCommand.h"
48 #include "InsertListCommand.h"
49 #include "KillRing.h"
50 #include "Page.h"
51 #include "Pasteboard.h"
52 #include "RenderBox.h"
53 #include "ReplaceSelectionCommand.h"
54 #include "Scrollbar.h"
55 #include "Settings.h"
56 #include "Sound.h"
57 #include "StyleProperties.h"
58 #include "TypingCommand.h"
59 #include "UnlinkCommand.h"
60 #include "UserTypingGestureIndicator.h"
61 #include "htmlediting.h"
62 #include "markup.h"
63 #include <wtf/text/AtomicString.h>
64
65 namespace WebCore {
66
67 using namespace HTMLNames;
68
69 class EditorInternalCommand {
70 public:
71     bool (*execute)(Frame&, Event*, EditorCommandSource, const String&);
72     bool (*isSupportedFromDOM)(Frame*);
73     bool (*isEnabled)(Frame&, Event*, EditorCommandSource);
74     TriState (*state)(Frame&, Event*);
75     String (*value)(Frame&, Event*);
76     bool isTextInsertion;
77     bool allowExecutionWhenDisabled;
78 };
79
80 typedef HashMap<String, const EditorInternalCommand*, CaseFoldingHash> CommandMap;
81
82 static const bool notTextInsertion = false;
83 static const bool isTextInsertion = true;
84
85 static const bool allowExecutionWhenDisabled = true;
86 static const bool doNotAllowExecutionWhenDisabled = false;
87
88 // Related to Editor::selectionForCommand.
89 // Certain operations continue to use the target control's selection even if the event handler
90 // already moved the selection outside of the text control.
91 static Frame* targetFrame(Frame& frame, Event* event)
92 {
93     if (!event)
94         return &frame;
95     Node* node = event->target()->toNode();
96     if (!node)
97         return &frame;
98     return node->document().frame();
99 }
100
101 static bool applyCommandToFrame(Frame& frame, EditorCommandSource source, EditAction action, Ref<EditingStyle>&& style)
102 {
103     // FIXME: We don't call shouldApplyStyle when the source is DOM; is there a good reason for that?
104     switch (source) {
105     case CommandFromMenuOrKeyBinding:
106         frame.editor().applyStyleToSelection(WTFMove(style), action);
107         return true;
108     case CommandFromDOM:
109     case CommandFromDOMWithUserInterface:
110         frame.editor().applyStyle(WTFMove(style), EditActionUnspecified);
111         return true;
112     }
113     ASSERT_NOT_REACHED();
114     return false;
115 }
116
117 static bool isStylePresent(Editor& editor, CSSPropertyID propertyID, const char* onValue)
118 {
119     // Style is considered present when
120     // Mac: present at the beginning of selection
121     // Windows: present throughout the selection
122     if (editor.behavior().shouldToggleStyleBasedOnStartOfSelection())
123         return editor.selectionStartHasStyle(propertyID, onValue);
124     return editor.selectionHasStyle(propertyID, onValue) == TrueTriState;
125 }
126
127 static bool executeApplyStyle(Frame& frame, EditorCommandSource source, EditAction action, CSSPropertyID propertyID, const String& propertyValue)
128 {
129     return applyCommandToFrame(frame, source, action, EditingStyle::create(propertyID, propertyValue));
130 }
131
132 static bool executeApplyStyle(Frame& frame, EditorCommandSource source, EditAction action, CSSPropertyID propertyID, CSSValueID propertyValue)
133 {
134     return applyCommandToFrame(frame, source, action, EditingStyle::create(propertyID, propertyValue));
135 }
136
137 static bool executeToggleStyle(Frame& frame, EditorCommandSource source, EditAction action, CSSPropertyID propertyID, const char* offValue, const char* onValue)
138 {
139     bool styleIsPresent = isStylePresent(frame.editor(), propertyID, onValue);
140     return applyCommandToFrame(frame, source, action, EditingStyle::create(propertyID, styleIsPresent ? offValue : onValue));
141 }
142
143 static bool executeApplyParagraphStyle(Frame& frame, EditorCommandSource source, EditAction action, CSSPropertyID propertyID, const String& propertyValue)
144 {
145     RefPtr<MutableStyleProperties> style = MutableStyleProperties::create();
146     style->setProperty(propertyID, propertyValue);
147     // FIXME: We don't call shouldApplyStyle when the source is DOM; is there a good reason for that?
148     switch (source) {
149     case CommandFromMenuOrKeyBinding:
150         frame.editor().applyParagraphStyleToSelection(style.get(), action);
151         return true;
152     case CommandFromDOM:
153     case CommandFromDOMWithUserInterface:
154         frame.editor().applyParagraphStyle(style.get());
155         return true;
156     }
157     ASSERT_NOT_REACHED();
158     return false;
159 }
160
161 static bool executeInsertFragment(Frame& frame, PassRefPtr<DocumentFragment> fragment)
162 {
163     ASSERT(frame.document());
164     applyCommand(ReplaceSelectionCommand::create(*frame.document(), fragment, ReplaceSelectionCommand::PreventNesting, EditActionInsert));
165     return true;
166 }
167
168 static bool executeInsertNode(Frame& frame, Ref<Node>&& content)
169 {
170     RefPtr<DocumentFragment> fragment = DocumentFragment::create(*frame.document());
171     ExceptionCode ec = 0;
172     fragment->appendChild(WTFMove(content), ec);
173     if (ec)
174         return false;
175     return executeInsertFragment(frame, fragment.release());
176 }
177
178 static bool expandSelectionToGranularity(Frame& frame, TextGranularity granularity)
179 {
180     VisibleSelection selection = frame.selection().selection();
181     selection.expandUsingGranularity(granularity);
182     RefPtr<Range> newRange = selection.toNormalizedRange();
183     if (!newRange)
184         return false;
185     if (newRange->collapsed())
186         return false;
187     RefPtr<Range> oldRange = selection.toNormalizedRange();
188     EAffinity affinity = selection.affinity();
189     if (!frame.editor().client()->shouldChangeSelectedRange(oldRange.get(), newRange.get(), affinity, false))
190         return false;
191     frame.selection().setSelectedRange(newRange.get(), affinity, true);
192     return true;
193 }
194
195 static TriState stateStyle(Frame& frame, CSSPropertyID propertyID, const char* desiredValue)
196 {
197     if (frame.editor().behavior().shouldToggleStyleBasedOnStartOfSelection())
198         return frame.editor().selectionStartHasStyle(propertyID, desiredValue) ? TrueTriState : FalseTriState;
199     return frame.editor().selectionHasStyle(propertyID, desiredValue);
200 }
201
202 static String valueStyle(Frame& frame, CSSPropertyID propertyID)
203 {
204     // FIXME: Rather than retrieving the style at the start of the current selection,
205     // we should retrieve the style present throughout the selection for non-Mac platforms.
206     return frame.editor().selectionStartCSSPropertyValue(propertyID);
207 }
208
209 static TriState stateTextWritingDirection(Frame& frame, WritingDirection direction)
210 {
211     bool hasNestedOrMultipleEmbeddings;
212     WritingDirection selectionDirection = EditingStyle::textDirectionForSelection(frame.selection().selection(),
213         frame.selection().typingStyle(), hasNestedOrMultipleEmbeddings);
214     // FXIME: We should be returning MixedTriState when selectionDirection == direction && hasNestedOrMultipleEmbeddings
215     return (selectionDirection == direction && !hasNestedOrMultipleEmbeddings) ? TrueTriState : FalseTriState;
216 }
217
218 static unsigned verticalScrollDistance(Frame& frame)
219 {
220     Element* focusedElement = frame.document()->focusedElement();
221     if (!focusedElement)
222         return 0;
223     auto* renderer = focusedElement->renderer();
224     if (!is<RenderBox>(renderer))
225         return 0;
226     const RenderStyle& style = renderer->style();
227     if (!(style.overflowY() == OSCROLL || style.overflowY() == OAUTO || focusedElement->hasEditableStyle()))
228         return 0;
229     int height = std::min<int>(downcast<RenderBox>(*renderer).clientHeight(), frame.view()->visibleHeight());
230     return static_cast<unsigned>(Scrollbar::pageStep(height));
231 }
232
233 static RefPtr<Range> unionDOMRanges(Range* a, Range* b)
234 {
235     Range* start = a->compareBoundaryPoints(Range::START_TO_START, b, ASSERT_NO_EXCEPTION) <= 0 ? a : b;
236     Range* end = a->compareBoundaryPoints(Range::END_TO_END, b, ASSERT_NO_EXCEPTION) <= 0 ? b : a;
237
238     return Range::create(a->ownerDocument(), &start->startContainer(), start->startOffset(), &end->endContainer(), end->endOffset());
239 }
240
241 // Execute command functions
242
243 static bool executeBackColor(Frame& frame, Event*, EditorCommandSource source, const String& value)
244 {
245     return executeApplyStyle(frame, source, EditActionSetBackgroundColor, CSSPropertyBackgroundColor, value);
246 }
247
248 static bool executeCopy(Frame& frame, Event*, EditorCommandSource, const String&)
249 {
250     frame.editor().copy();
251     return true;
252 }
253
254 static bool executeCreateLink(Frame& frame, Event*, EditorCommandSource, const String& value)
255 {
256     // FIXME: If userInterface is true, we should display a dialog box to let the user enter a URL.
257     if (value.isEmpty())
258         return false;
259     ASSERT(frame.document());
260     applyCommand(CreateLinkCommand::create(*frame.document(), value));
261     return true;
262 }
263
264 static bool executeCut(Frame& frame, Event*, EditorCommandSource source, const String&)
265 {
266     if (source == CommandFromMenuOrKeyBinding) {
267         UserTypingGestureIndicator typingGestureIndicator(frame);
268         frame.editor().cut();
269     } else
270         frame.editor().cut();
271     return true;
272 }
273
274 static bool executeClearText(Frame& frame, Event*, EditorCommandSource, const String&)
275 {
276     frame.editor().clearText();
277     return true;
278 }
279
280 static bool executeDefaultParagraphSeparator(Frame& frame, Event*, EditorCommandSource, const String& value)
281 {
282     if (equalIgnoringCase(value, "div"))
283         frame.editor().setDefaultParagraphSeparator(EditorParagraphSeparatorIsDiv);
284     else if (equalIgnoringCase(value, "p"))
285         frame.editor().setDefaultParagraphSeparator(EditorParagraphSeparatorIsP);
286
287     return true;
288 }
289
290 static bool executeDelete(Frame& frame, Event*, EditorCommandSource source, const String&)
291 {
292     switch (source) {
293     case CommandFromMenuOrKeyBinding: {
294         // Doesn't modify the text if the current selection isn't a range.
295         UserTypingGestureIndicator typingGestureIndicator(frame);
296         frame.editor().performDelete();
297         return true;
298     }
299     case CommandFromDOM:
300     case CommandFromDOMWithUserInterface:
301         // If the current selection is a caret, delete the preceding character. IE performs forwardDelete, but we currently side with Firefox.
302         // Doesn't scroll to make the selection visible, or modify the kill ring (this time, siding with IE, not Firefox).
303         TypingCommand::deleteKeyPressed(*frame.document(), frame.selection().granularity() == WordGranularity ? TypingCommand::SmartDelete : 0);
304         return true;
305     }
306     ASSERT_NOT_REACHED();
307     return false;
308 }
309
310 static bool executeDeleteBackward(Frame& frame, Event*, EditorCommandSource, const String&)
311 {
312     frame.editor().deleteWithDirection(DirectionBackward, CharacterGranularity, false, true);
313     return true;
314 }
315
316 static bool executeDeleteBackwardByDecomposingPreviousCharacter(Frame& frame, Event*, EditorCommandSource, const String&)
317 {
318     LOG_ERROR("DeleteBackwardByDecomposingPreviousCharacter is not implemented, doing DeleteBackward instead");
319     frame.editor().deleteWithDirection(DirectionBackward, CharacterGranularity, false, true);
320     return true;
321 }
322
323 static bool executeDeleteForward(Frame& frame, Event*, EditorCommandSource, const String&)
324 {
325     frame.editor().deleteWithDirection(DirectionForward, CharacterGranularity, false, true);
326     return true;
327 }
328
329 static bool executeDeleteToBeginningOfLine(Frame& frame, Event*, EditorCommandSource, const String&)
330 {
331     frame.editor().deleteWithDirection(DirectionBackward, LineBoundary, true, false);
332     return true;
333 }
334
335 static bool executeDeleteToBeginningOfParagraph(Frame& frame, Event*, EditorCommandSource, const String&)
336 {
337     frame.editor().deleteWithDirection(DirectionBackward, ParagraphBoundary, true, false);
338     return true;
339 }
340
341 static bool executeDeleteToEndOfLine(Frame& frame, Event*, EditorCommandSource, const String&)
342 {
343     // Despite its name, this command should delete the newline at the end of
344     // a paragraph if you are at the end of a paragraph (like DeleteToEndOfParagraph).
345     frame.editor().deleteWithDirection(DirectionForward, LineBoundary, true, false);
346     return true;
347 }
348
349 static bool executeDeleteToEndOfParagraph(Frame& frame, Event*, EditorCommandSource, const String&)
350 {
351     // Despite its name, this command should delete the newline at the end of
352     // a paragraph if you are at the end of a paragraph.
353     frame.editor().deleteWithDirection(DirectionForward, ParagraphBoundary, true, false);
354     return true;
355 }
356
357 static bool executeDeleteToMark(Frame& frame, Event*, EditorCommandSource, const String&)
358 {
359     RefPtr<Range> mark = frame.editor().mark().toNormalizedRange();
360     FrameSelection& selection = frame.selection();
361     if (mark) {
362         bool selected = selection.setSelectedRange(unionDOMRanges(mark.get(), frame.editor().selectedRange().get()).get(), DOWNSTREAM, true);
363         ASSERT(selected);
364         if (!selected)
365             return false;
366     }
367     frame.editor().performDelete();
368     frame.editor().setMark(selection.selection());
369     return true;
370 }
371
372 static bool executeDeleteWordBackward(Frame& frame, Event*, EditorCommandSource, const String&)
373 {
374     frame.editor().deleteWithDirection(DirectionBackward, WordGranularity, true, false);
375     return true;
376 }
377
378 static bool executeDeleteWordForward(Frame& frame, Event*, EditorCommandSource, const String&)
379 {
380     frame.editor().deleteWithDirection(DirectionForward, WordGranularity, true, false);
381     return true;
382 }
383
384 static bool executeFindString(Frame& frame, Event*, EditorCommandSource, const String& value)
385 {
386     return frame.editor().findString(value, CaseInsensitive | WrapAround);
387 }
388
389 static bool executeFontName(Frame& frame, Event*, EditorCommandSource source, const String& value)
390 {
391     return executeApplyStyle(frame, source, EditActionSetFont, CSSPropertyFontFamily, value);
392 }
393
394 static bool executeFontSize(Frame& frame, Event*, EditorCommandSource source, const String& value)
395 {
396     CSSValueID size;
397     if (!HTMLFontElement::cssValueFromFontSizeNumber(value, size))
398         return false;
399     return executeApplyStyle(frame, source, EditActionChangeAttributes, CSSPropertyFontSize, size);
400 }
401
402 static bool executeFontSizeDelta(Frame& frame, Event*, EditorCommandSource source, const String& value)
403 {
404     return executeApplyStyle(frame, source, EditActionChangeAttributes, CSSPropertyWebkitFontSizeDelta, value);
405 }
406
407 static bool executeForeColor(Frame& frame, Event*, EditorCommandSource source, const String& value)
408 {
409     return executeApplyStyle(frame, source, EditActionSetColor, CSSPropertyColor, value);
410 }
411
412 static bool executeFormatBlock(Frame& frame, Event*, EditorCommandSource, const String& value)
413 {
414     String tagName = value.lower();
415     if (tagName[0] == '<' && tagName[tagName.length() - 1] == '>')
416         tagName = tagName.substring(1, tagName.length() - 2);
417
418     String localName, prefix;
419     if (!Document::parseQualifiedName(tagName, prefix, localName, IGNORE_EXCEPTION))
420         return false;
421     QualifiedName qualifiedTagName(prefix, localName, xhtmlNamespaceURI);
422
423     ASSERT(frame.document());
424     RefPtr<FormatBlockCommand> command = FormatBlockCommand::create(*frame.document(), qualifiedTagName);
425     applyCommand(command);
426     return command->didApply();
427 }
428
429 static bool executeForwardDelete(Frame& frame, Event*, EditorCommandSource source, const String&)
430 {
431     switch (source) {
432     case CommandFromMenuOrKeyBinding:
433         frame.editor().deleteWithDirection(DirectionForward, CharacterGranularity, false, true);
434         return true;
435     case CommandFromDOM:
436     case CommandFromDOMWithUserInterface:
437         // Doesn't scroll to make the selection visible, or modify the kill ring.
438         // ForwardDelete is not implemented in IE or Firefox, so this behavior is only needed for
439         // backward compatibility with ourselves, and for consistency with Delete.
440         TypingCommand::forwardDeleteKeyPressed(*frame.document());
441         return true;
442     }
443     ASSERT_NOT_REACHED();
444     return false;
445 }
446
447 static bool executeIgnoreSpelling(Frame& frame, Event*, EditorCommandSource, const String&)
448 {
449     frame.editor().ignoreSpelling();
450     return true;
451 }
452
453 static bool executeIndent(Frame& frame, Event*, EditorCommandSource, const String&)
454 {
455     ASSERT(frame.document());
456     applyCommand(IndentOutdentCommand::create(*frame.document(), IndentOutdentCommand::Indent));
457     return true;
458 }
459
460 static bool executeInsertBacktab(Frame& frame, Event* event, EditorCommandSource, const String&)
461 {
462     return targetFrame(frame, event)->eventHandler().handleTextInputEvent("\t", event, TextEventInputBackTab);
463 }
464
465 static bool executeInsertHorizontalRule(Frame& frame, Event*, EditorCommandSource, const String& value)
466 {
467     Ref<HTMLHRElement> rule = HTMLHRElement::create(*frame.document());
468     if (!value.isEmpty())
469         rule->setIdAttribute(value);
470     return executeInsertNode(frame, WTFMove(rule));
471 }
472
473 static bool executeInsertHTML(Frame& frame, Event*, EditorCommandSource, const String& value)
474 {
475     return executeInsertFragment(frame, createFragmentFromMarkup(*frame.document(), value, ""));
476 }
477
478 static bool executeInsertImage(Frame& frame, Event*, EditorCommandSource, const String& value)
479 {
480     // FIXME: If userInterface is true, we should display a dialog box and let the user choose a local image.
481     Ref<HTMLImageElement> image = HTMLImageElement::create(*frame.document());
482     image->setSrc(value);
483     return executeInsertNode(frame, WTFMove(image));
484 }
485
486 static bool executeInsertLineBreak(Frame& frame, Event* event, EditorCommandSource source, const String&)
487 {
488     switch (source) {
489     case CommandFromMenuOrKeyBinding:
490         return targetFrame(frame, event)->eventHandler().handleTextInputEvent("\n", event, TextEventInputLineBreak);
491     case CommandFromDOM:
492     case CommandFromDOMWithUserInterface:
493         // Doesn't scroll to make the selection visible, or modify the kill ring.
494         // InsertLineBreak is not implemented in IE or Firefox, so this behavior is only needed for
495         // backward compatibility with ourselves, and for consistency with other commands.
496         TypingCommand::insertLineBreak(*frame.document(), 0);
497         return true;
498     }
499     ASSERT_NOT_REACHED();
500     return false;
501 }
502
503 static bool executeInsertNewline(Frame& frame, Event* event, EditorCommandSource, const String&)
504 {
505     Frame* targetFrame = WebCore::targetFrame(frame, event);
506     return targetFrame->eventHandler().handleTextInputEvent("\n", event, targetFrame->editor().canEditRichly() ? TextEventInputKeyboard : TextEventInputLineBreak);
507 }
508
509 static bool executeInsertNewlineInQuotedContent(Frame& frame, Event*, EditorCommandSource, const String&)
510 {
511     TypingCommand::insertParagraphSeparatorInQuotedContent(*frame.document());
512     return true;
513 }
514
515 static bool executeInsertOrderedList(Frame& frame, Event*, EditorCommandSource, const String&)
516 {
517     ASSERT(frame.document());
518     applyCommand(InsertListCommand::create(*frame.document(), InsertListCommand::OrderedList));
519     return true;
520 }
521
522 static bool executeInsertParagraph(Frame& frame, Event*, EditorCommandSource, const String&)
523 {
524     TypingCommand::insertParagraphSeparator(*frame.document(), 0);
525     return true;
526 }
527
528 static bool executeInsertTab(Frame& frame, Event* event, EditorCommandSource, const String&)
529 {
530     return targetFrame(frame, event)->eventHandler().handleTextInputEvent("\t", event);
531 }
532
533 static bool executeInsertText(Frame& frame, Event*, EditorCommandSource, const String& value)
534 {
535     TypingCommand::insertText(*frame.document(), value, 0);
536     return true;
537 }
538
539 static bool executeInsertUnorderedList(Frame& frame, Event*, EditorCommandSource, const String&)
540 {
541     ASSERT(frame.document());
542     applyCommand(InsertListCommand::create(*frame.document(), InsertListCommand::UnorderedList));
543     return true;
544 }
545
546 static bool executeJustifyCenter(Frame& frame, Event*, EditorCommandSource source, const String&)
547 {
548     return executeApplyParagraphStyle(frame, source, EditActionCenter, CSSPropertyTextAlign, "center");
549 }
550
551 static bool executeJustifyFull(Frame& frame, Event*, EditorCommandSource source, const String&)
552 {
553     return executeApplyParagraphStyle(frame, source, EditActionJustify, CSSPropertyTextAlign, "justify");
554 }
555
556 static bool executeJustifyLeft(Frame& frame, Event*, EditorCommandSource source, const String&)
557 {
558     return executeApplyParagraphStyle(frame, source, EditActionAlignLeft, CSSPropertyTextAlign, "left");
559 }
560
561 static bool executeJustifyRight(Frame& frame, Event*, EditorCommandSource source, const String&)
562 {
563     return executeApplyParagraphStyle(frame, source, EditActionAlignRight, CSSPropertyTextAlign, "right");
564 }
565
566 static bool executeMakeTextWritingDirectionLeftToRight(Frame& frame, Event*, EditorCommandSource, const String&)
567 {
568     RefPtr<MutableStyleProperties> style = MutableStyleProperties::create();
569     style->setProperty(CSSPropertyUnicodeBidi, CSSValueEmbed);
570     style->setProperty(CSSPropertyDirection, CSSValueLtr);
571     frame.editor().applyStyle(style.get(), EditActionSetWritingDirection);
572     return true;
573 }
574
575 static bool executeMakeTextWritingDirectionNatural(Frame& frame, Event*, EditorCommandSource, const String&)
576 {
577     RefPtr<MutableStyleProperties> style = MutableStyleProperties::create();
578     style->setProperty(CSSPropertyUnicodeBidi, CSSValueNormal);
579     frame.editor().applyStyle(style.get(), EditActionSetWritingDirection);
580     return true;
581 }
582
583 static bool executeMakeTextWritingDirectionRightToLeft(Frame& frame, Event*, EditorCommandSource, const String&)
584 {
585     RefPtr<MutableStyleProperties> style = MutableStyleProperties::create();
586     style->setProperty(CSSPropertyUnicodeBidi, CSSValueEmbed);
587     style->setProperty(CSSPropertyDirection, CSSValueRtl);
588     frame.editor().applyStyle(style.get(), EditActionSetWritingDirection);
589     return true;
590 }
591
592 static bool executeMoveBackward(Frame& frame, Event*, EditorCommandSource, const String&)
593 {
594     frame.selection().modify(FrameSelection::AlterationMove, DirectionBackward, CharacterGranularity, UserTriggered);
595     return true;
596 }
597
598 static bool executeMoveBackwardAndModifySelection(Frame& frame, Event*, EditorCommandSource, const String&)
599 {
600     frame.selection().modify(FrameSelection::AlterationExtend, DirectionBackward, CharacterGranularity, UserTriggered);
601     return true;
602 }
603
604 static bool executeMoveDown(Frame& frame, Event*, EditorCommandSource, const String&)
605 {
606     return frame.selection().modify(FrameSelection::AlterationMove, DirectionForward, LineGranularity, UserTriggered);
607 }
608
609 static bool executeMoveDownAndModifySelection(Frame& frame, Event*, EditorCommandSource, const String&)
610 {
611     frame.selection().modify(FrameSelection::AlterationExtend, DirectionForward, LineGranularity, UserTriggered);
612     return true;
613 }
614
615 static bool executeMoveForward(Frame& frame, Event*, EditorCommandSource, const String&)
616 {
617     frame.selection().modify(FrameSelection::AlterationMove, DirectionForward, CharacterGranularity, UserTriggered);
618     return true;
619 }
620
621 static bool executeMoveForwardAndModifySelection(Frame& frame, Event*, EditorCommandSource, const String&)
622 {
623     frame.selection().modify(FrameSelection::AlterationExtend, DirectionForward, CharacterGranularity, UserTriggered);
624     return true;
625 }
626
627 static bool executeMoveLeft(Frame& frame, Event*, EditorCommandSource, const String&)
628 {
629     return frame.selection().modify(FrameSelection::AlterationMove, DirectionLeft, CharacterGranularity, UserTriggered);
630 }
631
632 static bool executeMoveLeftAndModifySelection(Frame& frame, Event*, EditorCommandSource, const String&)
633 {
634     frame.selection().modify(FrameSelection::AlterationExtend, DirectionLeft, CharacterGranularity, UserTriggered);
635     return true;
636 }
637
638 static bool executeMovePageDown(Frame& frame, Event*, EditorCommandSource, const String&)
639 {
640     unsigned distance = verticalScrollDistance(frame);
641     if (!distance)
642         return false;
643     return frame.selection().modify(FrameSelection::AlterationMove, distance, FrameSelection::DirectionDown,
644         UserTriggered, FrameSelection::AlignCursorOnScrollAlways);
645 }
646
647 static bool executeMovePageDownAndModifySelection(Frame& frame, Event*, EditorCommandSource, const String&)
648 {
649     unsigned distance = verticalScrollDistance(frame);
650     if (!distance)
651         return false;
652     return frame.selection().modify(FrameSelection::AlterationExtend, distance, FrameSelection::DirectionDown,
653         UserTriggered, FrameSelection::AlignCursorOnScrollAlways);
654 }
655
656 static bool executeMovePageUp(Frame& frame, Event*, EditorCommandSource, const String&)
657 {
658     unsigned distance = verticalScrollDistance(frame);
659     if (!distance)
660         return false;
661     return frame.selection().modify(FrameSelection::AlterationMove, distance, FrameSelection::DirectionUp,
662         UserTriggered, FrameSelection::AlignCursorOnScrollAlways);
663 }
664
665 static bool executeMovePageUpAndModifySelection(Frame& frame, Event*, EditorCommandSource, const String&)
666 {
667     unsigned distance = verticalScrollDistance(frame);
668     if (!distance)
669         return false;
670     return frame.selection().modify(FrameSelection::AlterationExtend, distance, FrameSelection::DirectionUp,
671         UserTriggered, FrameSelection::AlignCursorOnScrollAlways);
672 }
673
674 static bool executeMoveRight(Frame& frame, Event*, EditorCommandSource, const String&)
675 {
676     return frame.selection().modify(FrameSelection::AlterationMove, DirectionRight, CharacterGranularity, UserTriggered);
677 }
678
679 static bool executeMoveRightAndModifySelection(Frame& frame, Event*, EditorCommandSource, const String&)
680 {
681     frame.selection().modify(FrameSelection::AlterationExtend, DirectionRight, CharacterGranularity, UserTriggered);
682     return true;
683 }
684
685 static bool executeMoveToBeginningOfDocument(Frame& frame, Event*, EditorCommandSource, const String&)
686 {
687     frame.selection().modify(FrameSelection::AlterationMove, DirectionBackward, DocumentBoundary, UserTriggered);
688     return true;
689 }
690
691 static bool executeMoveToBeginningOfDocumentAndModifySelection(Frame& frame, Event*, EditorCommandSource, const String&)
692 {
693     frame.selection().modify(FrameSelection::AlterationExtend, DirectionBackward, DocumentBoundary, UserTriggered);
694     return true;
695 }
696
697 static bool executeMoveToBeginningOfLine(Frame& frame, Event*, EditorCommandSource, const String&)
698 {
699     frame.selection().modify(FrameSelection::AlterationMove, DirectionBackward, LineBoundary, UserTriggered);
700     return true;
701 }
702
703 static bool executeMoveToBeginningOfLineAndModifySelection(Frame& frame, Event*, EditorCommandSource, const String&)
704 {
705     frame.selection().modify(FrameSelection::AlterationExtend, DirectionBackward, LineBoundary, UserTriggered);
706     return true;
707 }
708
709 static bool executeMoveToBeginningOfParagraph(Frame& frame, Event*, EditorCommandSource, const String&)
710 {
711     frame.selection().modify(FrameSelection::AlterationMove, DirectionBackward, ParagraphBoundary, UserTriggered);
712     return true;
713 }
714
715 static bool executeMoveToBeginningOfParagraphAndModifySelection(Frame& frame, Event*, EditorCommandSource, const String&)
716 {
717     frame.selection().modify(FrameSelection::AlterationExtend, DirectionBackward, ParagraphBoundary, UserTriggered);
718     return true;
719 }
720
721 static bool executeMoveToBeginningOfSentence(Frame& frame, Event*, EditorCommandSource, const String&)
722 {
723     frame.selection().modify(FrameSelection::AlterationMove, DirectionBackward, SentenceBoundary, UserTriggered);
724     return true;
725 }
726
727 static bool executeMoveToBeginningOfSentenceAndModifySelection(Frame& frame, Event*, EditorCommandSource, const String&)
728 {
729     frame.selection().modify(FrameSelection::AlterationExtend, DirectionBackward, SentenceBoundary, UserTriggered);
730     return true;
731 }
732
733 static bool executeMoveToEndOfDocument(Frame& frame, Event*, EditorCommandSource, const String&)
734 {
735     frame.selection().modify(FrameSelection::AlterationMove, DirectionForward, DocumentBoundary, UserTriggered);
736     return true;
737 }
738
739 static bool executeMoveToEndOfDocumentAndModifySelection(Frame& frame, Event*, EditorCommandSource, const String&)
740 {
741     frame.selection().modify(FrameSelection::AlterationExtend, DirectionForward, DocumentBoundary, UserTriggered);
742     return true;
743 }
744
745 static bool executeMoveToEndOfSentence(Frame& frame, Event*, EditorCommandSource, const String&)
746 {
747     frame.selection().modify(FrameSelection::AlterationMove, DirectionForward, SentenceBoundary, UserTriggered);
748     return true;
749 }
750
751 static bool executeMoveToEndOfSentenceAndModifySelection(Frame& frame, Event*, EditorCommandSource, const String&)
752 {
753     frame.selection().modify(FrameSelection::AlterationExtend, DirectionForward, SentenceBoundary, UserTriggered);
754     return true;
755 }
756
757 static bool executeMoveToEndOfLine(Frame& frame, Event*, EditorCommandSource, const String&)
758 {
759     frame.selection().modify(FrameSelection::AlterationMove, DirectionForward, LineBoundary, UserTriggered);
760     return true;
761 }
762
763 static bool executeMoveToEndOfLineAndModifySelection(Frame& frame, Event*, EditorCommandSource, const String&)
764 {
765     frame.selection().modify(FrameSelection::AlterationExtend, DirectionForward, LineBoundary, UserTriggered);
766     return true;
767 }
768
769 static bool executeMoveToEndOfParagraph(Frame& frame, Event*, EditorCommandSource, const String&)
770 {
771     frame.selection().modify(FrameSelection::AlterationMove, DirectionForward, ParagraphBoundary, UserTriggered);
772     return true;
773 }
774
775 static bool executeMoveToEndOfParagraphAndModifySelection(Frame& frame, Event*, EditorCommandSource, const String&)
776 {
777     frame.selection().modify(FrameSelection::AlterationExtend, DirectionForward, ParagraphBoundary, UserTriggered);
778     return true;
779 }
780
781 static bool executeMoveParagraphBackwardAndModifySelection(Frame& frame, Event*, EditorCommandSource, const String&)
782 {
783     frame.selection().modify(FrameSelection::AlterationExtend, DirectionBackward, ParagraphGranularity, UserTriggered);
784     return true;
785 }
786
787 static bool executeMoveParagraphForwardAndModifySelection(Frame& frame, Event*, EditorCommandSource, const String&)
788 {
789     frame.selection().modify(FrameSelection::AlterationExtend, DirectionForward, ParagraphGranularity, UserTriggered);
790     return true;
791 }
792
793 static bool executeMoveUp(Frame& frame, Event*, EditorCommandSource, const String&)
794 {
795     return frame.selection().modify(FrameSelection::AlterationMove, DirectionBackward, LineGranularity, UserTriggered);
796 }
797
798 static bool executeMoveUpAndModifySelection(Frame& frame, Event*, EditorCommandSource, const String&)
799 {
800     frame.selection().modify(FrameSelection::AlterationExtend, DirectionBackward, LineGranularity, UserTriggered);
801     return true;
802 }
803
804 static bool executeMoveWordBackward(Frame& frame, Event*, EditorCommandSource, const String&)
805 {
806     frame.selection().modify(FrameSelection::AlterationMove, DirectionBackward, WordGranularity, UserTriggered);
807     return true;
808 }
809
810 static bool executeMoveWordBackwardAndModifySelection(Frame& frame, Event*, EditorCommandSource, const String&)
811 {
812     frame.selection().modify(FrameSelection::AlterationExtend, DirectionBackward, WordGranularity, UserTriggered);
813     return true;
814 }
815
816 static bool executeMoveWordForward(Frame& frame, Event*, EditorCommandSource, const String&)
817 {
818     frame.selection().modify(FrameSelection::AlterationMove, DirectionForward, WordGranularity, UserTriggered);
819     return true;
820 }
821
822 static bool executeMoveWordForwardAndModifySelection(Frame& frame, Event*, EditorCommandSource, const String&)
823 {
824     frame.selection().modify(FrameSelection::AlterationExtend, DirectionForward, WordGranularity, UserTriggered);
825     return true;
826 }
827
828 static bool executeMoveWordLeft(Frame& frame, Event*, EditorCommandSource, const String&)
829 {
830     frame.selection().modify(FrameSelection::AlterationMove, DirectionLeft, WordGranularity, UserTriggered);
831     return true;
832 }
833
834 static bool executeMoveWordLeftAndModifySelection(Frame& frame, Event*, EditorCommandSource, const String&)
835 {
836     frame.selection().modify(FrameSelection::AlterationExtend, DirectionLeft, WordGranularity, UserTriggered);
837     return true;
838 }
839
840 static bool executeMoveWordRight(Frame& frame, Event*, EditorCommandSource, const String&)
841 {
842     frame.selection().modify(FrameSelection::AlterationMove, DirectionRight, WordGranularity, UserTriggered);
843     return true;
844 }
845
846 static bool executeMoveWordRightAndModifySelection(Frame& frame, Event*, EditorCommandSource, const String&)
847 {
848     frame.selection().modify(FrameSelection::AlterationExtend, DirectionRight, WordGranularity, UserTriggered);
849     return true;
850 }
851
852 static bool executeMoveToLeftEndOfLine(Frame& frame, Event*, EditorCommandSource, const String&)
853 {
854     frame.selection().modify(FrameSelection::AlterationMove, DirectionLeft, LineBoundary, UserTriggered);
855     return true;
856 }
857
858 static bool executeMoveToLeftEndOfLineAndModifySelection(Frame& frame, Event*, EditorCommandSource, const String&)
859 {
860     frame.selection().modify(FrameSelection::AlterationExtend, DirectionLeft, LineBoundary, UserTriggered);
861     return true;
862 }
863
864 static bool executeMoveToRightEndOfLine(Frame& frame, Event*, EditorCommandSource, const String&)
865 {
866     frame.selection().modify(FrameSelection::AlterationMove, DirectionRight, LineBoundary, UserTriggered);
867     return true;
868 }
869
870 static bool executeMoveToRightEndOfLineAndModifySelection(Frame& frame, Event*, EditorCommandSource, const String&)
871 {
872     frame.selection().modify(FrameSelection::AlterationExtend, DirectionRight, LineBoundary, UserTriggered);
873     return true;
874 }
875
876 static bool executeOutdent(Frame& frame, Event*, EditorCommandSource, const String&)
877 {
878     ASSERT(frame.document());
879     applyCommand(IndentOutdentCommand::create(*frame.document(), IndentOutdentCommand::Outdent));
880     return true;
881 }
882
883 static bool executeToggleOverwrite(Frame& frame, Event*, EditorCommandSource, const String&)
884 {
885     frame.editor().toggleOverwriteModeEnabled();
886     return true;
887 }
888
889 static bool executePaste(Frame& frame, Event*, EditorCommandSource source, const String&)
890 {
891     if (source == CommandFromMenuOrKeyBinding) {
892         UserTypingGestureIndicator typingGestureIndicator(frame);
893         frame.editor().paste();
894     } else
895         frame.editor().paste();
896     return true;
897 }
898
899 #if PLATFORM(GTK)
900
901 static bool executePasteGlobalSelection(Frame& frame, Event*, EditorCommandSource source, const String&)
902 {
903     // FIXME: This check should be in an enable function, not here.
904     if (!frame.editor().client()->supportsGlobalSelection())
905         return false;
906
907     ASSERT_UNUSED(source, source == CommandFromMenuOrKeyBinding);
908     UserTypingGestureIndicator typingGestureIndicator(frame);
909     frame.editor().paste(*Pasteboard::createForGlobalSelection());
910     return true;
911 }
912
913 #endif
914
915 static bool executePasteAndMatchStyle(Frame& frame, Event*, EditorCommandSource source, const String&)
916 {
917     if (source == CommandFromMenuOrKeyBinding) {
918         UserTypingGestureIndicator typingGestureIndicator(frame);
919         frame.editor().pasteAsPlainText();
920     } else
921         frame.editor().pasteAsPlainText();
922     return true;
923 }
924
925 static bool executePasteAsPlainText(Frame& frame, Event*, EditorCommandSource source, const String&)
926 {
927     if (source == CommandFromMenuOrKeyBinding) {
928         UserTypingGestureIndicator typingGestureIndicator(frame);
929         frame.editor().pasteAsPlainText();
930     } else
931         frame.editor().pasteAsPlainText();
932     return true;
933 }
934
935 static bool executePrint(Frame& frame, Event*, EditorCommandSource, const String&)
936 {
937     Page* page = frame.page();
938     if (!page)
939         return false;
940     page->chrome().print(&frame);
941     return true;
942 }
943
944 static bool executeRedo(Frame& frame, Event*, EditorCommandSource, const String&)
945 {
946     frame.editor().redo();
947     return true;
948 }
949
950 static bool executeRemoveFormat(Frame& frame, Event*, EditorCommandSource, const String&)
951 {
952     frame.editor().removeFormattingAndStyle();
953     return true;
954 }
955
956 static bool executeScrollPageBackward(Frame& frame, Event*, EditorCommandSource, const String&)
957 {
958     return frame.eventHandler().logicalScrollRecursively(ScrollBlockDirectionBackward, ScrollByPage);
959 }
960
961 static bool executeScrollPageForward(Frame& frame, Event*, EditorCommandSource, const String&)
962 {
963     return frame.eventHandler().logicalScrollRecursively(ScrollBlockDirectionForward, ScrollByPage);
964 }
965
966 static bool executeScrollLineUp(Frame& frame, Event*, EditorCommandSource, const String&)
967 {
968     return frame.eventHandler().scrollRecursively(ScrollUp, ScrollByLine);
969 }
970
971 static bool executeScrollLineDown(Frame& frame, Event*, EditorCommandSource, const String&)
972 {
973     return frame.eventHandler().scrollRecursively(ScrollDown, ScrollByLine);
974 }
975
976 static bool executeScrollToBeginningOfDocument(Frame& frame, Event*, EditorCommandSource, const String&)
977 {
978     return frame.eventHandler().logicalScrollRecursively(ScrollBlockDirectionBackward, ScrollByDocument);
979 }
980
981 static bool executeScrollToEndOfDocument(Frame& frame, Event*, EditorCommandSource, const String&)
982 {
983     return frame.eventHandler().logicalScrollRecursively(ScrollBlockDirectionForward, ScrollByDocument);
984 }
985
986 static bool executeSelectAll(Frame& frame, Event*, EditorCommandSource, const String&)
987 {
988     frame.selection().selectAll();
989     return true;
990 }
991
992 static bool executeSelectLine(Frame& frame, Event*, EditorCommandSource, const String&)
993 {
994     return expandSelectionToGranularity(frame, LineGranularity);
995 }
996
997 static bool executeSelectParagraph(Frame& frame, Event*, EditorCommandSource, const String&)
998 {
999     return expandSelectionToGranularity(frame, ParagraphGranularity);
1000 }
1001
1002 static bool executeSelectSentence(Frame& frame, Event*, EditorCommandSource, const String&)
1003 {
1004     return expandSelectionToGranularity(frame, SentenceGranularity);
1005 }
1006
1007 static bool executeSelectToMark(Frame& frame, Event*, EditorCommandSource, const String&)
1008 {
1009     RefPtr<Range> mark = frame.editor().mark().toNormalizedRange();
1010     RefPtr<Range> selection = frame.editor().selectedRange();
1011     if (!mark || !selection) {
1012         systemBeep();
1013         return false;
1014     }
1015     frame.selection().setSelectedRange(unionDOMRanges(mark.get(), selection.get()).get(), DOWNSTREAM, true);
1016     return true;
1017 }
1018
1019 static bool executeSelectWord(Frame& frame, Event*, EditorCommandSource, const String&)
1020 {
1021     return expandSelectionToGranularity(frame, WordGranularity);
1022 }
1023
1024 static bool executeSetMark(Frame& frame, Event*, EditorCommandSource, const String&)
1025 {
1026     frame.editor().setMark(frame.selection().selection());
1027     return true;
1028 }
1029
1030 static TextDecorationChange textDecorationChangeForToggling(Editor& editor, CSSPropertyID propertyID, const char* onValue)
1031 {
1032     return isStylePresent(editor, propertyID, onValue) ? TextDecorationChange::Remove : TextDecorationChange::Add;
1033 }
1034
1035 static bool executeStrikethrough(Frame& frame, Event*, EditorCommandSource source, const String&)
1036 {
1037     Ref<EditingStyle> style = EditingStyle::create();
1038     style->setStrikeThroughChange(textDecorationChangeForToggling(frame.editor(), CSSPropertyWebkitTextDecorationsInEffect, "line-through"));
1039     // FIXME: Needs a new EditAction!
1040     return applyCommandToFrame(frame, source, EditActionUnderline, WTFMove(style));
1041 }
1042
1043 static bool executeStyleWithCSS(Frame& frame, Event*, EditorCommandSource, const String& value)
1044 {
1045     frame.editor().setShouldStyleWithCSS(!equalIgnoringCase(value, "false"));
1046     return true;
1047 }
1048
1049 static bool executeUseCSS(Frame& frame, Event*, EditorCommandSource, const String& value)
1050 {
1051     frame.editor().setShouldStyleWithCSS(equalIgnoringCase(value, "false"));
1052     return true;
1053 }
1054
1055 static bool executeSubscript(Frame& frame, Event*, EditorCommandSource source, const String&)
1056 {
1057     return executeToggleStyle(frame, source, EditActionSubscript, CSSPropertyVerticalAlign, "baseline", "sub");
1058 }
1059
1060 static bool executeSuperscript(Frame& frame, Event*, EditorCommandSource source, const String&)
1061 {
1062     return executeToggleStyle(frame, source, EditActionSuperscript, CSSPropertyVerticalAlign, "baseline", "super");
1063 }
1064
1065 static bool executeSwapWithMark(Frame& frame, Event*, EditorCommandSource, const String&)
1066 {
1067     const VisibleSelection& mark = frame.editor().mark();
1068     const VisibleSelection& selection = frame.selection().selection();
1069     if (mark.isNone() || selection.isNone()) {
1070         systemBeep();
1071         return false;
1072     }
1073     frame.selection().setSelection(mark);
1074     frame.editor().setMark(selection);
1075     return true;
1076 }
1077
1078 #if PLATFORM(MAC)
1079 static bool executeTakeFindStringFromSelection(Frame& frame, Event*, EditorCommandSource, const String&)
1080 {
1081     frame.editor().takeFindStringFromSelection();
1082     return true;
1083 }
1084 #endif
1085
1086 static bool executeToggleBold(Frame& frame, Event*, EditorCommandSource source, const String&)
1087 {
1088     return executeToggleStyle(frame, source, EditActionBold, CSSPropertyFontWeight, "normal", "bold");
1089 }
1090
1091 static bool executeToggleItalic(Frame& frame, Event*, EditorCommandSource source, const String&)
1092 {
1093     return executeToggleStyle(frame, source, EditActionItalics, CSSPropertyFontStyle, "normal", "italic");
1094 }
1095
1096 static bool executeTranspose(Frame& frame, Event*, EditorCommandSource, const String&)
1097 {
1098     frame.editor().transpose();
1099     return true;
1100 }
1101
1102 static bool executeUnderline(Frame& frame, Event*, EditorCommandSource source, const String&)
1103 {
1104     Ref<EditingStyle> style = EditingStyle::create();
1105     TextDecorationChange change = textDecorationChangeForToggling(frame.editor(), CSSPropertyWebkitTextDecorationsInEffect, "underline");
1106     style->setUnderlineChange(change);
1107     return applyCommandToFrame(frame, source, EditActionUnderline, WTFMove(style));
1108 }
1109
1110 static bool executeUndo(Frame& frame, Event*, EditorCommandSource, const String&)
1111 {
1112     frame.editor().undo();
1113     return true;
1114 }
1115
1116 static bool executeUnlink(Frame& frame, Event*, EditorCommandSource, const String&)
1117 {
1118     ASSERT(frame.document());
1119     applyCommand(UnlinkCommand::create(*frame.document()));
1120     return true;
1121 }
1122
1123 static bool executeUnscript(Frame& frame, Event*, EditorCommandSource source, const String&)
1124 {
1125     return executeApplyStyle(frame, source, EditActionUnscript, CSSPropertyVerticalAlign, "baseline");
1126 }
1127
1128 static bool executeUnselect(Frame& frame, Event*, EditorCommandSource, const String&)
1129 {
1130     frame.selection().clear();
1131     return true;
1132 }
1133
1134 static bool executeYank(Frame& frame, Event*, EditorCommandSource, const String&)
1135 {
1136     frame.editor().insertTextWithoutSendingTextEvent(frame.editor().killRing().yank(), false, 0);
1137     frame.editor().killRing().setToYankedState();
1138     return true;
1139 }
1140
1141 static bool executeYankAndSelect(Frame& frame, Event*, EditorCommandSource, const String&)
1142 {
1143     frame.editor().insertTextWithoutSendingTextEvent(frame.editor().killRing().yank(), true, 0);
1144     frame.editor().killRing().setToYankedState();
1145     return true;
1146 }
1147
1148 // Supported functions
1149
1150 static bool supported(Frame*)
1151 {
1152     return true;
1153 }
1154
1155 static bool supportedFromMenuOrKeyBinding(Frame*)
1156 {
1157     return false;
1158 }
1159
1160 static bool supportedCopyCut(Frame* frame)
1161 {
1162     if (!frame)
1163         return false;
1164
1165     bool defaultValue = frame->settings().javaScriptCanAccessClipboard();
1166
1167     EditorClient* client = frame->editor().client();
1168     return client ? client->canCopyCut(frame, defaultValue) : defaultValue;
1169 }
1170
1171 static bool supportedPaste(Frame* frame)
1172 {
1173     if (!frame)
1174         return false;
1175
1176     bool defaultValue = frame->settings().javaScriptCanAccessClipboard() && frame->settings().DOMPasteAllowed();
1177
1178     EditorClient* client = frame->editor().client();
1179     return client ? client->canPaste(frame, defaultValue) : defaultValue;
1180 }
1181
1182 // Enabled functions
1183
1184 static bool enabled(Frame&, Event*, EditorCommandSource)
1185 {
1186     return true;
1187 }
1188
1189 static bool enabledVisibleSelection(Frame& frame, Event* event, EditorCommandSource)
1190 {
1191     // The term "visible" here includes a caret in editable text or a range in any text.
1192     const VisibleSelection& selection = frame.editor().selectionForCommand(event);
1193     return (selection.isCaret() && selection.isContentEditable()) || selection.isRange();
1194 }
1195
1196 static bool caretBrowsingEnabled(Frame& frame)
1197 {
1198     return frame.settings().caretBrowsingEnabled();
1199 }
1200
1201 static EditorCommandSource dummyEditorCommandSource = static_cast<EditorCommandSource>(0);
1202
1203 static bool enabledVisibleSelectionOrCaretBrowsing(Frame& frame, Event* event, EditorCommandSource)
1204 {
1205     // The EditorCommandSource parameter is unused in enabledVisibleSelection, so just pass a dummy variable
1206     return caretBrowsingEnabled(frame) || enabledVisibleSelection(frame, event, dummyEditorCommandSource);
1207 }
1208
1209 static bool enabledVisibleSelectionAndMark(Frame& frame, Event* event, EditorCommandSource)
1210 {
1211     const VisibleSelection& selection = frame.editor().selectionForCommand(event);
1212     return ((selection.isCaret() && selection.isContentEditable()) || selection.isRange())
1213         && frame.editor().mark().isCaretOrRange();
1214 }
1215
1216 static bool enableCaretInEditableText(Frame& frame, Event* event, EditorCommandSource)
1217 {
1218     const VisibleSelection& selection = frame.editor().selectionForCommand(event);
1219     return selection.isCaret() && selection.isContentEditable();
1220 }
1221
1222 static bool enabledCopy(Frame& frame, Event*, EditorCommandSource)
1223 {
1224     return frame.editor().canDHTMLCopy() || frame.editor().canCopy();
1225 }
1226
1227 static bool enabledCut(Frame& frame, Event*, EditorCommandSource)
1228 {
1229     return frame.editor().canDHTMLCut() || frame.editor().canCut();
1230 }
1231
1232 static bool enabledClearText(Frame& frame, Event*, EditorCommandSource)
1233 {
1234     UNUSED_PARAM(frame);
1235     return false;
1236 }
1237
1238 static bool enabledInEditableText(Frame& frame, Event* event, EditorCommandSource)
1239 {
1240     return frame.editor().selectionForCommand(event).rootEditableElement();
1241 }
1242
1243 static bool enabledDelete(Frame& frame, Event* event, EditorCommandSource source)
1244 {
1245     switch (source) {
1246     case CommandFromMenuOrKeyBinding:    
1247         return frame.editor().canDelete();
1248     case CommandFromDOM:
1249     case CommandFromDOMWithUserInterface:
1250         // "Delete" from DOM is like delete/backspace keypress, affects selected range if non-empty,
1251         // otherwise removes a character
1252         return enabledInEditableText(frame, event, source);
1253     }
1254     ASSERT_NOT_REACHED();
1255     return false;
1256 }
1257
1258 static bool enabledInEditableTextOrCaretBrowsing(Frame& frame, Event* event, EditorCommandSource)
1259 {
1260     // The EditorCommandSource parameter is unused in enabledInEditableText, so just pass a dummy variable
1261     return caretBrowsingEnabled(frame) || enabledInEditableText(frame, event, dummyEditorCommandSource);
1262 }
1263
1264 static bool enabledInRichlyEditableText(Frame& frame, Event*, EditorCommandSource)
1265 {
1266     const VisibleSelection& selection = frame.selection().selection();
1267     return selection.isCaretOrRange() && selection.isContentRichlyEditable() && selection.rootEditableElement();
1268 }
1269
1270 static bool enabledPaste(Frame& frame, Event*, EditorCommandSource)
1271 {
1272     return frame.editor().canPaste();
1273 }
1274
1275 static bool enabledRangeInEditableText(Frame& frame, Event*, EditorCommandSource)
1276 {
1277     return frame.selection().isRange() && frame.selection().selection().isContentEditable();
1278 }
1279
1280 static bool enabledRangeInRichlyEditableText(Frame& frame, Event*, EditorCommandSource)
1281 {
1282     return frame.selection().isRange() && frame.selection().selection().isContentRichlyEditable();
1283 }
1284
1285 static bool enabledRedo(Frame& frame, Event*, EditorCommandSource)
1286 {
1287     return frame.editor().canRedo();
1288 }
1289
1290 #if PLATFORM(MAC)
1291 static bool enabledTakeFindStringFromSelection(Frame& frame, Event*, EditorCommandSource)
1292 {
1293     return frame.editor().canCopyExcludingStandaloneImages();
1294 }
1295 #endif
1296
1297 static bool enabledUndo(Frame& frame, Event*, EditorCommandSource)
1298 {
1299     return frame.editor().canUndo();
1300 }
1301
1302 // State functions
1303
1304 static TriState stateNone(Frame&, Event*)
1305 {
1306     return FalseTriState;
1307 }
1308
1309 static TriState stateBold(Frame& frame, Event*)
1310 {
1311     return stateStyle(frame, CSSPropertyFontWeight, "bold");
1312 }
1313
1314 static TriState stateItalic(Frame& frame, Event*)
1315 {
1316     return stateStyle(frame, CSSPropertyFontStyle, "italic");
1317 }
1318
1319 static TriState stateOrderedList(Frame& frame, Event*)
1320 {
1321     return frame.editor().selectionOrderedListState();
1322 }
1323
1324 static TriState stateStrikethrough(Frame& frame, Event*)
1325 {
1326     return stateStyle(frame, CSSPropertyWebkitTextDecorationsInEffect, "line-through");
1327 }
1328
1329 static TriState stateStyleWithCSS(Frame& frame, Event*)
1330 {
1331     return frame.editor().shouldStyleWithCSS() ? TrueTriState : FalseTriState;
1332 }
1333
1334 static TriState stateSubscript(Frame& frame, Event*)
1335 {
1336     return stateStyle(frame, CSSPropertyVerticalAlign, "sub");
1337 }
1338
1339 static TriState stateSuperscript(Frame& frame, Event*)
1340 {
1341     return stateStyle(frame, CSSPropertyVerticalAlign, "super");
1342 }
1343
1344 static TriState stateTextWritingDirectionLeftToRight(Frame& frame, Event*)
1345 {
1346     return stateTextWritingDirection(frame, LeftToRightWritingDirection);
1347 }
1348
1349 static TriState stateTextWritingDirectionNatural(Frame& frame, Event*)
1350 {
1351     return stateTextWritingDirection(frame, NaturalWritingDirection);
1352 }
1353
1354 static TriState stateTextWritingDirectionRightToLeft(Frame& frame, Event*)
1355 {
1356     return stateTextWritingDirection(frame, RightToLeftWritingDirection);
1357 }
1358
1359 static TriState stateUnderline(Frame& frame, Event*)
1360 {
1361     return stateStyle(frame, CSSPropertyWebkitTextDecorationsInEffect, "underline");
1362 }
1363
1364 static TriState stateUnorderedList(Frame& frame, Event*)
1365 {
1366     return frame.editor().selectionUnorderedListState();
1367 }
1368
1369 static TriState stateJustifyCenter(Frame& frame, Event*)
1370 {
1371     return stateStyle(frame, CSSPropertyTextAlign, "center");
1372 }
1373
1374 static TriState stateJustifyFull(Frame& frame, Event*)
1375 {
1376     return stateStyle(frame, CSSPropertyTextAlign, "justify");
1377 }
1378
1379 static TriState stateJustifyLeft(Frame& frame, Event*)
1380 {
1381     return stateStyle(frame, CSSPropertyTextAlign, "left");
1382 }
1383
1384 static TriState stateJustifyRight(Frame& frame, Event*)
1385 {
1386     return stateStyle(frame, CSSPropertyTextAlign, "right");
1387 }
1388
1389 // Value functions
1390
1391 static String valueNull(Frame&, Event*)
1392 {
1393     return String();
1394 }
1395
1396 static String valueBackColor(Frame& frame, Event*)
1397 {
1398     return valueStyle(frame, CSSPropertyBackgroundColor);
1399 }
1400
1401 static String valueDefaultParagraphSeparator(Frame& frame, Event*)
1402 {
1403     switch (frame.editor().defaultParagraphSeparator()) {
1404     case EditorParagraphSeparatorIsDiv:
1405         return divTag.localName();
1406     case EditorParagraphSeparatorIsP:
1407         return pTag.localName();
1408     }
1409
1410     ASSERT_NOT_REACHED();
1411     return String();
1412 }
1413
1414 static String valueFontName(Frame& frame, Event*)
1415 {
1416     return valueStyle(frame, CSSPropertyFontFamily);
1417 }
1418
1419 static String valueFontSize(Frame& frame, Event*)
1420 {
1421     return valueStyle(frame, CSSPropertyFontSize);
1422 }
1423
1424 static String valueFontSizeDelta(Frame& frame, Event*)
1425 {
1426     return valueStyle(frame, CSSPropertyWebkitFontSizeDelta);
1427 }
1428
1429 static String valueForeColor(Frame& frame, Event*)
1430 {
1431     return valueStyle(frame, CSSPropertyColor);
1432 }
1433
1434 static String valueFormatBlock(Frame& frame, Event*)
1435 {
1436     const VisibleSelection& selection = frame.selection().selection();
1437     if (!selection.isNonOrphanedCaretOrRange() || !selection.isContentEditable())
1438         return "";
1439     Element* formatBlockElement = FormatBlockCommand::elementForFormatBlockCommand(selection.firstRange().get());
1440     if (!formatBlockElement)
1441         return "";
1442     return formatBlockElement->localName();
1443 }
1444
1445 // Map of functions
1446
1447 struct CommandEntry {
1448     const char* name;
1449     EditorInternalCommand command;
1450 };
1451
1452 static const CommandMap& createCommandMap()
1453 {
1454     static const CommandEntry commands[] = {
1455         { "AlignCenter", { executeJustifyCenter, supportedFromMenuOrKeyBinding, enabledInRichlyEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1456         { "AlignJustified", { executeJustifyFull, supportedFromMenuOrKeyBinding, enabledInRichlyEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1457         { "AlignLeft", { executeJustifyLeft, supportedFromMenuOrKeyBinding, enabledInRichlyEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1458         { "AlignRight", { executeJustifyRight, supportedFromMenuOrKeyBinding, enabledInRichlyEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1459         { "BackColor", { executeBackColor, supported, enabledInRichlyEditableText, stateNone, valueBackColor, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1460         { "Bold", { executeToggleBold, supported, enabledInRichlyEditableText, stateBold, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1461         { "ClearText", { executeClearText, supported, enabledClearText, stateNone, valueNull, notTextInsertion, allowExecutionWhenDisabled } },
1462         { "Copy", { executeCopy, supportedCopyCut, enabledCopy, stateNone, valueNull, notTextInsertion, allowExecutionWhenDisabled } },
1463         { "CreateLink", { executeCreateLink, supported, enabledInRichlyEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1464         { "Cut", { executeCut, supportedCopyCut, enabledCut, stateNone, valueNull, notTextInsertion, allowExecutionWhenDisabled } },
1465         { "DefaultParagraphSeparator", { executeDefaultParagraphSeparator, supported, enabled, stateNone, valueDefaultParagraphSeparator, notTextInsertion, doNotAllowExecutionWhenDisabled} },
1466         { "Delete", { executeDelete, supported, enabledDelete, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1467         { "DeleteBackward", { executeDeleteBackward, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1468         { "DeleteBackwardByDecomposingPreviousCharacter", { executeDeleteBackwardByDecomposingPreviousCharacter, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1469         { "DeleteForward", { executeDeleteForward, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1470         { "DeleteToBeginningOfLine", { executeDeleteToBeginningOfLine, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1471         { "DeleteToBeginningOfParagraph", { executeDeleteToBeginningOfParagraph, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1472         { "DeleteToEndOfLine", { executeDeleteToEndOfLine, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1473         { "DeleteToEndOfParagraph", { executeDeleteToEndOfParagraph, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1474         { "DeleteToMark", { executeDeleteToMark, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1475         { "DeleteWordBackward", { executeDeleteWordBackward, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1476         { "DeleteWordForward", { executeDeleteWordForward, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1477         { "FindString", { executeFindString, supported, enabled, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1478         { "FontName", { executeFontName, supported, enabledInEditableText, stateNone, valueFontName, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1479         { "FontSize", { executeFontSize, supported, enabledInEditableText, stateNone, valueFontSize, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1480         { "FontSizeDelta", { executeFontSizeDelta, supported, enabledInEditableText, stateNone, valueFontSizeDelta, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1481         { "ForeColor", { executeForeColor, supported, enabledInRichlyEditableText, stateNone, valueForeColor, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1482         { "FormatBlock", { executeFormatBlock, supported, enabledInRichlyEditableText, stateNone, valueFormatBlock, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1483         { "ForwardDelete", { executeForwardDelete, supported, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1484         { "HiliteColor", { executeBackColor, supported, enabledInRichlyEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1485         { "IgnoreSpelling", { executeIgnoreSpelling, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1486         { "Indent", { executeIndent, supported, enabledInRichlyEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1487         { "InsertBacktab", { executeInsertBacktab, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, isTextInsertion, doNotAllowExecutionWhenDisabled } },
1488         { "InsertHTML", { executeInsertHTML, supported, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1489         { "InsertHorizontalRule", { executeInsertHorizontalRule, supported, enabledInRichlyEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1490         { "InsertImage", { executeInsertImage, supported, enabledInRichlyEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1491         { "InsertLineBreak", { executeInsertLineBreak, supported, enabledInEditableText, stateNone, valueNull, isTextInsertion, doNotAllowExecutionWhenDisabled } },
1492         { "InsertNewline", { executeInsertNewline, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, isTextInsertion, doNotAllowExecutionWhenDisabled } },    
1493         { "InsertNewlineInQuotedContent", { executeInsertNewlineInQuotedContent, supported, enabledInRichlyEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1494         { "InsertOrderedList", { executeInsertOrderedList, supported, enabledInRichlyEditableText, stateOrderedList, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1495         { "InsertParagraph", { executeInsertParagraph, supported, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1496         { "InsertTab", { executeInsertTab, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, isTextInsertion, doNotAllowExecutionWhenDisabled } },
1497         { "InsertText", { executeInsertText, supported, enabledInEditableText, stateNone, valueNull, isTextInsertion, doNotAllowExecutionWhenDisabled } },
1498         { "InsertUnorderedList", { executeInsertUnorderedList, supported, enabledInRichlyEditableText, stateUnorderedList, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1499         { "Italic", { executeToggleItalic, supported, enabledInRichlyEditableText, stateItalic, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1500         { "JustifyCenter", { executeJustifyCenter, supported, enabledInRichlyEditableText, stateJustifyCenter, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1501         { "JustifyFull", { executeJustifyFull, supported, enabledInRichlyEditableText, stateJustifyFull, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1502         { "JustifyLeft", { executeJustifyLeft, supported, enabledInRichlyEditableText, stateJustifyLeft, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1503         { "JustifyNone", { executeJustifyLeft, supported, enabledInRichlyEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1504         { "JustifyRight", { executeJustifyRight, supported, enabledInRichlyEditableText, stateJustifyRight, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1505         { "MakeTextWritingDirectionLeftToRight", { executeMakeTextWritingDirectionLeftToRight, supportedFromMenuOrKeyBinding, enabledInRichlyEditableText, stateTextWritingDirectionLeftToRight, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1506         { "MakeTextWritingDirectionNatural", { executeMakeTextWritingDirectionNatural, supportedFromMenuOrKeyBinding, enabledInRichlyEditableText, stateTextWritingDirectionNatural, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1507         { "MakeTextWritingDirectionRightToLeft", { executeMakeTextWritingDirectionRightToLeft, supportedFromMenuOrKeyBinding, enabledInRichlyEditableText, stateTextWritingDirectionRightToLeft, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1508         { "MoveBackward", { executeMoveBackward, supportedFromMenuOrKeyBinding, enabledInEditableTextOrCaretBrowsing, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1509         { "MoveBackwardAndModifySelection", { executeMoveBackwardAndModifySelection, supportedFromMenuOrKeyBinding, enabledVisibleSelectionOrCaretBrowsing, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1510         { "MoveDown", { executeMoveDown, supportedFromMenuOrKeyBinding, enabledInEditableTextOrCaretBrowsing, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1511         { "MoveDownAndModifySelection", { executeMoveDownAndModifySelection, supportedFromMenuOrKeyBinding, enabledVisibleSelectionOrCaretBrowsing, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1512         { "MoveForward", { executeMoveForward, supportedFromMenuOrKeyBinding, enabledInEditableTextOrCaretBrowsing, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1513         { "MoveForwardAndModifySelection", { executeMoveForwardAndModifySelection, supportedFromMenuOrKeyBinding, enabledVisibleSelectionOrCaretBrowsing, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1514         { "MoveLeft", { executeMoveLeft, supportedFromMenuOrKeyBinding, enabledInEditableTextOrCaretBrowsing, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1515         { "MoveLeftAndModifySelection", { executeMoveLeftAndModifySelection, supportedFromMenuOrKeyBinding, enabledVisibleSelectionOrCaretBrowsing, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1516         { "MovePageDown", { executeMovePageDown, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1517         { "MovePageDownAndModifySelection", { executeMovePageDownAndModifySelection, supportedFromMenuOrKeyBinding, enabledVisibleSelection, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1518         { "MovePageUp", { executeMovePageUp, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1519         { "MovePageUpAndModifySelection", { executeMovePageUpAndModifySelection, supportedFromMenuOrKeyBinding, enabledVisibleSelection, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1520         { "MoveParagraphBackwardAndModifySelection", { executeMoveParagraphBackwardAndModifySelection, supportedFromMenuOrKeyBinding, enabledVisibleSelectionOrCaretBrowsing, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1521         { "MoveParagraphForwardAndModifySelection", { executeMoveParagraphForwardAndModifySelection, supportedFromMenuOrKeyBinding, enabledVisibleSelectionOrCaretBrowsing, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1522         { "MoveRight", { executeMoveRight, supportedFromMenuOrKeyBinding, enabledInEditableTextOrCaretBrowsing, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1523         { "MoveRightAndModifySelection", { executeMoveRightAndModifySelection, supportedFromMenuOrKeyBinding, enabledVisibleSelectionOrCaretBrowsing, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1524         { "MoveToBeginningOfDocument", { executeMoveToBeginningOfDocument, supportedFromMenuOrKeyBinding, enabledInEditableTextOrCaretBrowsing, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1525         { "MoveToBeginningOfDocumentAndModifySelection", { executeMoveToBeginningOfDocumentAndModifySelection, supportedFromMenuOrKeyBinding, enabledVisibleSelectionOrCaretBrowsing, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1526         { "MoveToBeginningOfLine", { executeMoveToBeginningOfLine, supportedFromMenuOrKeyBinding, enabledInEditableTextOrCaretBrowsing, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1527         { "MoveToBeginningOfLineAndModifySelection", { executeMoveToBeginningOfLineAndModifySelection, supportedFromMenuOrKeyBinding, enabledVisibleSelectionOrCaretBrowsing, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1528         { "MoveToBeginningOfParagraph", { executeMoveToBeginningOfParagraph, supportedFromMenuOrKeyBinding, enabledInEditableTextOrCaretBrowsing, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1529         { "MoveToBeginningOfParagraphAndModifySelection", { executeMoveToBeginningOfParagraphAndModifySelection, supportedFromMenuOrKeyBinding, enabledVisibleSelectionOrCaretBrowsing, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1530         { "MoveToBeginningOfSentence", { executeMoveToBeginningOfSentence, supportedFromMenuOrKeyBinding, enabledInEditableTextOrCaretBrowsing, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1531         { "MoveToBeginningOfSentenceAndModifySelection", { executeMoveToBeginningOfSentenceAndModifySelection, supportedFromMenuOrKeyBinding, enabledVisibleSelectionOrCaretBrowsing, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1532         { "MoveToEndOfDocument", { executeMoveToEndOfDocument, supportedFromMenuOrKeyBinding, enabledInEditableTextOrCaretBrowsing, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1533         { "MoveToEndOfDocumentAndModifySelection", { executeMoveToEndOfDocumentAndModifySelection, supportedFromMenuOrKeyBinding, enabledVisibleSelectionOrCaretBrowsing, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1534         { "MoveToEndOfLine", { executeMoveToEndOfLine, supportedFromMenuOrKeyBinding, enabledInEditableTextOrCaretBrowsing, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1535         { "MoveToEndOfLineAndModifySelection", { executeMoveToEndOfLineAndModifySelection, supportedFromMenuOrKeyBinding, enabledVisibleSelectionOrCaretBrowsing, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1536         { "MoveToEndOfParagraph", { executeMoveToEndOfParagraph, supportedFromMenuOrKeyBinding, enabledInEditableTextOrCaretBrowsing, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1537         { "MoveToEndOfParagraphAndModifySelection", { executeMoveToEndOfParagraphAndModifySelection, supportedFromMenuOrKeyBinding, enabledVisibleSelectionOrCaretBrowsing, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1538         { "MoveToEndOfSentence", { executeMoveToEndOfSentence, supportedFromMenuOrKeyBinding, enabledInEditableTextOrCaretBrowsing, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1539         { "MoveToEndOfSentenceAndModifySelection", { executeMoveToEndOfSentenceAndModifySelection, supportedFromMenuOrKeyBinding, enabledVisibleSelectionOrCaretBrowsing, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1540         { "MoveToLeftEndOfLine", { executeMoveToLeftEndOfLine, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1541         { "MoveToLeftEndOfLineAndModifySelection", { executeMoveToLeftEndOfLineAndModifySelection, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1542         { "MoveToRightEndOfLine", { executeMoveToRightEndOfLine, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1543         { "MoveToRightEndOfLineAndModifySelection", { executeMoveToRightEndOfLineAndModifySelection, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1544         { "MoveUp", { executeMoveUp, supportedFromMenuOrKeyBinding, enabledInEditableTextOrCaretBrowsing, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1545         { "MoveUpAndModifySelection", { executeMoveUpAndModifySelection, supportedFromMenuOrKeyBinding, enabledVisibleSelectionOrCaretBrowsing, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1546         { "MoveWordBackward", { executeMoveWordBackward, supportedFromMenuOrKeyBinding, enabledInEditableTextOrCaretBrowsing, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1547         { "MoveWordBackwardAndModifySelection", { executeMoveWordBackwardAndModifySelection, supportedFromMenuOrKeyBinding, enabledVisibleSelectionOrCaretBrowsing, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1548         { "MoveWordForward", { executeMoveWordForward, supportedFromMenuOrKeyBinding, enabledInEditableTextOrCaretBrowsing, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1549         { "MoveWordForwardAndModifySelection", { executeMoveWordForwardAndModifySelection, supportedFromMenuOrKeyBinding, enabledVisibleSelectionOrCaretBrowsing, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1550         { "MoveWordLeft", { executeMoveWordLeft, supportedFromMenuOrKeyBinding, enabledInEditableTextOrCaretBrowsing, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1551         { "MoveWordLeftAndModifySelection", { executeMoveWordLeftAndModifySelection, supportedFromMenuOrKeyBinding, enabledVisibleSelectionOrCaretBrowsing, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1552         { "MoveWordRight", { executeMoveWordRight, supportedFromMenuOrKeyBinding, enabledInEditableTextOrCaretBrowsing, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1553         { "MoveWordRightAndModifySelection", { executeMoveWordRightAndModifySelection, supportedFromMenuOrKeyBinding, enabledVisibleSelectionOrCaretBrowsing, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1554         { "Outdent", { executeOutdent, supported, enabledInRichlyEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1555         { "OverWrite", { executeToggleOverwrite, supportedFromMenuOrKeyBinding, enabledInRichlyEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1556         { "Paste", { executePaste, supportedPaste, enabledPaste, stateNone, valueNull, notTextInsertion, allowExecutionWhenDisabled } },
1557         { "PasteAndMatchStyle", { executePasteAndMatchStyle, supportedPaste, enabledPaste, stateNone, valueNull, notTextInsertion, allowExecutionWhenDisabled } },
1558         { "PasteAsPlainText", { executePasteAsPlainText, supportedPaste, enabledPaste, stateNone, valueNull, notTextInsertion, allowExecutionWhenDisabled } },
1559         { "Print", { executePrint, supported, enabled, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1560         { "Redo", { executeRedo, supported, enabledRedo, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1561         { "RemoveFormat", { executeRemoveFormat, supported, enabledRangeInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1562         { "ScrollPageBackward", { executeScrollPageBackward, supportedFromMenuOrKeyBinding, enabled, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1563         { "ScrollPageForward", { executeScrollPageForward, supportedFromMenuOrKeyBinding, enabled, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1564         { "ScrollLineUp", { executeScrollLineUp, supportedFromMenuOrKeyBinding, enabled, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1565         { "ScrollLineDown", { executeScrollLineDown, supportedFromMenuOrKeyBinding, enabled, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1566         { "ScrollToBeginningOfDocument", { executeScrollToBeginningOfDocument, supportedFromMenuOrKeyBinding, enabled, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1567         { "ScrollToEndOfDocument", { executeScrollToEndOfDocument, supportedFromMenuOrKeyBinding, enabled, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1568         { "SelectAll", { executeSelectAll, supported, enabled, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1569         { "SelectLine", { executeSelectLine, supportedFromMenuOrKeyBinding, enabledVisibleSelection, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1570         { "SelectParagraph", { executeSelectParagraph, supportedFromMenuOrKeyBinding, enabledVisibleSelection, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1571         { "SelectSentence", { executeSelectSentence, supportedFromMenuOrKeyBinding, enabledVisibleSelection, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1572         { "SelectToMark", { executeSelectToMark, supportedFromMenuOrKeyBinding, enabledVisibleSelectionAndMark, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1573         { "SelectWord", { executeSelectWord, supportedFromMenuOrKeyBinding, enabledVisibleSelection, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1574         { "SetMark", { executeSetMark, supportedFromMenuOrKeyBinding, enabledVisibleSelection, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1575         { "Strikethrough", { executeStrikethrough, supported, enabledInRichlyEditableText, stateStrikethrough, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1576         { "StyleWithCSS", { executeStyleWithCSS, supported, enabled, stateStyleWithCSS, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1577         { "Subscript", { executeSubscript, supported, enabledInRichlyEditableText, stateSubscript, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1578         { "Superscript", { executeSuperscript, supported, enabledInRichlyEditableText, stateSuperscript, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1579         { "SwapWithMark", { executeSwapWithMark, supportedFromMenuOrKeyBinding, enabledVisibleSelectionAndMark, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1580         { "ToggleBold", { executeToggleBold, supportedFromMenuOrKeyBinding, enabledInRichlyEditableText, stateBold, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1581         { "ToggleItalic", { executeToggleItalic, supportedFromMenuOrKeyBinding, enabledInRichlyEditableText, stateItalic, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1582         { "ToggleUnderline", { executeUnderline, supportedFromMenuOrKeyBinding, enabledInRichlyEditableText, stateUnderline, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1583         { "Transpose", { executeTranspose, supported, enableCaretInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1584         { "Underline", { executeUnderline, supported, enabledInRichlyEditableText, stateUnderline, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1585         { "Undo", { executeUndo, supported, enabledUndo, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1586         { "Unlink", { executeUnlink, supported, enabledRangeInRichlyEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1587         { "Unscript", { executeUnscript, supportedFromMenuOrKeyBinding, enabledInRichlyEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1588         { "Unselect", { executeUnselect, supported, enabledVisibleSelection, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1589         { "UseCSS", { executeUseCSS, supported, enabled, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1590         { "Yank", { executeYank, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1591         { "YankAndSelect", { executeYankAndSelect, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1592
1593 #if PLATFORM(GTK)
1594         { "PasteGlobalSelection", { executePasteGlobalSelection, supportedFromMenuOrKeyBinding, enabledPaste, stateNone, valueNull, notTextInsertion, allowExecutionWhenDisabled } },
1595 #endif
1596
1597 #if PLATFORM(MAC)
1598         { "TakeFindStringFromSelection", { executeTakeFindStringFromSelection, supportedFromMenuOrKeyBinding, enabledTakeFindStringFromSelection, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1599 #endif
1600     };
1601
1602     // These unsupported commands are listed here since they appear in the Microsoft
1603     // documentation used as the starting point for our DOM executeCommand support.
1604     //
1605     // 2D-Position (not supported)
1606     // AbsolutePosition (not supported)
1607     // BlockDirLTR (not supported)
1608     // BlockDirRTL (not supported)
1609     // BrowseMode (not supported)
1610     // ClearAuthenticationCache (not supported)
1611     // CreateBookmark (not supported)
1612     // DirLTR (not supported)
1613     // DirRTL (not supported)
1614     // EditMode (not supported)
1615     // InlineDirLTR (not supported)
1616     // InlineDirRTL (not supported)
1617     // InsertButton (not supported)
1618     // InsertFieldSet (not supported)
1619     // InsertIFrame (not supported)
1620     // InsertInputButton (not supported)
1621     // InsertInputCheckbox (not supported)
1622     // InsertInputFileUpload (not supported)
1623     // InsertInputHidden (not supported)
1624     // InsertInputImage (not supported)
1625     // InsertInputPassword (not supported)
1626     // InsertInputRadio (not supported)
1627     // InsertInputReset (not supported)
1628     // InsertInputSubmit (not supported)
1629     // InsertInputText (not supported)
1630     // InsertMarquee (not supported)
1631     // InsertSelectDropDown (not supported)
1632     // InsertSelectListBox (not supported)
1633     // InsertTextArea (not supported)
1634     // LiveResize (not supported)
1635     // MultipleSelection (not supported)
1636     // Open (not supported)
1637     // PlayImage (not supported)
1638     // Refresh (not supported)
1639     // RemoveParaFormat (not supported)
1640     // SaveAs (not supported)
1641     // SizeToControl (not supported)
1642     // SizeToControlHeight (not supported)
1643     // SizeToControlWidth (not supported)
1644     // Stop (not supported)
1645     // StopImage (not supported)
1646     // Unbookmark (not supported)
1647
1648     CommandMap& commandMap = *new CommandMap;
1649
1650     for (auto& command : commands) {
1651         ASSERT(!commandMap.get(command.name));
1652         commandMap.set(command.name, &command.command);
1653     }
1654
1655     return commandMap;
1656 }
1657
1658 static const EditorInternalCommand* internalCommand(const String& commandName)
1659 {
1660     static const CommandMap& commandMap = createCommandMap();
1661     return commandName.isEmpty() ? 0 : commandMap.get(commandName);
1662 }
1663
1664 Editor::Command Editor::command(const String& commandName)
1665 {
1666     return Command(internalCommand(commandName), CommandFromMenuOrKeyBinding, &m_frame);
1667 }
1668
1669 Editor::Command Editor::command(const String& commandName, EditorCommandSource source)
1670 {
1671     return Command(internalCommand(commandName), source, &m_frame);
1672 }
1673
1674 bool Editor::commandIsSupportedFromMenuOrKeyBinding(const String& commandName)
1675 {
1676     return internalCommand(commandName);
1677 }
1678
1679 Editor::Command::Command()
1680 {
1681 }
1682
1683 Editor::Command::Command(const EditorInternalCommand* command, EditorCommandSource source, PassRefPtr<Frame> frame)
1684     : m_command(command)
1685     , m_source(source)
1686     , m_frame(command ? frame : 0)
1687 {
1688     // Use separate assertions so we can tell which bad thing happened.
1689     if (!command)
1690         ASSERT(!m_frame);
1691     else
1692         ASSERT(m_frame);
1693 }
1694
1695 bool Editor::Command::execute(const String& parameter, Event* triggeringEvent) const
1696 {
1697     if (!isEnabled(triggeringEvent)) {
1698         // Let certain commands be executed when performed explicitly even if they are disabled.
1699         if (!isSupported() || !m_frame || !m_command->allowExecutionWhenDisabled)
1700             return false;
1701     }
1702     m_frame->document()->updateLayoutIgnorePendingStylesheets();
1703     return m_command->execute(*m_frame, triggeringEvent, m_source, parameter);
1704 }
1705
1706 bool Editor::Command::execute(Event* triggeringEvent) const
1707 {
1708     return execute(String(), triggeringEvent);
1709 }
1710
1711 bool Editor::Command::isSupported() const
1712 {
1713     if (!m_command)
1714         return false;
1715     switch (m_source) {
1716     case CommandFromMenuOrKeyBinding:
1717         return true;
1718     case CommandFromDOM:
1719     case CommandFromDOMWithUserInterface:
1720         return m_command->isSupportedFromDOM(m_frame.get());
1721     }
1722     ASSERT_NOT_REACHED();
1723     return false;
1724 }
1725
1726 bool Editor::Command::isEnabled(Event* triggeringEvent) const
1727 {
1728     if (!isSupported() || !m_frame)
1729         return false;
1730     return m_command->isEnabled(*m_frame, triggeringEvent, m_source);
1731 }
1732
1733 TriState Editor::Command::state(Event* triggeringEvent) const
1734 {
1735     if (!isSupported() || !m_frame)
1736         return FalseTriState;
1737     return m_command->state(*m_frame, triggeringEvent);
1738 }
1739
1740 String Editor::Command::value(Event* triggeringEvent) const
1741 {
1742     if (!isSupported() || !m_frame)
1743         return String();
1744     if (m_command->value == valueNull && m_command->state != stateNone)
1745         return m_command->state(*m_frame, triggeringEvent) == TrueTriState ? "true" : "false";
1746     return m_command->value(*m_frame, triggeringEvent);
1747 }
1748
1749 bool Editor::Command::isTextInsertion() const
1750 {
1751     return m_command && m_command->isTextInsertion;
1752 }
1753
1754 } // namespace WebCore