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 64 namespace WebCore { 65 66 using namespace HTMLNames; 67 68 class EditorInternalCommand { 69 public: 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 79 typedef HashMap<String, const EditorInternalCommand*, CaseFoldingHash> CommandMap; 80 81 static const bool notTextInsertion = false; 82 static const bool isTextInsertion = true; 83 84 static const bool allowExecutionWhenDisabled = true; 85 static 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. 90 static 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 100 static 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 116 static 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 123 static 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. 133 static 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 158 static 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 174 static 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 192 static bool executeInsertFragment(Frame* frame, PassRefPtr<DocumentFragment> fragment) 193 { 194 applyCommand(ReplaceSelectionCommand::create(frame->document(), fragment, ReplaceSelectionCommand::PreventNesting, EditActionUnspecified)); 195 return true; 196 } 197 198 static 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 208 static 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 226 static 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 233 static 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 240 static 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 247 static 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 265 static 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 278 static bool executeBackColor(Frame* frame, Event*, EditorCommandSource source, const String& value) 279 { 280 return executeApplyStyle(frame, source, EditActionSetBackgroundColor, CSSPropertyBackgroundColor, value); 281 } 282 283 static bool executeCopy(Frame* frame, Event*, EditorCommandSource, const String&) 284 { 285 frame->editor()->copy(); 286 return true; 287 } 288 289 static 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 298 static 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 308 static 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 328 static bool executeDeleteBackward(Frame* frame, Event*, EditorCommandSource, const String&) 329 { 330 frame->editor()->deleteWithDirection(DirectionBackward, CharacterGranularity, false, true); 331 return true; 332 } 333 334 static 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 341 static bool executeDeleteForward(Frame* frame, Event*, EditorCommandSource, const String&) 342 { 343 frame->editor()->deleteWithDirection(DirectionForward, CharacterGranularity, false, true); 344 return true; 345 } 346 347 static bool executeDeleteToBeginningOfLine(Frame* frame, Event*, EditorCommandSource, const String&) 348 { 349 frame->editor()->deleteWithDirection(DirectionBackward, LineBoundary, true, false); 350 return true; 351 } 352 353 static bool executeDeleteToBeginningOfParagraph(Frame* frame, Event*, EditorCommandSource, const String&) 354 { 355 frame->editor()->deleteWithDirection(DirectionBackward, ParagraphBoundary, true, false); 356 return true; 357 } 358 359 static 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 367 static 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 375 static 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 390 static bool executeDeleteWordBackward(Frame* frame, Event*, EditorCommandSource, const String&) 391 { 392 frame->editor()->deleteWithDirection(DirectionBackward, WordGranularity, true, false); 393 return true; 394 } 395 396 static bool executeDeleteWordForward(Frame* frame, Event*, EditorCommandSource, const String&) 397 { 398 frame->editor()->deleteWithDirection(DirectionForward, WordGranularity, true, false); 399 return true; 400 } 401 402 static bool executeFindString(Frame* frame, Event*, EditorCommandSource, const String& value) 403 { 404 return frame->editor()->findString(value, true, false, true, false); 405 } 406 407 static bool executeFontName(Frame* frame, Event*, EditorCommandSource source, const String& value) 408 { 409 return executeApplyStyle(frame, source, EditActionSetFont, CSSPropertyFontFamily, value); 410 } 411 412 static 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 420 static bool executeFontSizeDelta(Frame* frame, Event*, EditorCommandSource source, const String& value) 421 { 422 return executeApplyStyle(frame, source, EditActionChangeAttributes, CSSPropertyWebkitFontSizeDelta, value); 423 } 424 425 static bool executeForeColor(Frame* frame, Event*, EditorCommandSource source, const String& value) 426 { 427 return executeApplyStyle(frame, source, EditActionSetColor, CSSPropertyColor, value); 428 } 429 430 static 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 447 static 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 465 static bool executeIgnoreSpelling(Frame* frame, Event*, EditorCommandSource, const String&) 466 { 467 frame->editor()->ignoreSpelling(); 468 return true; 469 } 470 471 static bool executeIndent(Frame* frame, Event*, EditorCommandSource, const String&) 472 { 473 applyCommand(IndentOutdentCommand::create(frame->document(), IndentOutdentCommand::Indent)); 474 return true; 475 } 476 477 static bool executeInsertBacktab(Frame* frame, Event* event, EditorCommandSource, const String&) 478 { 479 return targetFrame(frame, event)->eventHandler()->handleTextInputEvent("\t", event, TextEventInputBackTab); 480 } 481 482 static 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 490 static bool executeInsertHTML(Frame* frame, Event*, EditorCommandSource, const String& value) 491 { 492 return executeInsertFragment(frame, createFragmentFromMarkup(frame->document(), value, "")); 493 } 494 495 static 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 503 static 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 520 static 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 526 static bool executeInsertNewlineInQuotedContent(Frame* frame, Event*, EditorCommandSource, const String&) 527 { 528 TypingCommand::insertParagraphSeparatorInQuotedContent(frame->document()); 529 return true; 530 } 531 532 static bool executeInsertOrderedList(Frame* frame, Event*, EditorCommandSource, const String&) 533 { 534 applyCommand(InsertListCommand::create(frame->document(), InsertListCommand::OrderedList)); 535 return true; 536 } 537 538 static bool executeInsertParagraph(Frame* frame, Event*, EditorCommandSource, const String&) 539 { 540 TypingCommand::insertParagraphSeparator(frame->document(), 0); 541 return true; 542 } 543 544 static bool executeInsertTab(Frame* frame, Event* event, EditorCommandSource, const String&) 545 { 546 return targetFrame(frame, event)->eventHandler()->handleTextInputEvent("\t", event); 547 } 548 549 static bool executeInsertText(Frame* frame, Event*, EditorCommandSource, const String& value) 550 { 551 TypingCommand::insertText(frame->document(), value, 0); 552 return true; 553 } 554 555 static bool executeInsertUnorderedList(Frame* frame, Event*, EditorCommandSource, const String&) 556 { 557 applyCommand(InsertListCommand::create(frame->document(), InsertListCommand::UnorderedList)); 558 return true; 559 } 560 561 static bool executeJustifyCenter(Frame* frame, Event*, EditorCommandSource source, const String&) 562 { 563 return executeApplyParagraphStyle(frame, source, EditActionCenter, CSSPropertyTextAlign, "center"); 564 } 565 566 static bool executeJustifyFull(Frame* frame, Event*, EditorCommandSource source, const String&) 567 { 568 return executeApplyParagraphStyle(frame, source, EditActionJustify, CSSPropertyTextAlign, "justify"); 569 } 570 571 static bool executeJustifyLeft(Frame* frame, Event*, EditorCommandSource source, const String&) 572 { 573 return executeApplyParagraphStyle(frame, source, EditActionAlignLeft, CSSPropertyTextAlign, "left"); 574 } 575 576 static bool executeJustifyRight(Frame* frame, Event*, EditorCommandSource source, const String&) 577 { 578 return executeApplyParagraphStyle(frame, source, EditActionAlignRight, CSSPropertyTextAlign, "right"); 579 } 580 581 static 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 590 static 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 598 static 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 607 static bool executeMoveBackward(Frame* frame, Event*, EditorCommandSource, const String&) 608 { 609 frame->selection()->modify(SelectionController::AlterationMove, DirectionBackward, CharacterGranularity, true); 610 return true; 611 } 612 613 static bool executeMoveBackwardAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&) 614 { 615 frame->selection()->modify(SelectionController::AlterationExtend, DirectionBackward, CharacterGranularity, true); 616 return true; 617 } 618 619 static bool executeMoveDown(Frame* frame, Event*, EditorCommandSource, const String&) 620 { 621 return frame->selection()->modify(SelectionController::AlterationMove, DirectionForward, LineGranularity, true); 622 } 623 624 static bool executeMoveDownAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&) 625 { 626 frame->selection()->modify(SelectionController::AlterationExtend, DirectionForward, LineGranularity, true); 627 return true; 628 } 629 630 static bool executeMoveForward(Frame* frame, Event*, EditorCommandSource, const String&) 631 { 632 frame->selection()->modify(SelectionController::AlterationMove, DirectionForward, CharacterGranularity, true); 633 return true; 634 } 635 636 static bool executeMoveForwardAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&) 637 { 638 frame->selection()->modify(SelectionController::AlterationExtend, DirectionForward, CharacterGranularity, true); 639 return true; 640 } 641 642 static bool executeMoveLeft(Frame* frame, Event*, EditorCommandSource, const String&) 643 { 644 return frame->selection()->modify(SelectionController::AlterationMove, DirectionLeft, CharacterGranularity, true); 645 } 646 647 static bool executeMoveLeftAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&) 648 { 649 frame->selection()->modify(SelectionController::AlterationExtend, DirectionLeft, CharacterGranularity, true); 650 return true; 651 } 652 653 static 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 661 static 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 669 static 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 677 static 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 685 static bool executeMoveRight(Frame* frame, Event*, EditorCommandSource, const String&) 686 { 687 return frame->selection()->modify(SelectionController::AlterationMove, DirectionRight, CharacterGranularity, true); 688 } 689 690 static bool executeMoveRightAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&) 691 { 692 frame->selection()->modify(SelectionController::AlterationExtend, DirectionRight, CharacterGranularity, true); 693 return true; 694 } 695 696 static bool executeMoveToBeginningOfDocument(Frame* frame, Event*, EditorCommandSource, const String&) 697 { 698 frame->selection()->modify(SelectionController::AlterationMove, DirectionBackward, DocumentBoundary, true); 699 return true; 700 } 701 702 static bool executeMoveToBeginningOfDocumentAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&) 703 { 704 frame->selection()->modify(SelectionController::AlterationExtend, DirectionBackward, DocumentBoundary, true); 705 return true; 706 } 707 708 static bool executeMoveToBeginningOfLine(Frame* frame, Event*, EditorCommandSource, const String&) 709 { 710 frame->selection()->modify(SelectionController::AlterationMove, DirectionBackward, LineBoundary, true); 711 return true; 712 } 713 714 static bool executeMoveToBeginningOfLineAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&) 715 { 716 frame->selection()->modify(SelectionController::AlterationExtend, DirectionBackward, LineBoundary, true); 717 return true; 718 } 719 720 static bool executeMoveToBeginningOfParagraph(Frame* frame, Event*, EditorCommandSource, const String&) 721 { 722 frame->selection()->modify(SelectionController::AlterationMove, DirectionBackward, ParagraphBoundary, true); 723 return true; 724 } 725 726 static bool executeMoveToBeginningOfParagraphAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&) 727 { 728 frame->selection()->modify(SelectionController::AlterationExtend, DirectionBackward, ParagraphBoundary, true); 729 return true; 730 } 731 732 static bool executeMoveToBeginningOfSentence(Frame* frame, Event*, EditorCommandSource, const String&) 733 { 734 frame->selection()->modify(SelectionController::AlterationMove, DirectionBackward, SentenceBoundary, true); 735 return true; 736 } 737 738 static bool executeMoveToBeginningOfSentenceAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&) 739 { 740 frame->selection()->modify(SelectionController::AlterationExtend, DirectionBackward, SentenceBoundary, true); 741 return true; 742 } 743 744 static bool executeMoveToEndOfDocument(Frame* frame, Event*, EditorCommandSource, const String&) 745 { 746 frame->selection()->modify(SelectionController::AlterationMove, DirectionForward, DocumentBoundary, true); 747 return true; 748 } 749 750 static bool executeMoveToEndOfDocumentAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&) 751 { 752 frame->selection()->modify(SelectionController::AlterationExtend, DirectionForward, DocumentBoundary, true); 753 return true; 754 } 755 756 static bool executeMoveToEndOfSentence(Frame* frame, Event*, EditorCommandSource, const String&) 757 { 758 frame->selection()->modify(SelectionController::AlterationMove, DirectionForward, SentenceBoundary, true); 759 return true; 760 } 761 762 static bool executeMoveToEndOfSentenceAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&) 763 { 764 frame->selection()->modify(SelectionController::AlterationExtend, DirectionForward, SentenceBoundary, true); 765 return true; 766 } 767 768 static bool executeMoveToEndOfLine(Frame* frame, Event*, EditorCommandSource, const String&) 769 { 770 frame->selection()->modify(SelectionController::AlterationMove, DirectionForward, LineBoundary, true); 771 return true; 772 } 773 774 static bool executeMoveToEndOfLineAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&) 775 { 776 frame->selection()->modify(SelectionController::AlterationExtend, DirectionForward, LineBoundary, true); 777 return true; 778 } 779 780 static bool executeMoveToEndOfParagraph(Frame* frame, Event*, EditorCommandSource, const String&) 781 { 782 frame->selection()->modify(SelectionController::AlterationMove, DirectionForward, ParagraphBoundary, true); 783 return true; 784 } 785 786 static bool executeMoveToEndOfParagraphAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&) 787 { 788 frame->selection()->modify(SelectionController::AlterationExtend, DirectionForward, ParagraphBoundary, true); 789 return true; 790 } 791 792 static bool executeMoveParagraphBackwardAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&) 793 { 794 frame->selection()->modify(SelectionController::AlterationExtend, DirectionBackward, ParagraphGranularity, true); 795 return true; 796 } 797 798 static bool executeMoveParagraphForwardAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&) 799 { 800 frame->selection()->modify(SelectionController::AlterationExtend, DirectionForward, ParagraphGranularity, true); 801 return true; 802 } 803 804 static bool executeMoveUp(Frame* frame, Event*, EditorCommandSource, const String&) 805 { 806 return frame->selection()->modify(SelectionController::AlterationMove, DirectionBackward, LineGranularity, true); 807 } 808 809 static bool executeMoveUpAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&) 810 { 811 frame->selection()->modify(SelectionController::AlterationExtend, DirectionBackward, LineGranularity, true); 812 return true; 813 } 814 815 static bool executeMoveWordBackward(Frame* frame, Event*, EditorCommandSource, const String&) 816 { 817 frame->selection()->modify(SelectionController::AlterationMove, DirectionBackward, WordGranularity, true); 818 return true; 819 } 820 821 static bool executeMoveWordBackwardAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&) 822 { 823 frame->selection()->modify(SelectionController::AlterationExtend, DirectionBackward, WordGranularity, true); 824 return true; 825 } 826 827 static bool executeMoveWordForward(Frame* frame, Event*, EditorCommandSource, const String&) 828 { 829 frame->selection()->modify(SelectionController::AlterationMove, DirectionForward, WordGranularity, true); 830 return true; 831 } 832 833 static bool executeMoveWordForwardAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&) 834 { 835 frame->selection()->modify(SelectionController::AlterationExtend, DirectionForward, WordGranularity, true); 836 return true; 837 } 838 839 static bool executeMoveWordLeft(Frame* frame, Event*, EditorCommandSource, const String&) 840 { 841 frame->selection()->modify(SelectionController::AlterationMove, DirectionLeft, WordGranularity, true); 842 return true; 843 } 844 845 static bool executeMoveWordLeftAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&) 846 { 847 frame->selection()->modify(SelectionController::AlterationExtend, DirectionLeft, WordGranularity, true); 848 return true; 849 } 850 851 static bool executeMoveWordRight(Frame* frame, Event*, EditorCommandSource, const String&) 852 { 853 frame->selection()->modify(SelectionController::AlterationMove, DirectionRight, WordGranularity, true); 854 return true; 855 } 856 857 static bool executeMoveWordRightAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&) 858 { 859 frame->selection()->modify(SelectionController::AlterationExtend, DirectionRight, WordGranularity, true); 860 return true; 861 } 862 863 static bool executeMoveToLeftEndOfLine(Frame* frame, Event*, EditorCommandSource, const String&) 864 { 865 frame->selection()->modify(SelectionController::AlterationMove, DirectionLeft, LineBoundary, true); 866 return true; 867 } 868 869 static bool executeMoveToLeftEndOfLineAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&) 870 { 871 frame->selection()->modify(SelectionController::AlterationExtend, DirectionLeft, LineBoundary, true); 872 return true; 873 } 874 875 static bool executeMoveToRightEndOfLine(Frame* frame, Event*, EditorCommandSource, const String&) 876 { 877 frame->selection()->modify(SelectionController::AlterationMove, DirectionRight, LineBoundary, true); 878 return true; 879 } 880 881 static bool executeMoveToRightEndOfLineAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&) 882 { 883 frame->selection()->modify(SelectionController::AlterationExtend, DirectionRight, LineBoundary, true); 884 return true; 885 } 886 887 static bool executeOutdent(Frame* frame, Event*, EditorCommandSource, const String&) 888 { 889 applyCommand(IndentOutdentCommand::create(frame->document(), IndentOutdentCommand::Outdent)); 890 return true; 891 } 892 893 static 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 903 static 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 913 static 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 923 static 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 932 static bool executeRedo(Frame* frame, Event*, EditorCommandSource, const String&) 933 { 934 frame->editor()->redo(); 935 return true; 936 } 937 938 static bool executeRemoveFormat(Frame* frame, Event*, EditorCommandSource, const String&) 939 { 940 frame->editor()->removeFormattingAndStyle(); 941 return true; 942 } 943 944 static bool executeScrollPageBackward(Frame* frame, Event*, EditorCommandSource, const String&) 945 { 946 return frame->eventHandler()->logicalScrollRecursively(ScrollBlockDirectionBackward, ScrollByPage); 947 } 948 949 static bool executeScrollPageForward(Frame* frame, Event*, EditorCommandSource, const String&) 950 { 951 return frame->eventHandler()->logicalScrollRecursively(ScrollBlockDirectionForward, ScrollByPage); 952 } 953 954 static bool executeScrollToBeginningOfDocument(Frame* frame, Event*, EditorCommandSource, const String&) 955 { 956 return frame->eventHandler()->logicalScrollRecursively(ScrollBlockDirectionBackward, ScrollByDocument); 957 } 958 959 static bool executeScrollToEndOfDocument(Frame* frame, Event*, EditorCommandSource, const String&) 960 { 961 return frame->eventHandler()->logicalScrollRecursively(ScrollBlockDirectionForward, ScrollByDocument); 962 } 963 964 static bool executeSelectAll(Frame* frame, Event*, EditorCommandSource, const String&) 965 { 966 frame->selection()->selectAll(); 967 return true; 968 } 969 970 static bool executeSelectLine(Frame* frame, Event*, EditorCommandSource, const String&) 971 { 972 return expandSelectionToGranularity(frame, LineGranularity); 973 } 974 975 static bool executeSelectParagraph(Frame* frame, Event*, EditorCommandSource, const String&) 976 { 977 return expandSelectionToGranularity(frame, ParagraphGranularity); 978 } 979 980 static bool executeSelectSentence(Frame* frame, Event*, EditorCommandSource, const String&) 981 { 982 return expandSelectionToGranularity(frame, SentenceGranularity); 983 } 984 985 static 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 997 static bool executeSelectWord(Frame* frame, Event*, EditorCommandSource, const String&) 998 { 999 return expandSelectionToGranularity(frame, WordGranularity); 1000 } 1001 1002 static bool executeSetMark(Frame* frame, Event*, EditorCommandSource, const String&) 1003 { 1004 frame->editor()->setMark(frame->selection()->selection()); 1005 return true; 1006 } 1007 1008 static 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 1014 static 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 1023 static bool executeSubscript(Frame* frame, Event*, EditorCommandSource source, const String&) 1024 { 1025 return executeToggleStyle(frame, source, EditActionSubscript, CSSPropertyVerticalAlign, "baseline", "sub"); 1026 } 1027 1028 static bool executeSuperscript(Frame* frame, Event*, EditorCommandSource source, const String&) 1029 { 1030 return executeToggleStyle(frame, source, EditActionSuperscript, CSSPropertyVerticalAlign, "baseline", "super"); 1031 } 1032 1033 static 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) 1047 static bool executeTakeFindStringFromSelection(Frame* frame, Event*, EditorCommandSource, const String&) 1048 { 1049 frame->editor()->takeFindStringFromSelection(); 1050 return true; 1051 } 1052 #endif 1053 1054 static bool executeToggleBold(Frame* frame, Event*, EditorCommandSource source, const String&) 1055 { 1056 return executeToggleStyle(frame, source, EditActionChangeAttributes, CSSPropertyFontWeight, "normal", "bold"); 1057 } 1058 1059 static bool executeToggleItalic(Frame* frame, Event*, EditorCommandSource source, const String&) 1060 { 1061 return executeToggleStyle(frame, source, EditActionChangeAttributes, CSSPropertyFontStyle, "normal", "italic"); 1062 } 1063 1064 static bool executeTranspose(Frame* frame, Event*, EditorCommandSource, const String&) 1065 { 1066 frame->editor()->transpose(); 1067 return true; 1068 } 1069 1070 static 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 1076 static bool executeUndo(Frame* frame, Event*, EditorCommandSource, const String&) 1077 { 1078 frame->editor()->undo(); 1079 return true; 1080 } 1081 1082 static bool executeUnlink(Frame* frame, Event*, EditorCommandSource, const String&) 1083 { 1084 applyCommand(UnlinkCommand::create(frame->document())); 1085 return true; 1086 } 1087 1088 static bool executeUnscript(Frame* frame, Event*, EditorCommandSource source, const String&) 1089 { 1090 return executeApplyStyle(frame, source, EditActionUnscript, CSSPropertyVerticalAlign, "baseline"); 1091 } 1092 1093 static bool executeUnselect(Frame* frame, Event*, EditorCommandSource, const String&) 1094 { 1095 frame->selection()->clear(); 1096 return true; 1097 } 1098 1099 static 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 1106 static 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 1115 static bool supported(Frame*) 1116 { 1117 return true; 1118 } 1119 1120 static bool supportedFromMenuOrKeyBinding(Frame*) 1121 { 1122 return false; 1123 } 1124 1125 static 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 1137 static 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 1151 static bool enabled(Frame*, Event*, EditorCommandSource) 1152 { 1153 return true; 1154 } 1155 1156 static 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 1163 static bool caretBrowsingEnabled(Frame* frame) 1164 { 1165 return frame->settings() && frame->settings()->caretBrowsingEnabled(); 1166 } 1167 1168 static EditorCommandSource dummyEditorCommandSource = static_cast<EditorCommandSource>(0); 1169 1170 static 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 1176 static 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 1183 static bool enableCaretInEditableText(Frame* frame, Event* event, EditorCommandSource) 1184 { 1185 const VisibleSelection& selection = frame->editor()->selectionForCommand(event); 1186 return selection.isCaret() && selection.isContentEditable(); 1187 } 1188 1189 static bool enabledCopy(Frame* frame, Event*, EditorCommandSource) 1190 { 1191 return frame->editor()->canDHTMLCopy() || frame->editor()->canCopy(); 1192 } 1193 1194 static bool enabledCut(Frame* frame, Event*, EditorCommandSource) 1195 { 1196 return frame->editor()->canDHTMLCut() || frame->editor()->canCut(); 1197 } 1198 1199 static bool enabledInEditableText(Frame* frame, Event* event, EditorCommandSource) 1200 { 1201 return frame->editor()->selectionForCommand(event).rootEditableElement(); 1202 } 1203 1204 static 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 1220 static 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 1226 static bool enabledInRichlyEditableText(Frame* frame, Event*, EditorCommandSource) 1227 { 1228 return frame->selection()->isCaretOrRange() && frame->selection()->isContentRichlyEditable() && frame->selection()->rootEditableElement(); 1229 } 1230 1231 static bool enabledPaste(Frame* frame, Event*, EditorCommandSource) 1232 { 1233 return frame->editor()->canPaste(); 1234 } 1235 1236 static bool enabledRangeInEditableText(Frame* frame, Event*, EditorCommandSource) 1237 { 1238 return frame->selection()->isRange() && frame->selection()->isContentEditable(); 1239 } 1240 1241 static bool enabledRangeInRichlyEditableText(Frame* frame, Event*, EditorCommandSource) 1242 { 1243 return frame->selection()->isRange() && frame->selection()->isContentRichlyEditable(); 1244 } 1245 1246 static bool enabledRedo(Frame* frame, Event*, EditorCommandSource) 1247 { 1248 return frame->editor()->canRedo(); 1249 } 1250 1251 #if PLATFORM(MAC) 1252 static bool enabledTakeFindStringFromSelection(Frame* frame, Event*, EditorCommandSource) 1253 { 1254 return frame->editor()->canCopyExcludingStandaloneImages(); 1255 } 1256 #endif 1257 1258 static bool enabledUndo(Frame* frame, Event*, EditorCommandSource) 1259 { 1260 return frame->editor()->canUndo(); 1261 } 1262 1263 // State functions 1264 1265 static TriState stateNone(Frame*, Event*) 1266 { 1267 return FalseTriState; 1268 } 1269 1270 static TriState stateBold(Frame* frame, Event*) 1271 { 1272 return stateStyle(frame, CSSPropertyFontWeight, "bold"); 1273 } 1274 1275 static TriState stateItalic(Frame* frame, Event*) 1276 { 1277 return stateStyle(frame, CSSPropertyFontStyle, "italic"); 1278 } 1279 1280 static TriState stateOrderedList(Frame* frame, Event*) 1281 { 1282 return frame->editor()->selectionOrderedListState(); 1283 } 1284 1285 static TriState stateStrikethrough(Frame* frame, Event*) 1286 { 1287 return stateStyle(frame, CSSPropertyWebkitTextDecorationsInEffect, "line-through"); 1288 } 1289 1290 static TriState stateStyleWithCSS(Frame* frame, Event*) 1291 { 1292 return frame->editor()->shouldStyleWithCSS() ? TrueTriState : FalseTriState; 1293 } 1294 1295 static TriState stateSubscript(Frame* frame, Event*) 1296 { 1297 return stateStyle(frame, CSSPropertyVerticalAlign, "sub"); 1298 } 1299 1300 static TriState stateSuperscript(Frame* frame, Event*) 1301 { 1302 return stateStyle(frame, CSSPropertyVerticalAlign, "super"); 1303 } 1304 1305 static TriState stateTextWritingDirectionLeftToRight(Frame* frame, Event*) 1306 { 1307 return stateTextWritingDirection(frame, LeftToRightWritingDirection); 1308 } 1309 1310 static TriState stateTextWritingDirectionNatural(Frame* frame, Event*) 1311 { 1312 return stateTextWritingDirection(frame, NaturalWritingDirection); 1313 } 1314 1315 static TriState stateTextWritingDirectionRightToLeft(Frame* frame, Event*) 1316 { 1317 return stateTextWritingDirection(frame, RightToLeftWritingDirection); 1318 } 1319 1320 static TriState stateUnderline(Frame* frame, Event*) 1321 { 1322 return stateStyle(frame, CSSPropertyWebkitTextDecorationsInEffect, "underline"); 1323 } 1324 1325 static TriState stateUnorderedList(Frame* frame, Event*) 1326 { 1327 return frame->editor()->selectionUnorderedListState(); 1328 } 1329 1330 static TriState stateJustifyCenter(Frame* frame, Event*) 1331 { 1332 return stateStyle(frame, CSSPropertyTextAlign, "center"); 1333 } 1334 1335 static TriState stateJustifyFull(Frame* frame, Event*) 1336 { 1337 return stateStyle(frame, CSSPropertyTextAlign, "justify"); 1338 } 1339 1340 static TriState stateJustifyLeft(Frame* frame, Event*) 1341 { 1342 return stateStyle(frame, CSSPropertyTextAlign, "left"); 1343 } 1344 1345 static TriState stateJustifyRight(Frame* frame, Event*) 1346 { 1347 return stateStyle(frame, CSSPropertyTextAlign, "right"); 1348 } 1349 1350 // Value functions 1351 1352 static String valueNull(Frame*, Event*) 1353 { 1354 return String(); 1355 } 1356 1357 static String valueBackColor(Frame* frame, Event*) 1358 { 1359 return valueStyle(frame, CSSPropertyBackgroundColor); 1360 } 1361 1362 static String valueFontName(Frame* frame, Event*) 1363 { 1364 return valueStyle(frame, CSSPropertyFontFamily); 1365 } 1366 1367 static String valueFontSize(Frame* frame, Event*) 1368 { 1369 return valueStyle(frame, CSSPropertyFontSize); 1370 } 1371 1372 static String valueFontSizeDelta(Frame* frame, Event*) 1373 { 1374 return valueStyle(frame, CSSPropertyWebkitFontSizeDelta); 1375 } 1376 1377 static String valueForeColor(Frame* frame, Event*) 1378 { 1379 return valueStyle(frame, CSSPropertyColor); 1380 } 1381 1382 static 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 1395 struct CommandEntry { 1396 const char* name; 1397 EditorInternalCommand command; 1398 }; 1399 1400 static 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 1598 static const EditorInternalCommand* internalCommand(const String& commandName) 1599 { 1600 static const CommandMap& commandMap = createCommandMap(); 1601 return commandName.isEmpty() ? 0 : commandMap.get(commandName); 1602 } 1603 1604 Editor::Command Editor::command(const String& commandName) 1605 { 1606 return Command(internalCommand(commandName), CommandFromMenuOrKeyBinding, m_frame); 1607 } 1608 1609 Editor::Command Editor::command(const String& commandName, EditorCommandSource source) 1610 { 1611 return Command(internalCommand(commandName), source, m_frame); 1612 } 1613 1614 bool Editor::commandIsSupportedFromMenuOrKeyBinding(const String& commandName) 1615 { 1616 return internalCommand(commandName); 1617 } 1618 1619 Editor::Command::Command() 1620 : m_command(0) 1621 { 1622 } 1623 1624 Editor::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 1636 bool 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 1647 bool Editor::Command::execute(Event* triggeringEvent) const 1648 { 1649 return execute(String(), triggeringEvent); 1650 } 1651 1652 bool 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 1667 bool 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 1674 TriState 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 1681 String 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 1690 bool Editor::Command::isTextInsertion() const 1691 { 1692 return m_command && m_command->isTextInsertion; 1693 } 1694 1695 } // namespace WebCore 1696