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