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