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