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