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