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