Changeset 28626 in webkit


Ignore:
Timestamp:
Dec 11, 2007 12:26:56 PM (16 years ago)
Author:
Darin Adler
Message:

WebCore:

Reviewed by Geoff.

  • exposed many new commands to the DOM Document executeCommand function by merging the JSEditor and Editor executeCommand implementations
  • replaced the execCommand function with a EditorCommand class
  • replaced the WTF::StrHash<> class template with the WebCore::StringHash class
  • replaced the WTF::CaseInsensitiveHash<> class template with the WebCore::CaseFoldingHash class
  • WebCore.base.exp: Updated.
  • WebCore.pro: Added EditorCommand.cpp, removed JSEditor.cpp.
  • WebCore.vcproj/WebCore.vcproj: Ditto.
  • WebCore.xcodeproj/project.pbxproj: Ditto.
  • WebCoreSources.bkl: Ditto.
  • dom/Document.cpp: (WebCore::Document::Document): Removed code to set up m_jsEditor. (WebCore::Document::~Document): Removed code to delete m_jsEditor. (WebCore::command): Added. Helper function that gets an Editor::Command. (WebCore::Document::executeCommand): Changed to use Editor::Command instead of JSEditor. (WebCore::Document::queryCommandEnabled): Ditto. (WebCore::Document::queryCommandIndeterm): (WebCore::Document::queryCommandState): Ditto. (WebCore::Document::queryCommandSupported): Ditto. (WebCore::Document::queryCommandValue): Ditto.
  • dom/Document.h: Removed JSEditor, jsEditor, m_jsEditor. Changed to use CaseFoldingHash.
  • editing/Editor.cpp: (WebCore::Editor::selectionForCommand): Renamed from selectionForEvent and made into a member function so it is accessible from the new EditorCommand.cpp file. Also changed to get the selection from the passed-in frame instead of from the page, because this should work on the targeted frame unless the event overrides it. (WebCore::Editor::handleKeypress): Updated for selectionForCommand change. (WebCore::Editor::handleInputMethodKeypress): Ditto. (WebCore::imageElementFromImageDocument): Renamed and changed to return a HTMLImageElement instead of a Node*. (WebCore::Editor::canCopy): Updated for name change. (WebCore::Editor::selectionUnorderedListState): Updated for TriState change. (WebCore::Editor::selectionOrderedListState): Ditto. (WebCore::Editor::selectionStartHasStyle): Make type of local more specific. (WebCore::updateState): Moved here from Frame. (WebCore::Editor::selectionHasStyle): Ditto. (WebCore::Editor::Editor): Initialize m_shouldStartNewKillRingSequence. (WebCore::Editor::insertTextWithoutSendingTextEvent): Updated for selectionForCommand change. (WebCore::Editor::copy): Updated for imageElementFromImageDocument change. (WebCore::Editor::toggleBold): Call the ToggleBold command via the command machinery since it's no longer in this file as a local function. (WebCore::Editor::toggleUnderline): Call the ToggleUnderline command. (WebCore::Editor::setBaseWritingDirection): Change type of argument and of local variable. (WebCore::Editor::addToKillRing): Moved here from EditorMac. Not useful without a kill ring, but it's relatively straightforward to implement one. (WebCore::Editor::appendToKillRing): Put default implementation here for platforms other than Mac. We should probably put a simple kill ring implementation here -- doesn't need to be shared with the OS oh platforms other than Mac. (WebCore::Editor::prependToKillRing): Ditto. (WebCore::Editor::yankFromKillRing): Ditto. (WebCore::Editor::startNewKillRingSequence): Ditto. (WebCore::Editor::setKillRingToYankedState): Ditto.
  • editing/Editor.h: Moved the TriState enum here instead of inside the Frame class. Added EditorCommandSource enum. Moved selectionHasStyle here from the Frame class. Added Editor::Command class with five functions for the various things you can do with a command (execute it, check if it can be used, and its state and value). Changed hte parameter of setBaseWritingDirection to be a const String& rather than a String. Got rid of the kill-ring-related operations, but added the kill ring functions themselves. Made selectedRange() public. Made the m_startNewKillRingSequence not Mac-specific and added "should" to its name.
  • editing/EditorCommand.cpp: Copied from WebCore/editing/Editor.cpp. Retained only the editing commands. (WebCore::targetFrame): Moved to the top of the file. (WebCore::executeApplyStyle): Added. Helper function for commands that need to apply styles. (WebCore::executeToggleStyle): Added. Helper function for commands that need to toggle styles based on the style of the start of selection. (WebCore::executeApplyParagraphStyle): Added. Like executeApplyStyle, but for paragraph styles. (WebCore::executeInsertFragment): Added. Helper function for commands that need to insert a DOM fragment. (WebCore::executeInsertNode): Added. Helper function for commands that need to insert a tree rooted in a single DOM node. (WebCore::stateStyle): Added. Helper function for the state of commands that represent style. (WebCore::valueStyle): Added. Helper function for the value of commands that represent style. (WebCore::canScroll): Added. Helper functions for some move and scroll commands that need to determine if the renderer they are in can scroll. (WebCore::unionDOMRanges): Moved here from EditorMac. (WebCore::executeBackColor): (WebCore::executeBackwardDelete): (WebCore::executeCopy): (WebCore::executeCreateLink): (WebCore::executeCut): (WebCore::executeDelete): (WebCore::executeDeleteToMark): (WebCore::executeDeleteWordBackward): (WebCore::executeDeleteWordForward): (WebCore::executeFindString): (WebCore::executeFontName): (WebCore::executeFontSize): (WebCore::executeFontSizeDelta): (WebCore::executeForeColor): (WebCore::executeFormatBlock): (WebCore::executeForwardDelete): (WebCore::executeIndent): (WebCore::executeInsertBacktab): (WebCore::executeInsertHorizontalRule): (WebCore::executeInsertHTML): (WebCore::executeInsertImage): (WebCore::executeInsertLineBreak): (WebCore::executeInsertNewline): (WebCore::executeInsertNewlineInQuotedContent): (WebCore::executeInsertOrderedList): (WebCore::executeInsertParagraph): (WebCore::executeInsertTab): (WebCore::executeInsertText): (WebCore::executeInsertUnorderedList): (WebCore::executeJustifyCenter): (WebCore::executeJustifyFull): (WebCore::executeJustifyLeft): (WebCore::executeJustifyRight): (WebCore::executeMoveBackward): (WebCore::executeMoveBackwardAndModifySelection): (WebCore::executeMoveDown): (WebCore::executeMoveDownAndModifySelection): (WebCore::executeMoveDownByPageAndModifyCaret): (WebCore::executeMoveForward): (WebCore::executeMoveForwardAndModifySelection): (WebCore::executeMoveLeft): (WebCore::executeMoveLeftAndModifySelection): (WebCore::executeMoveRight): (WebCore::executeMoveRightAndModifySelection): (WebCore::executeMoveToBeginningOfDocument): (WebCore::executeMoveToBeginningOfDocumentAndModifySelection): (WebCore::executeMoveToBeginningOfLine): (WebCore::executeMoveToBeginningOfLineAndModifySelection): (WebCore::executeMoveToBeginningOfParagraph): (WebCore::executeMoveToBeginningOfParagraphAndModifySelection): (WebCore::executeMoveToBeginningOfSentence): (WebCore::executeMoveToBeginningOfSentenceAndModifySelection): (WebCore::executeMoveToEndOfDocument): (WebCore::executeMoveToEndOfDocumentAndModifySelection): (WebCore::executeMoveToEndOfSentence): (WebCore::executeMoveToEndOfSentenceAndModifySelection): (WebCore::executeMoveToEndOfLine): (WebCore::executeMoveToEndOfLineAndModifySelection): (WebCore::executeMoveToEndOfParagraph): (WebCore::executeMoveToEndOfParagraphAndModifySelection): (WebCore::executeMoveParagraphBackwardAndModifySelection): (WebCore::executeMoveParagraphForwardAndModifySelection): (WebCore::executeMoveUp): (WebCore::executeMoveUpAndModifySelection): (WebCore::executeMoveUpByPageAndModifyCaret): (WebCore::executeMoveWordBackward): (WebCore::executeMoveWordBackwardAndModifySelection): (WebCore::executeMoveWordForward): (WebCore::executeMoveWordForwardAndModifySelection): (WebCore::executeMoveWordLeft): (WebCore::executeMoveWordLeftAndModifySelection): (WebCore::executeMoveWordRight): (WebCore::executeMoveWordRightAndModifySelection): (WebCore::executeOutdent): (WebCore::executePaste): (WebCore::executePasteAndMatchStyle): (WebCore::executePrint): (WebCore::executeRedo): (WebCore::executeRemoveFormat): (WebCore::executeSelectAll): (WebCore::executeSelectToMark): (WebCore::executeSetMark): (WebCore::executeStrikethrough): (WebCore::executeSubscript): (WebCore::executeSuperscript): (WebCore::executeSwapWithMark): (WebCore::executeToggleBold): (WebCore::executeToggleItalic): (WebCore::executeTranspose): (WebCore::executeUnderline): (WebCore::executeUndo): (WebCore::executeUnlink): (WebCore::executeUnscript): (WebCore::executeUnselect): (WebCore::executeYank): (WebCore::executeYankAndSelect): (WebCore::supported): (WebCore::supportedPaste): (WebCore::enabled): (WebCore::enabledAnySelection): (WebCore::enabledAnySelectionAndMark): (WebCore::enableCaretInEditableText): (WebCore::enabledCopy): (WebCore::enabledCut): (WebCore::enabledInEditableText): (WebCore::enabledInRichlyEditableText): (WebCore::enabledPaste): (WebCore::enabledRangeInEditableText): (WebCore::enabledRangeInRichlyEditableText): (WebCore::enabledRedo): (WebCore::enabledUndo): (WebCore::stateNone): (WebCore::stateBold): (WebCore::stateItalic): (WebCore::stateOrderedList): (WebCore::stateStrikethrough): (WebCore::stateSubscript): (WebCore::stateSuperscript): (WebCore::stateUnderline): (WebCore::stateUnorderedList): (WebCore::valueNull): (WebCore::valueBackColor): (WebCore::valueFontName): (WebCore::valueFontSize): (WebCore::valueFontSizeDelta): (WebCore::valueForeColor): (WebCore::createCommandMap): Added lots of commands, including all the commands from JSEditor. A few commands needed different behavior based on whether they are invoked from the DOM or a keyboard binding. (WebCore::Editor::command): Added. Gets a command object given a name. (WebCore::Editor::Command::Command): Added. (WebCore::Editor::Command::execute): Added. (WebCore::Editor::Command::isSupported): Added. (WebCore::Editor::Command::isEnabled): Added. (WebCore::Editor::Command::state): Added. (WebCore::Editor::Command::value): Added. (WebCore::Editor::execCommand): Changed to call command().execute().
  • editing/JSEditor.cpp: Removed.
  • editing/JSEditor.h: Removed.
  • editing/mac/EditorMac.mm: Changed to provide kill ring primitives intead of kill ring commands, so the kill ring commands can be cross-platform. (WebCore::Editor::appendToKillRing): Added. (WebCore::Editor::prependToKillRing): Added. (WebCore::Editor::yankFromKillRing): Added. (WebCore::Editor::startNewKillRingSequence): Added. (WebCore::Editor::setKillRingToYankedState): Added.
  • page/Frame.cpp: Removed selectionHasStyle, TriState, and updateState.
  • page/Frame.h: Ditto.
  • page/mac/WebCoreFrameBridge.mm: Removed selectionHasStyle.
  • page/mac/WebCoreFrameBridge.h: Ditto.
  • platform/ContextMenu.cpp: (WebCore::ContextMenu::checkOrEnableIfNeeded): Updated for TriState change.
  • platform/text/StringHash.h: (WebCore::StringHash::hash): Merged the StrHash<> template classes into this. (WebCore::StringHash::equal): Ditto. (WebCore::CaseFoldingHash::hash): Merged the CaseInsensitiveHash<> template classes into this. (WebCore::CaseFoldingHash::equal): Ditto.
  • platform/text/StringImpl.cpp: (WebCore::equal): Changed to invoke StringHash. (WebCore::equalIgnoringCase): Changed to invoke CaseFoldingHash.
  • dom/DOMImplementation.cpp: (WebCore::addString): Updated to use StringHash and CaseFoldingHash. (WebCore::isSVG10Feature): Ditto. (WebCore::isSVG11Feature): Ditto.
  • loader/FrameLoader.cpp: (WebCore::localSchemes): Ditto.
  • platform/graphics/FontCache.cpp: (WebCore::computeHash): Ditto.
  • platform/network/HTTPHeaderMap.h: Ditto.
  • platform/text/PlatformString.h: Ditto.
  • platform/text/StringImpl.h: Ditto.
  • rendering/RenderPartObject.cpp: (WebCore::RenderPartObject::updateWidget): Ditto.
  • xml/XMLHttpRequest.cpp: (WebCore::canSetRequestHeader): Ditto.
  • rendering/RenderTreeAsText.cpp: Removed stray include of JSEditor.h.

WebKit/mac:

Reviewed by Geoff.

  • change more editing commands to use WebCore::Editor
  • change to use the new WebCore::Editor::command() function
  • WebView/WebHTMLView.mm: Changed alignCenter, alignJustified, alignLeft, alignRight, cut, copy, deleteToMark, indent, insertNewlineIgnoringFieldEditor, insertTabIgnoringFieldEditor, outdent, selectAll, selectToMark, setMark, subscript, superscript, swapWithMark, underline, unscript, yank, and yankAndSelect to use the "forward to WebCore" macro instead of having hand-written implementations. (kit): Added function to change a TriState to an AppKit-style tri-state value. (-[WebHTMLView coreCommandBySelector:]): Added. No longer converts case of the first character or copies the selector name, since the Editor commands are not case sensitive any more. Returns a command object. (-[WebHTMLView coreCommandByName:]): Added. (-[WebHTMLView executeCoreCommandBySelector:]): Renamed from callWebCoreCommand:, and changed to use the new coreCommandBySelector: method. (-[WebHTMLView executeCoreCommandByName:]): Added. (-[WebHTMLView validateUserInterfaceItemWithoutDelegate:]): Changed all the methods that call through to WebCore to also use the state() and isEnabled() functions on the commands for the menu item state and user interface item enabling. (-[WebHTMLView _handleStyleKeyEquivalent:]): Use ToggleBold and ToggleItalic by name rather than having local methods for them; no need for methods with a single call site. (-[WebHTMLView insertParagraphSeparator:]): Use executeCoreCommandByName: rather than the deprecated execCommand(). (-[WebHTMLView doCommandBySelector:]): Changed to use command().execute() rather than the deprecated execCommand().
  • WebView/WebHTMLViewInternal.h: Removed some unneeded method declarations.

WebKit/win:

  • WebView.cpp: (WebView::handleEditingKeyboardEvent): Update for change to Editor API.
Location:
trunk
Files:
2 deleted
32 edited
1 copied

Legend:

Unmodified
Added
Removed
  • trunk/WebCore/ChangeLog

    r28625 r28626  
     12007-12-11  Darin Adler  <darin@apple.com>
     2
     3        Reviewed by Geoff.
     4
     5        - exposed many new commands to the DOM Document executeCommand function by
     6          merging the JSEditor and Editor executeCommand implementations
     7        - replaced the execCommand function with a EditorCommand class
     8        - replaced the WTF::StrHash<> class template with the WebCore::StringHash class
     9        - replaced the WTF::CaseInsensitiveHash<> class template with the
     10          WebCore::CaseFoldingHash class
     11
     12        * WebCore.base.exp: Updated.
     13        * WebCore.pro: Added EditorCommand.cpp, removed JSEditor.cpp.
     14        * WebCore.vcproj/WebCore.vcproj: Ditto.
     15        * WebCore.xcodeproj/project.pbxproj: Ditto.
     16        * WebCoreSources.bkl: Ditto.
     17
     18        * dom/Document.cpp:
     19        (WebCore::Document::Document): Removed code to set up m_jsEditor.
     20        (WebCore::Document::~Document): Removed code to delete m_jsEditor.
     21        (WebCore::command): Added. Helper function that gets an Editor::Command.
     22        (WebCore::Document::executeCommand): Changed to use Editor::Command instead of
     23        JSEditor.
     24        (WebCore::Document::queryCommandEnabled): Ditto.
     25        (WebCore::Document::queryCommandIndeterm):
     26        (WebCore::Document::queryCommandState): Ditto.
     27        (WebCore::Document::queryCommandSupported): Ditto.
     28        (WebCore::Document::queryCommandValue): Ditto.
     29
     30        * dom/Document.h: Removed JSEditor, jsEditor, m_jsEditor. Changed to
     31        use CaseFoldingHash.
     32
     33        * editing/Editor.cpp:
     34        (WebCore::Editor::selectionForCommand): Renamed from selectionForEvent and
     35        made into a member function so it is accessible from the new EditorCommand.cpp file.
     36        Also changed to get the selection from the passed-in frame instead of from the
     37        page, because this should work on the targeted frame unless the event overrides it.
     38        (WebCore::Editor::handleKeypress): Updated for selectionForCommand change.
     39        (WebCore::Editor::handleInputMethodKeypress): Ditto.
     40        (WebCore::imageElementFromImageDocument): Renamed and changed to return
     41        a HTMLImageElement instead of a Node*.
     42        (WebCore::Editor::canCopy): Updated for name change.
     43        (WebCore::Editor::selectionUnorderedListState): Updated for TriState change.
     44        (WebCore::Editor::selectionOrderedListState): Ditto.
     45        (WebCore::Editor::selectionStartHasStyle): Make type of local more specific.
     46        (WebCore::updateState): Moved here from Frame.
     47        (WebCore::Editor::selectionHasStyle): Ditto.
     48        (WebCore::Editor::Editor): Initialize m_shouldStartNewKillRingSequence.
     49        (WebCore::Editor::insertTextWithoutSendingTextEvent): Updated for
     50        selectionForCommand change.
     51        (WebCore::Editor::copy): Updated for imageElementFromImageDocument change.
     52        (WebCore::Editor::toggleBold): Call the ToggleBold command via the command
     53        machinery since it's no longer in this file as a local function.
     54        (WebCore::Editor::toggleUnderline): Call the ToggleUnderline command.
     55        (WebCore::Editor::setBaseWritingDirection): Change type of argument and of
     56        local variable.
     57        (WebCore::Editor::addToKillRing): Moved here from EditorMac. Not useful
     58        without a kill ring, but it's relatively straightforward to implement one.
     59        (WebCore::Editor::appendToKillRing): Put default implementation here for
     60        platforms other than Mac. We should probably put a simple kill ring
     61        implementation here -- doesn't need to be shared with the OS oh platforms
     62        other than Mac.
     63        (WebCore::Editor::prependToKillRing): Ditto.
     64        (WebCore::Editor::yankFromKillRing): Ditto.
     65        (WebCore::Editor::startNewKillRingSequence): Ditto.
     66        (WebCore::Editor::setKillRingToYankedState): Ditto.
     67
     68        * editing/Editor.h: Moved the TriState enum here instead of inside the
     69        Frame class. Added EditorCommandSource enum. Moved selectionHasStyle
     70        here from the Frame class. Added Editor::Command class with five functions
     71        for the various things you can do with a command (execute it, check if it
     72        can be used, and its state and value). Changed hte parameter of
     73        setBaseWritingDirection to be a const String& rather than a String.
     74        Got rid of the kill-ring-related operations, but added the kill ring
     75        functions themselves. Made selectedRange() public. Made the
     76        m_startNewKillRingSequence not Mac-specific and added "should" to its
     77        name.
     78
     79        * editing/EditorCommand.cpp: Copied from WebCore/editing/Editor.cpp.
     80        Retained only the editing commands.
     81        (WebCore::targetFrame): Moved to the top of the file.
     82        (WebCore::executeApplyStyle): Added. Helper function for commands
     83        that need to apply styles.
     84        (WebCore::executeToggleStyle): Added. Helper function for commands
     85        that need to toggle styles based on the style of the start of selection.
     86        (WebCore::executeApplyParagraphStyle): Added. Like executeApplyStyle, but
     87        for paragraph styles.
     88        (WebCore::executeInsertFragment): Added. Helper function for commands
     89        that need to insert a DOM fragment.
     90        (WebCore::executeInsertNode): Added. Helper function for commands that
     91        need to insert a tree rooted in a single DOM node.
     92        (WebCore::stateStyle): Added. Helper function for the state of commands
     93        that represent style.
     94        (WebCore::valueStyle): Added. Helper function for the value of commands
     95        that represent style.
     96        (WebCore::canScroll): Added. Helper functions for some move and scroll
     97        commands that need to determine if the renderer they are in can scroll.
     98        (WebCore::unionDOMRanges): Moved here from EditorMac.
     99        (WebCore::executeBackColor):
     100        (WebCore::executeBackwardDelete):
     101        (WebCore::executeCopy):
     102        (WebCore::executeCreateLink):
     103        (WebCore::executeCut):
     104        (WebCore::executeDelete):
     105        (WebCore::executeDeleteToMark):
     106        (WebCore::executeDeleteWordBackward):
     107        (WebCore::executeDeleteWordForward):
     108        (WebCore::executeFindString):
     109        (WebCore::executeFontName):
     110        (WebCore::executeFontSize):
     111        (WebCore::executeFontSizeDelta):
     112        (WebCore::executeForeColor):
     113        (WebCore::executeFormatBlock):
     114        (WebCore::executeForwardDelete):
     115        (WebCore::executeIndent):
     116        (WebCore::executeInsertBacktab):
     117        (WebCore::executeInsertHorizontalRule):
     118        (WebCore::executeInsertHTML):
     119        (WebCore::executeInsertImage):
     120        (WebCore::executeInsertLineBreak):
     121        (WebCore::executeInsertNewline):
     122        (WebCore::executeInsertNewlineInQuotedContent):
     123        (WebCore::executeInsertOrderedList):
     124        (WebCore::executeInsertParagraph):
     125        (WebCore::executeInsertTab):
     126        (WebCore::executeInsertText):
     127        (WebCore::executeInsertUnorderedList):
     128        (WebCore::executeJustifyCenter):
     129        (WebCore::executeJustifyFull):
     130        (WebCore::executeJustifyLeft):
     131        (WebCore::executeJustifyRight):
     132        (WebCore::executeMoveBackward):
     133        (WebCore::executeMoveBackwardAndModifySelection):
     134        (WebCore::executeMoveDown):
     135        (WebCore::executeMoveDownAndModifySelection):
     136        (WebCore::executeMoveDownByPageAndModifyCaret):
     137        (WebCore::executeMoveForward):
     138        (WebCore::executeMoveForwardAndModifySelection):
     139        (WebCore::executeMoveLeft):
     140        (WebCore::executeMoveLeftAndModifySelection):
     141        (WebCore::executeMoveRight):
     142        (WebCore::executeMoveRightAndModifySelection):
     143        (WebCore::executeMoveToBeginningOfDocument):
     144        (WebCore::executeMoveToBeginningOfDocumentAndModifySelection):
     145        (WebCore::executeMoveToBeginningOfLine):
     146        (WebCore::executeMoveToBeginningOfLineAndModifySelection):
     147        (WebCore::executeMoveToBeginningOfParagraph):
     148        (WebCore::executeMoveToBeginningOfParagraphAndModifySelection):
     149        (WebCore::executeMoveToBeginningOfSentence):
     150        (WebCore::executeMoveToBeginningOfSentenceAndModifySelection):
     151        (WebCore::executeMoveToEndOfDocument):
     152        (WebCore::executeMoveToEndOfDocumentAndModifySelection):
     153        (WebCore::executeMoveToEndOfSentence):
     154        (WebCore::executeMoveToEndOfSentenceAndModifySelection):
     155        (WebCore::executeMoveToEndOfLine):
     156        (WebCore::executeMoveToEndOfLineAndModifySelection):
     157        (WebCore::executeMoveToEndOfParagraph):
     158        (WebCore::executeMoveToEndOfParagraphAndModifySelection):
     159        (WebCore::executeMoveParagraphBackwardAndModifySelection):
     160        (WebCore::executeMoveParagraphForwardAndModifySelection):
     161        (WebCore::executeMoveUp):
     162        (WebCore::executeMoveUpAndModifySelection):
     163        (WebCore::executeMoveUpByPageAndModifyCaret):
     164        (WebCore::executeMoveWordBackward):
     165        (WebCore::executeMoveWordBackwardAndModifySelection):
     166        (WebCore::executeMoveWordForward):
     167        (WebCore::executeMoveWordForwardAndModifySelection):
     168        (WebCore::executeMoveWordLeft):
     169        (WebCore::executeMoveWordLeftAndModifySelection):
     170        (WebCore::executeMoveWordRight):
     171        (WebCore::executeMoveWordRightAndModifySelection):
     172        (WebCore::executeOutdent):
     173        (WebCore::executePaste):
     174        (WebCore::executePasteAndMatchStyle):
     175        (WebCore::executePrint):
     176        (WebCore::executeRedo):
     177        (WebCore::executeRemoveFormat):
     178        (WebCore::executeSelectAll):
     179        (WebCore::executeSelectToMark):
     180        (WebCore::executeSetMark):
     181        (WebCore::executeStrikethrough):
     182        (WebCore::executeSubscript):
     183        (WebCore::executeSuperscript):
     184        (WebCore::executeSwapWithMark):
     185        (WebCore::executeToggleBold):
     186        (WebCore::executeToggleItalic):
     187        (WebCore::executeTranspose):
     188        (WebCore::executeUnderline):
     189        (WebCore::executeUndo):
     190        (WebCore::executeUnlink):
     191        (WebCore::executeUnscript):
     192        (WebCore::executeUnselect):
     193        (WebCore::executeYank):
     194        (WebCore::executeYankAndSelect):
     195        (WebCore::supported):
     196        (WebCore::supportedPaste):
     197        (WebCore::enabled):
     198        (WebCore::enabledAnySelection):
     199        (WebCore::enabledAnySelectionAndMark):
     200        (WebCore::enableCaretInEditableText):
     201        (WebCore::enabledCopy):
     202        (WebCore::enabledCut):
     203        (WebCore::enabledInEditableText):
     204        (WebCore::enabledInRichlyEditableText):
     205        (WebCore::enabledPaste):
     206        (WebCore::enabledRangeInEditableText):
     207        (WebCore::enabledRangeInRichlyEditableText):
     208        (WebCore::enabledRedo):
     209        (WebCore::enabledUndo):
     210        (WebCore::stateNone):
     211        (WebCore::stateBold):
     212        (WebCore::stateItalic):
     213        (WebCore::stateOrderedList):
     214        (WebCore::stateStrikethrough):
     215        (WebCore::stateSubscript):
     216        (WebCore::stateSuperscript):
     217        (WebCore::stateUnderline):
     218        (WebCore::stateUnorderedList):
     219        (WebCore::valueNull):
     220        (WebCore::valueBackColor):
     221        (WebCore::valueFontName):
     222        (WebCore::valueFontSize):
     223        (WebCore::valueFontSizeDelta):
     224        (WebCore::valueForeColor):
     225        (WebCore::createCommandMap): Added lots of commands, including all the commands
     226        from JSEditor. A few commands needed different behavior based on whether they are
     227        invoked from the DOM or a keyboard binding.
     228        (WebCore::Editor::command): Added. Gets a command object given a name.
     229        (WebCore::Editor::Command::Command): Added.
     230        (WebCore::Editor::Command::execute): Added.
     231        (WebCore::Editor::Command::isSupported): Added.
     232        (WebCore::Editor::Command::isEnabled): Added.
     233        (WebCore::Editor::Command::state): Added.
     234        (WebCore::Editor::Command::value): Added.
     235        (WebCore::Editor::execCommand): Changed to call command().execute().
     236
     237        * editing/JSEditor.cpp: Removed.
     238        * editing/JSEditor.h: Removed.
     239
     240        * editing/mac/EditorMac.mm: Changed to provide kill ring primitives intead of
     241        kill ring commands, so the kill ring commands can be cross-platform.
     242        (WebCore::Editor::appendToKillRing): Added.
     243        (WebCore::Editor::prependToKillRing): Added.
     244        (WebCore::Editor::yankFromKillRing): Added.
     245        (WebCore::Editor::startNewKillRingSequence): Added.
     246        (WebCore::Editor::setKillRingToYankedState): Added.
     247
     248        * page/Frame.cpp: Removed selectionHasStyle, TriState, and updateState.
     249        * page/Frame.h: Ditto.
     250
     251        * page/mac/WebCoreFrameBridge.mm: Removed selectionHasStyle.
     252        * page/mac/WebCoreFrameBridge.h: Ditto.
     253
     254        * platform/ContextMenu.cpp:
     255        (WebCore::ContextMenu::checkOrEnableIfNeeded): Updated for TriState change.
     256
     257        * platform/text/StringHash.h:
     258        (WebCore::StringHash::hash): Merged the StrHash<> template classes into this.
     259        (WebCore::StringHash::equal): Ditto.
     260        (WebCore::CaseFoldingHash::hash): Merged the CaseInsensitiveHash<> template
     261        classes into this.
     262        (WebCore::CaseFoldingHash::equal): Ditto.
     263
     264        * platform/text/StringImpl.cpp:
     265        (WebCore::equal): Changed to invoke StringHash.
     266        (WebCore::equalIgnoringCase): Changed to invoke CaseFoldingHash.
     267
     268        * dom/DOMImplementation.cpp:
     269        (WebCore::addString): Updated to use StringHash and CaseFoldingHash.
     270        (WebCore::isSVG10Feature): Ditto.
     271        (WebCore::isSVG11Feature): Ditto.
     272        * loader/FrameLoader.cpp:
     273        (WebCore::localSchemes): Ditto.
     274        * platform/graphics/FontCache.cpp:
     275        (WebCore::computeHash): Ditto.
     276        * platform/network/HTTPHeaderMap.h: Ditto.
     277        * platform/text/PlatformString.h: Ditto.
     278        * platform/text/StringImpl.h: Ditto.
     279        * rendering/RenderPartObject.cpp:
     280        (WebCore::RenderPartObject::updateWidget): Ditto.
     281        * xml/XMLHttpRequest.cpp:
     282        (WebCore::canSetRequestHeader): Ditto.
     283
     284        * rendering/RenderTreeAsText.cpp: Removed stray include of JSEditor.h.
     285
    12862007-12-11  Darin Adler  <darin@apple.com>
    2287
  • trunk/WebCore/WebCore.base.exp

    r28620 r28626  
    330330__ZN7WebCore18PlatformMouseEventC1EP7NSEvent
    331331__ZN7WebCore18SecurityOriginDataC1ERKNS_6StringES3_t
     332__ZN7WebCore19CSSStyleDeclaration11setPropertyERKNS_6StringES3_Ri
    332333__ZN7WebCore19InspectorController11showConsoleEv
    333334__ZN7WebCore19InspectorController12attachWindowEv
     
    355356__ZN7WebCore20ResourceResponseBase24setExpectedContentLengthEx
    356357__ZN7WebCore21ContextMenuController16clearContextMenuEv
     358__ZN7WebCore21PlatformKeyboardEvent24disambiguateKeyDownEventENS0_4TypeEb
    357359__ZN7WebCore21PlatformKeyboardEventC1EP7NSEvent
    358 __ZN7WebCore21PlatformKeyboardEvent24disambiguateKeyDownEventENS0_4TypeEb
    359360__ZN7WebCore21WindowsLatin1EncodingEv
    360361__ZN7WebCore21findEventWithKeyStateEPNS_5EventE
     
    362363__ZN7WebCore21reportThreadViolationEPKc
    363364__ZN7WebCore24notifyHistoryItemChangedE
     365__ZN7WebCore26CSSMutableStyleDeclarationC1Ev
    364366__ZN7WebCore26NetscapePlugInStreamLoader6createEPNS_5FrameEP11objc_object
    365367__ZN7WebCore26usesTestModeFocusRingColorEv
     
    415417__ZN7WebCore6Editor10applyStyleEPNS_19CSSStyleDeclarationENS_10EditActionE
    416418__ZN7WebCore6Editor10insertTextERKNS_6StringEPNS_5EventE
    417 __ZN7WebCore6Editor11canDHTMLCutEv
    418 __ZN7WebCore6Editor22isTextInsertionCommandERKNS_12AtomicStringE
    419 __ZN7WebCore6Editor11execCommandERKNS_12AtomicStringEPNS_5EventE
    420 __ZN7WebCore6Editor11tryDHTMLCutEv
    421 __ZN7WebCore6Editor12canDHTMLCopyEv
    422 __ZN7WebCore6Editor12deleteToMarkEv
    423 __ZN7WebCore6Editor12selectToMarkEv
    424 __ZN7WebCore6Editor12swapWithMarkEv
    425 __ZN7WebCore6Editor12tryDHTMLCopyEv
    426419__ZN7WebCore6Editor13canDHTMLPasteEv
    427420__ZN7WebCore6Editor13performDeleteEv
    428421__ZN7WebCore6Editor13rangeForPointERKNS_8IntPointE
    429422__ZN7WebCore6Editor13tryDHTMLPasteEv
    430 __ZN7WebCore6Editor13yankAndSelectEv
    431423__ZN7WebCore6Editor14setCompositionERKNS_6StringERKN3WTF6VectorINS_20CompositionUnderlineELm0EEEjj
    432424__ZN7WebCore6Editor16pasteAsPlainTextEv
     
    453445__ZN7WebCore6Editor44confirmCompositionWithoutDisturbingSelectionEv
    454446__ZN7WebCore6Editor4copyEv
    455 __ZN7WebCore6Editor4yankEv
    456447__ZN7WebCore6Editor5pasteEv
    457448__ZN7WebCore6Editor6indentEv
     449__ZN7WebCore6Editor7CommandC1Ev
     450__ZN7WebCore6Editor7commandERKNS_6StringE
     451__ZN7WebCore6Editor7commandERKNS_6StringENS_19EditorCommandSourceE
    458452__ZN7WebCore6Editor7copyURLERKNS_4KURLERKNS_6StringE
    459453__ZN7WebCore6Editor7outdentEv
    460 __ZN7WebCore6Editor7setMarkEv
    461454__ZN7WebCore6String6appendERKS0_
    462455__ZN7WebCore6StringC1EP8NSString
    463456__ZN7WebCore6StringC1EPKc
     457__ZN7WebCore6StringC1EPKcj
    464458__ZN7WebCore6StringC1ERKNS_16DeprecatedStringE
    465459__ZN7WebCore6Widget7setViewEP6NSView
     
    678672__ZNK7WebCore5Range9startNodeEv
    679673__ZNK7WebCore6Editor13canEditRichlyEv
     674__ZNK7WebCore6Editor17selectionHasStyleEPNS_19CSSStyleDeclarationE
    680675__ZNK7WebCore6Editor17shouldDeleteRangeEPNS_5RangeE
    681676__ZNK7WebCore6Editor22selectionStartHasStyleEPNS_19CSSStyleDeclarationE
    682677__ZNK7WebCore6Editor23getCompositionSelectionERjS1_
    683678__ZNK7WebCore6Editor6canCutEv
     679__ZNK7WebCore6Editor7Command15isTextInsertionEv
     680__ZNK7WebCore6Editor7Command5stateEPNS_5EventE
     681__ZNK7WebCore6Editor7Command7executeEPNS_5EventE
     682__ZNK7WebCore6Editor7Command7executeERKNS_6StringEPNS_5EventE
     683__ZNK7WebCore6Editor7Command9isEnabledEPNS_5EventE
    684684__ZNK7WebCore6Editor7canCopyEv
    685685__ZNK7WebCore6Editor7canEditEv
  • trunk/WebCore/WebCore.pro

    r28592 r28626  
    528528    editing/EditCommand.cpp \
    529529    editing/Editor.cpp \
     530    editing/EditorCommand.cpp \
    530531    editing/FormatBlockCommand.cpp \
    531532    editing/htmlediting.cpp \
     
    539540    editing/InsertTextCommand.cpp \
    540541    editing/JoinTextNodesCommand.cpp \
    541     editing/JSEditor.cpp \
    542542    editing/markup.cpp \
    543543    editing/MergeIdenticalElementsCommand.cpp \
  • trunk/WebCore/WebCore.vcproj/WebCore.vcproj

    r28592 r28626  
    63106310                        </File>
    63116311                        <File
     6312                                RelativePath="..\editing\EditorCommand.cpp"
     6313                                >
     6314                        </File>
     6315                        <File
    63126316                                RelativePath="..\editing\EditorDeleteAction.h"
    63136317                                >
     
    64036407                        <File
    64046408                                RelativePath="..\editing\JoinTextNodesCommand.h"
    6405                                 >
    6406                         </File>
    6407                         <File
    6408                                 RelativePath="..\editing\JSEditor.cpp"
    6409                                 >
    6410                         </File>
    6411                         <File
    6412                                 RelativePath="..\editing\JSEditor.h"
    64136409                                >
    64146410                        </File>
  • trunk/WebCore/WebCore.xcodeproj/project.pbxproj

    r28592 r28626  
    14691469                93309DF3099E64920056E581 /* JoinTextNodesCommand.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 93309DA4099E64910056E581 /* JoinTextNodesCommand.cpp */; };
    14701470                93309DF4099E64920056E581 /* JoinTextNodesCommand.h in Headers */ = {isa = PBXBuildFile; fileRef = 93309DA5099E64910056E581 /* JoinTextNodesCommand.h */; };
    1471                 93309DF5099E64920056E581 /* JSEditor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 93309DA6099E64910056E581 /* JSEditor.cpp */; };
    1472                 93309DF6099E64920056E581 /* JSEditor.h in Headers */ = {isa = PBXBuildFile; fileRef = 93309DA7099E64910056E581 /* JSEditor.h */; };
    14731471                93309DF7099E64920056E581 /* markup.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 93309DA8099E64910056E581 /* markup.cpp */; };
    14741472                93309DF8099E64920056E581 /* markup.h in Headers */ = {isa = PBXBuildFile; fileRef = 93309DA9099E64910056E581 /* markup.h */; };
     
    15621560                93A1EAA00A5634C9006960A0 /* ImageDocumentMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = 93A1EA9F0A5634C9006960A0 /* ImageDocumentMac.mm */; };
    15631561                93A1EAA80A563508006960A0 /* ImageDocumentMac.h in Headers */ = {isa = PBXBuildFile; fileRef = 93A1EAA70A563508006960A0 /* ImageDocumentMac.h */; };
     1562                93A38B4B0D0E5808006872C2 /* EditorCommand.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 93A38B4A0D0E5808006872C2 /* EditorCommand.cpp */; };
    15641563                93B6A0E60B0BCA5C00F5027A /* ContextMenu.h in Headers */ = {isa = PBXBuildFile; fileRef = 93B6A0E50B0BCA5C00F5027A /* ContextMenu.h */; settings = {ATTRIBUTES = (Private, ); }; };
    15651564                93B6A0E80B0BCA6700F5027A /* ContextMenu.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 93B6A0E70B0BCA6700F5027A /* ContextMenu.cpp */; };
     
    57625761                93309DA4099E64910056E581 /* JoinTextNodesCommand.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JoinTextNodesCommand.cpp; sourceTree = "<group>"; };
    57635762                93309DA5099E64910056E581 /* JoinTextNodesCommand.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JoinTextNodesCommand.h; sourceTree = "<group>"; };
    5764                 93309DA6099E64910056E581 /* JSEditor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSEditor.cpp; sourceTree = "<group>"; };
    5765                 93309DA7099E64910056E581 /* JSEditor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSEditor.h; sourceTree = "<group>"; };
    57665763                93309DA8099E64910056E581 /* markup.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = markup.cpp; sourceTree = "<group>"; };
    57675764                93309DA9099E64910056E581 /* markup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = markup.h; sourceTree = "<group>"; };
     
    58605857                93A1EA9F0A5634C9006960A0 /* ImageDocumentMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ImageDocumentMac.mm; sourceTree = "<group>"; };
    58615858                93A1EAA70A563508006960A0 /* ImageDocumentMac.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ImageDocumentMac.h; sourceTree = "<group>"; };
     5859                93A38B4A0D0E5808006872C2 /* EditorCommand.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = EditorCommand.cpp; sourceTree = "<group>"; };
    58625860                93B6A0E50B0BCA5C00F5027A /* ContextMenu.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = ContextMenu.h; sourceTree = "<group>"; };
    58635861                93B6A0E70B0BCA6700F5027A /* ContextMenu.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = ContextMenu.cpp; sourceTree = "<group>"; };
     
    96129610                                4B3043CA0AE0373B00A82647 /* Editor.cpp */,
    96139611                                4B3043CB0AE0373B00A82647 /* Editor.h */,
     9612                                93A38B4A0D0E5808006872C2 /* EditorCommand.cpp */,
    96149613                                4BAE95B00B2FA9CE00AED8A0 /* EditorDeleteAction.h */,
    96159614                                93FDAFC90B11307400E2746F /* EditorInsertAction.h */,
     
    96369635                                93309DA4099E64910056E581 /* JoinTextNodesCommand.cpp */,
    96379636                                93309DA5099E64910056E581 /* JoinTextNodesCommand.h */,
    9638                                 93309DA6099E64910056E581 /* JSEditor.cpp */,
    9639                                 93309DA7099E64910056E581 /* JSEditor.h */,
    96409637                                93309DA8099E64910056E581 /* markup.cpp */,
    96419638                                93309DA9099E64910056E581 /* markup.h */,
     
    1332613323                                1A494EDF0A123F4C00FDAFC1 /* JSDocumentFragment.h in Headers */,
    1332713324                                65DF31F609D1CC60000BE325 /* JSDocumentType.h in Headers */,
    13328                                 93309DF6099E64920056E581 /* JSEditor.h in Headers */,
    1332913325                                65DF31FA09D1CC60000BE325 /* JSElement.h in Headers */,
    1333013326                                65DF323009D1DDBC000BE325 /* JSEntity.h in Headers */,
     
    1502715023                                1A494EDE0A123F4C00FDAFC1 /* JSDocumentFragment.cpp in Sources */,
    1502815024                                65DF31F509D1CC60000BE325 /* JSDocumentType.cpp in Sources */,
    15029                                 93309DF5099E64920056E581 /* JSEditor.cpp in Sources */,
    1503015025                                65DF31F909D1CC60000BE325 /* JSElement.cpp in Sources */,
    1503115026                                BC2ED5550C6B9BD300920BFF /* JSElementCustom.cpp in Sources */,
     
    1579715792                                93309DF7099E64920056E581 /* markup.cpp in Sources */,
    1579815793                                93309E1D099E64920056E581 /* visible_units.cpp in Sources */,
     15794                                93A38B4B0D0E5808006872C2 /* EditorCommand.cpp in Sources */,
    1579915795                        );
    1580015796                        runOnlyForDeploymentPostprocessing = 0;
  • trunk/WebCore/WebCoreSources.bkl

    r28592 r28626  
    351351        editing/EditCommand.cpp
    352352        editing/Editor.cpp
     353        editing/EditorCommand.cpp
    353354        editing/FormatBlockCommand.cpp
    354355        editing/HTMLInterchange.cpp
     
    360361        editing/InsertParagraphSeparatorCommand.cpp
    361362        editing/InsertTextCommand.cpp
    362         editing/JSEditor.cpp
    363363        editing/JoinTextNodesCommand.cpp
    364364        editing/MergeIdenticalElementsCommand.cpp
  • trunk/WebCore/dom/DOMImplementation.cpp

    r25754 r28626  
    6666#if ENABLE(SVG)
    6767
    68 static void addString(HashSet<StringImpl*, CaseInsensitiveHash<StringImpl*> >& set, const
     68static void addString(HashSet<StringImpl*, CaseFoldingHash>& set, const
    6969char* string)
    7070{
     
    7777{
    7878    static bool initialized = false;
    79     static HashSet<StringImpl*, CaseInsensitiveHash<StringImpl*> > svgFeatures;
     79    static HashSet<StringImpl*, CaseFoldingHash> svgFeatures;
    8080    if (!initialized) {
    8181        // TODO: features need to be uncommented when we implement them
     
    100100{
    101101    static bool initialized = false;
    102     static HashSet<StringImpl*, CaseInsensitiveHash<StringImpl*> > svgFeatures;
     102    static HashSet<StringImpl*, CaseFoldingHash> svgFeatures;
    103103    if (!initialized) {
    104104        // TODO: features need to be uncommented when we implement them
  • trunk/WebCore/dom/Document.cpp

    r28620 r28626  
    6969#include "HitTestRequest.h"
    7070#include "HitTestResult.h"
    71 #include "JSEditor.h"
    7271#include "KeyboardEvent.h"
    7372#include "Logging.h"
     
    339338    m_overMinimumLayoutThreshold = false;
    340339   
    341     m_jsEditor = 0;
    342 
    343340    initSecurityOrigin();
    344341
     
    431428    }
    432429    m_decoder = 0;
    433    
    434     if (m_jsEditor) {
    435         delete m_jsEditor;
    436         m_jsEditor = 0;
    437     }
    438430   
    439431    unsigned count = sizeof(m_nameCollectionInfo) / sizeof(m_nameCollectionInfo[0]);
     
    28582850// Support for Javascript execCommand, and related methods
    28592851
    2860 JSEditor *Document::jsEditor()
    2861 {
    2862     if (!m_jsEditor)
    2863         m_jsEditor = new JSEditor(this);
    2864     return m_jsEditor;
    2865 }
    2866 
    2867 bool Document::execCommand(const String &command, bool userInterface, const String &value)
    2868 {
    2869     return jsEditor()->execCommand(command, userInterface, value);
    2870 }
    2871 
    2872 bool Document::queryCommandEnabled(const String &command)
    2873 {
    2874     return jsEditor()->queryCommandEnabled(command);
    2875 }
    2876 
    2877 bool Document::queryCommandIndeterm(const String &command)
    2878 {
    2879     return jsEditor()->queryCommandIndeterm(command);
    2880 }
    2881 
    2882 bool Document::queryCommandState(const String &command)
    2883 {
    2884     return jsEditor()->queryCommandState(command);
    2885 }
    2886 
    2887 bool Document::queryCommandSupported(const String &command)
    2888 {
    2889     return jsEditor()->queryCommandSupported(command);
    2890 }
    2891 
    2892 String Document::queryCommandValue(const String &command)
    2893 {
    2894     return jsEditor()->queryCommandValue(command);
    2895 }
    2896 
    2897 static IntRect placeholderRectForMarker(void)
    2898 {
    2899     return IntRect(-1,-1,-1,-1);
     2852static Editor::Command command(Document* document, const String& commandName, bool userInterface = false)
     2853{
     2854    Frame* frame = document->frame();
     2855    if (!frame || frame->document() != document)
     2856        return Editor::Command();
     2857    return frame->editor()->command(commandName,
     2858        userInterface ? CommandFromDOMWithUserInterface : CommandFromDOM);
     2859}
     2860
     2861bool Document::execCommand(const String& commandName, bool userInterface, const String& value)
     2862{
     2863    return command(this, commandName, userInterface).execute(value);
     2864}
     2865
     2866bool Document::queryCommandEnabled(const String& commandName)
     2867{
     2868    return command(this, commandName).isEnabled();
     2869}
     2870
     2871bool Document::queryCommandIndeterm(const String& commandName)
     2872{
     2873    return command(this, commandName).state() == MixedTriState;
     2874}
     2875
     2876bool Document::queryCommandState(const String& commandName)
     2877{
     2878    return command(this, commandName).state() != FalseTriState;
     2879}
     2880
     2881bool Document::queryCommandSupported(const String& commandName)
     2882{
     2883    return command(this, commandName).isSupported();
     2884}
     2885
     2886String Document::queryCommandValue(const String& commandName)
     2887{
     2888    return command(this, commandName).value();
     2889}
     2890
     2891static IntRect placeholderRectForMarker()
     2892{
     2893    return IntRect(-1, -1, -1, -1);
    29002894}
    29012895
  • trunk/WebCore/dom/Document.h

    r28620 r28626  
    7171    class HTMLMapElement;
    7272    class IntPoint;
    73     class JSEditor;
    7473    class MouseEventWithHitTestResults;
    7574    class NameNodeList;
     
    869868    void updateFocusAppearanceTimerFired(Timer<Document>*);
    870869
    871     JSEditor* jsEditor();
    872     JSEditor* m_jsEditor;
    873 
    874870    mutable String m_domain;
    875871
     
    887883    mutable HashCountedSet<AtomicStringImpl*> m_duplicateIds;
    888884   
    889     mutable HashMap<StringImpl*, Element*, CaseInsensitiveHash<StringImpl*> > m_elementsByAccessKey;
     885    mutable HashMap<StringImpl*, Element*, CaseFoldingHash> m_elementsByAccessKey;
    890886   
    891887    InheritedBool m_designMode;
  • trunk/WebCore/editing/Editor.cpp

    r28620 r28626  
    3333#include "CSSProperty.h"
    3434#include "CSSPropertyNames.h"
    35 #include "CharacterData.h"
    36 #include "Clipboard.h"
    3735#include "ClipboardEvent.h"
    3836#include "DeleteButtonController.h"
    3937#include "DeleteSelectionCommand.h"
    4038#include "DocLoader.h"
    41 #include "Document.h"
    4239#include "DocumentFragment.h"
    43 #include "EditCommand.h"
    44 #include "Editor.h"
    4540#include "EditorClient.h"
    46 #include "Event.h"
    4741#include "EventHandler.h"
    4842#include "EventNames.h"
    4943#include "FocusController.h"
    5044#include "FrameView.h"
    51 #include "HTMLElement.h"
    5245#include "HTMLInputElement.h"
    53 #include "HTMLNames.h"
    5446#include "HTMLTextAreaElement.h"
    5547#include "HitTestResult.h"
     
    5749#include "InsertListCommand.h"
    5850#include "KeyboardEvent.h"
    59 #include "KURL.h"
    6051#include "ModifySelectionListLevel.h"
    6152#include "Page.h"
    6253#include "Pasteboard.h"
    63 #include "Range.h"
    6454#include "RemoveFormatCommand.h"
    6555#include "ReplaceSelectionCommand.h"
    66 #include "SelectionController.h"
    6756#include "Sound.h"
    6857#include "Text.h"
     
    7564namespace WebCore {
    7665
    77 class FontData;
    78 
    7966using namespace std;
    8067using namespace EventNames;
     
    8370// When an event handler has moved the selection outside of a text control
    8471// we should use the target control's selection for this editing operation.
    85 static Selection selectionForEvent(Frame* frame, Event* event)
    86 {
    87     Page* page = frame->page();
    88     if (!page)
    89         return Selection();
    90     Selection selection = page->selection();
     72Selection Editor::selectionForCommand(Event* event)
     73{
     74    Selection selection = m_frame->selectionController()->selection();
    9175    if (!event)
    9276        return selection;
     77    // If the target is a text control, and the current selection is outside of its shadow tree,
     78    // then use the saved selection for that text control.
    9379    Node* target = event->target()->toNode();
    9480    Node* selectionStart = selection.start().node();
    95    
    96     // If the target is a text control, and the current selection is outside of its shadow tree,
    97     // then use the saved selection for that text control.
    9881    if (target && (!selectionStart || target->shadowAncestorNode() != selectionStart->shadowAncestorNode())) {
    9982        if (target->hasTagName(inputTag) && static_cast<HTMLInputElement*>(target)->isTextField())
     
    11598{
    11699    if (EditorClient* c = client())
    117         if (selectionForEvent(m_frame, event).isContentEditable())
     100        if (selectionForCommand(event).isContentEditable())
    118101            c->handleKeyboardEvent(event);
    119102}
     
    122105{
    123106    if (EditorClient* c = client())
    124         if (selectionForEvent(m_frame, event).isContentEditable())
     107        if (selectionForCommand(event).isContentEditable())
    125108            c->handleInputMethodKeydown(event);
    126109}
     
    161144}
    162145
    163 static Node* imageNodeFromImageDocument(Document* document)
     146static HTMLImageElement* imageElementFromImageDocument(Document* document)
    164147{
    165148    if (!document)
    166149        return 0;
    167    
    168150    if (!document->isImageDocument())
    169151        return 0;
     
    175157    Node* node = body->firstChild();
    176158    if (!node)
    177         return 0;
    178    
     159        return 0;   
    179160    if (!node->hasTagName(imgTag))
    180161        return 0;
    181    
    182     return node;
     162    return static_cast<HTMLImageElement*>(node);
    183163}
    184164
    185165bool Editor::canCopy() const
    186166{
    187     if (imageNodeFromImageDocument(m_frame->document()))
     167    if (imageElementFromImageDocument(m_frame->document()))
    188168        return true;
    189        
    190169    SelectionController* selectionController = m_frame->selectionController();
    191170    return selectionController->isRange() && !selectionController->isInPasswordField();
     
    480459}
    481460
    482 Frame::TriState Editor::selectionUnorderedListState() const
     461TriState Editor::selectionUnorderedListState() const
    483462{
    484463    if (m_frame->selectionController()->isCaret()) {
    485464        Node* selectionNode = m_frame->selectionController()->selection().start().node();
    486465        if (enclosingNodeWithTag(selectionNode, ulTag))
    487             return Frame::trueTriState;
     466            return TrueTriState;
    488467    } else if (m_frame->selectionController()->isRange()) {
    489468        Node* startNode = enclosingNodeWithTag(m_frame->selectionController()->selection().start().node(), ulTag);
    490469        Node* endNode = enclosingNodeWithTag(m_frame->selectionController()->selection().end().node(), ulTag);
    491470        if (startNode && endNode && startNode == endNode)
    492             return Frame::trueTriState;
    493     }
    494 
    495     return Frame::falseTriState;
    496 }
    497 
    498 Frame::TriState Editor::selectionOrderedListState() const
     471            return TrueTriState;
     472    }
     473
     474    return FalseTriState;
     475}
     476
     477TriState Editor::selectionOrderedListState() const
    499478{
    500479    if (m_frame->selectionController()->isCaret()) {
    501480        Node* selectionNode = m_frame->selectionController()->selection().start().node();
    502481        if (enclosingNodeWithTag(selectionNode, olTag))
    503             return Frame::trueTriState;
     482            return TrueTriState;
    504483    } else if (m_frame->selectionController()->isRange()) {
    505484        Node* startNode = enclosingNodeWithTag(m_frame->selectionController()->selection().start().node(), olTag);
    506485        Node* endNode = enclosingNodeWithTag(m_frame->selectionController()->selection().end().node(), olTag);
    507486        if (startNode && endNode && startNode == endNode)
    508             return Frame::trueTriState;
    509     }
    510 
    511     return Frame::falseTriState;
     487            return TrueTriState;
     488    }
     489
     490    return FalseTriState;
    512491}
    513492
     
    621600            // do nothing
    622601            break;
    623         case Selection::CARET: {
     602        case Selection::CARET:
    624603            m_frame->computeAndSetTypingStyle(style, editingAction);
    625604            break;
    626         }
    627605        case Selection::RANGE:
    628606            if (m_frame->document() && style)
     
    677655{
    678656    Node* nodeToRemove;
    679     RefPtr<CSSStyleDeclaration> selectionStyle = m_frame->selectionComputedStyle(nodeToRemove);
     657    RefPtr<CSSComputedStyleDeclaration> selectionStyle = m_frame->selectionComputedStyle(nodeToRemove);
    680658    if (!selectionStyle)
    681659        return false;
     
    702680}
    703681
     682static void updateState(CSSMutableStyleDeclaration* desiredStyle, CSSComputedStyleDeclaration* computedStyle, bool& atStart, TriState& state)
     683{
     684    DeprecatedValueListConstIterator<CSSProperty> end;
     685    for (DeprecatedValueListConstIterator<CSSProperty> it = desiredStyle->valuesIterator(); it != end; ++it) {
     686        int propertyID = (*it).id();
     687        String desiredProperty = desiredStyle->getPropertyValue(propertyID);
     688        String computedProperty = computedStyle->getPropertyValue(propertyID);
     689        TriState propertyState = equalIgnoringCase(desiredProperty, computedProperty)
     690            ? TrueTriState : FalseTriState;
     691        if (atStart) {
     692            state = propertyState;
     693            atStart = false;
     694        } else if (state != propertyState) {
     695            state = MixedTriState;
     696            break;
     697        }
     698    }
     699}
     700
     701TriState Editor::selectionHasStyle(CSSStyleDeclaration* style) const
     702{
     703    bool atStart = true;
     704    TriState state = FalseTriState;
     705
     706    RefPtr<CSSMutableStyleDeclaration> mutableStyle = style->makeMutable();
     707
     708    if (!m_frame->selectionController()->isRange()) {
     709        Node* nodeToRemove;
     710        RefPtr<CSSComputedStyleDeclaration> selectionStyle = m_frame->selectionComputedStyle(nodeToRemove);
     711        if (!selectionStyle)
     712            return FalseTriState;
     713        updateState(mutableStyle.get(), selectionStyle.get(), atStart, state);
     714        if (nodeToRemove) {
     715            ExceptionCode ec = 0;
     716            nodeToRemove->remove(ec);
     717            ASSERT(ec == 0);
     718        }
     719    } else {
     720        for (Node* node = m_frame->selectionController()->start().node(); node; node = node->traverseNextNode()) {
     721            RefPtr<CSSComputedStyleDeclaration> computedStyle = new CSSComputedStyleDeclaration(node);
     722            if (computedStyle)
     723                updateState(mutableStyle.get(), computedStyle.get(), atStart, state);
     724            if (state == MixedTriState)
     725                break;
     726            if (node == m_frame->selectionController()->end().node())
     727                break;
     728        }
     729    }
     730
     731    return state;
     732}
    704733void Editor::indent()
    705734{
     
    796825}
    797826
    798 // Execute command functions
    799 
    800 static bool execCopy(Frame* frame, Event*)
    801 {
    802     frame->editor()->copy();
    803     return true;
    804 }
    805 
    806 static bool execCut(Frame* frame, Event*)
    807 {
    808     frame->editor()->cut();
    809     return true;
    810 }
    811 
    812 static bool execDelete(Frame* frame, Event*)
    813 {
    814     frame->editor()->performDelete();
    815     return true;
    816 }
    817 
    818 static bool execDeleteWordBackward(Frame* frame, Event*)
    819 {
    820     frame->editor()->deleteWithDirection(SelectionController::BACKWARD, WordGranularity, true, false);
    821     return true;
    822 }
    823 
    824 static bool execDeleteWordForward(Frame* frame, Event*)
    825 {
    826     frame->editor()->deleteWithDirection(SelectionController::FORWARD, WordGranularity, true, false);
    827     return true;
    828 }
    829 
    830 static bool execBackwardDelete(Frame* frame, Event*)
    831 {
    832     frame->editor()->deleteWithDirection(SelectionController::BACKWARD, CharacterGranularity, false, true);
    833     return true;
    834 }
    835 
    836 static bool execForwardDelete(Frame* frame, Event*)
    837 {
    838     frame->editor()->deleteWithDirection(SelectionController::FORWARD, CharacterGranularity, false, true);
    839     return true;
    840 }
    841 
    842 static bool execMoveBackward(Frame* frame, Event*)
    843 {
    844     frame->selectionController()->modify(SelectionController::MOVE, SelectionController::BACKWARD, CharacterGranularity, true);
    845     return true;
    846 }
    847 
    848 static bool execMoveBackwardAndModifySelection(Frame* frame, Event*)
    849 {
    850     frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::BACKWARD, CharacterGranularity, true);
    851     return true;
    852 }
    853 
    854 static bool execMoveUpByPageAndModifyCaret(Frame* frame, Event*)
    855 {
    856     RenderObject* renderer = frame->document()->focusedNode()->renderer();
    857     if (renderer->style()->overflowY() == OSCROLL
    858         || renderer->style()->overflowY() == OAUTO
    859         || renderer->isTextArea()) {
    860         int height = -(frame->document()->focusedNode()->renderer()->clientHeight()-PAGE_KEEP);
    861         bool handledScroll = renderer->scroll(ScrollUp, ScrollByPage);
    862         bool handledCaretMove = frame->selectionController()->modify(SelectionController::MOVE, height);
    863         return handledScroll || handledCaretMove;
    864     }
    865     return false;
    866 }
    867 
    868 static bool execMoveDown(Frame* frame, Event*)
    869 {
    870     frame->selectionController()->modify(SelectionController::MOVE, SelectionController::FORWARD, LineGranularity, true);
    871     return true;
    872 }
    873 
    874 static bool execMoveDownAndModifySelection(Frame* frame, Event*)
    875 {
    876     frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::FORWARD, LineGranularity, true);
    877     return true;
    878 }
    879 
    880 static bool execMoveForward(Frame* frame, Event*)
    881 {
    882     frame->selectionController()->modify(SelectionController::MOVE, SelectionController::FORWARD, CharacterGranularity, true);
    883     return true;
    884 }
    885 
    886 static bool execMoveForwardAndModifySelection(Frame* frame, Event*)
    887 {
    888     frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::FORWARD, CharacterGranularity, true);
    889     return true;
    890 }
    891 
    892 static bool execMoveDownByPageAndModifyCaret(Frame* frame, Event*)
    893 {
    894     RenderObject* renderer = frame->document()->focusedNode()->renderer();
    895     if (renderer->style()->overflowY() == OSCROLL
    896         || renderer->style()->overflowY() == OAUTO
    897         || renderer->isTextArea()) {
    898         int height = frame->document()->focusedNode()->renderer()->clientHeight()-PAGE_KEEP;
    899         bool handledScroll = renderer->scroll(ScrollDown, ScrollByPage);
    900         bool handledCaretMove = frame->selectionController()->modify(SelectionController::MOVE, height);
    901         return handledScroll || handledCaretMove;
    902     }
    903     return false;
    904 }
    905 
    906 static bool execMoveLeft(Frame* frame, Event*)
    907 {
    908     frame->selectionController()->modify(SelectionController::MOVE, SelectionController::LEFT, CharacterGranularity, true);
    909     return true;
    910 }
    911 
    912 static bool execMoveLeftAndModifySelection(Frame* frame, Event*)
    913 {
    914     frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::LEFT, CharacterGranularity, true);
    915     return true;
    916 }
    917 
    918 static bool execMoveRight(Frame* frame, Event*)
    919 {
    920     frame->selectionController()->modify(SelectionController::MOVE, SelectionController::RIGHT, CharacterGranularity, true);
    921     return true;
    922 }
    923 
    924 static bool execMoveRightAndModifySelection(Frame* frame, Event*)
    925 {
    926     frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::RIGHT, CharacterGranularity, true);
    927     return true;
    928 }
    929 
    930 static bool execMoveToBeginningOfDocument(Frame* frame, Event*)
    931 {
    932     frame->selectionController()->modify(SelectionController::MOVE, SelectionController::BACKWARD, DocumentBoundary, true);
    933     return true;
    934 }
    935 
    936 static bool execMoveToBeginningOfDocumentAndModifySelection(Frame* frame, Event*)
    937 {
    938     frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::BACKWARD, DocumentBoundary, true);
    939     return true;
    940 }
    941 
    942 static bool execMoveToBeginningOfSentence(Frame* frame, Event*)
    943 {
    944     frame->selectionController()->modify(SelectionController::MOVE, SelectionController::BACKWARD, SentenceBoundary, true);
    945     return true;
    946 }
    947 
    948 static bool execMoveToBeginningOfSentenceAndModifySelection(Frame* frame, Event*)
    949 {
    950     frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::BACKWARD, SentenceBoundary, true);
    951     return true;
    952 }
    953 
    954 static bool execMoveToBeginningOfLine(Frame* frame, Event*)
    955 {
    956     frame->selectionController()->modify(SelectionController::MOVE, SelectionController::BACKWARD, LineBoundary, true);
    957     return true;
    958 }
    959 
    960 static bool execMoveToBeginningOfLineAndModifySelection(Frame* frame, Event*)
    961 {
    962     frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::BACKWARD, LineBoundary, true);
    963     return true;
    964 }
    965 
    966 static bool execMoveToBeginningOfParagraph(Frame* frame, Event*)
    967 {
    968     frame->selectionController()->modify(SelectionController::MOVE, SelectionController::BACKWARD, ParagraphBoundary, true);
    969     return true;
    970 }
    971 
    972 static bool execMoveToBeginningOfParagraphAndModifySelection(Frame* frame, Event*)
    973 {
    974     frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::BACKWARD, ParagraphBoundary, true);
    975     return true;
    976 }
    977 
    978 static bool execMoveToEndOfDocument(Frame* frame, Event*)
    979 {
    980     frame->selectionController()->modify(SelectionController::MOVE, SelectionController::FORWARD, DocumentBoundary, true);
    981     return true;
    982 }
    983 
    984 static bool execMoveToEndOfDocumentAndModifySelection(Frame* frame, Event*)
    985 {
    986     frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::FORWARD, DocumentBoundary, true);
    987     return true;
    988 }
    989 
    990 static bool execMoveToEndOfSentence(Frame* frame, Event*)
    991 {
    992     frame->selectionController()->modify(SelectionController::MOVE, SelectionController::FORWARD, SentenceBoundary, true);
    993     return true;
    994 }
    995 
    996 static bool execMoveToEndOfSentenceAndModifySelection(Frame* frame, Event*)
    997 {
    998     frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::FORWARD, SentenceBoundary, true);
    999     return true;
    1000 }
    1001 
    1002 static bool execMoveToEndOfLine(Frame* frame, Event*)
    1003 {
    1004     frame->selectionController()->modify(SelectionController::MOVE, SelectionController::FORWARD, LineBoundary, true);
    1005     return true;
    1006 }
    1007 
    1008 static bool execMoveToEndOfLineAndModifySelection(Frame* frame, Event*)
    1009 {
    1010     frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::FORWARD, LineBoundary, true);
    1011     return true;
    1012 }
    1013 
    1014 static bool execMoveToEndOfParagraph(Frame* frame, Event*)
    1015 {
    1016     frame->selectionController()->modify(SelectionController::MOVE, SelectionController::FORWARD, ParagraphBoundary, true);
    1017     return true;
    1018 }
    1019 
    1020 static bool execMoveToEndOfParagraphAndModifySelection(Frame* frame, Event*)
    1021 {
    1022     frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::FORWARD, ParagraphBoundary, true);
    1023     return true;
    1024 }
    1025 
    1026 static bool execMoveParagraphBackwardAndModifySelection(Frame* frame, Event*)
    1027 {
    1028     frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::BACKWARD, ParagraphGranularity, true);
    1029     return true;
    1030 }
    1031 
    1032 static bool execMoveParagraphForwardAndModifySelection(Frame* frame, Event*)
    1033 {
    1034     frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::FORWARD, ParagraphGranularity, true);
    1035     return true;
    1036 }
    1037 
    1038 static bool execMoveUp(Frame* frame, Event*)
    1039 {
    1040     frame->selectionController()->modify(SelectionController::MOVE, SelectionController::BACKWARD, LineGranularity, true);
    1041     return true;
    1042 }
    1043 
    1044 static bool execMoveUpAndModifySelection(Frame* frame, Event*)
    1045 {
    1046     frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::BACKWARD, LineGranularity, true);
    1047     return true;
    1048 }
    1049 
    1050 static bool execMoveWordBackward(Frame* frame, Event*)
    1051 {
    1052     frame->selectionController()->modify(SelectionController::MOVE, SelectionController::BACKWARD, WordGranularity, true);
    1053     return true;
    1054 }
    1055 
    1056 static bool execMoveWordBackwardAndModifySelection(Frame* frame, Event*)
    1057 {
    1058     frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::BACKWARD, WordGranularity, true);
    1059     return true;
    1060 }
    1061 
    1062 static bool execMoveWordForward(Frame* frame, Event*)
    1063 {
    1064     frame->selectionController()->modify(SelectionController::MOVE, SelectionController::FORWARD, WordGranularity, true);
    1065     return true;
    1066 }
    1067 
    1068 static bool execMoveWordForwardAndModifySelection(Frame* frame, Event*)
    1069 {
    1070     frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::FORWARD, WordGranularity, true);
    1071     return true;
    1072 }
    1073 
    1074 static bool execMoveWordLeft(Frame* frame, Event*)
    1075 {
    1076     frame->selectionController()->modify(SelectionController::MOVE, SelectionController::LEFT, WordGranularity, true);
    1077     return true;
    1078 }
    1079 
    1080 static bool execMoveWordLeftAndModifySelection(Frame* frame, Event*)
    1081 {
    1082     frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::LEFT, WordGranularity, true);
    1083     return true;
    1084 }
    1085 
    1086 static bool execMoveWordRight(Frame* frame, Event*)
    1087 {
    1088     frame->selectionController()->modify(SelectionController::MOVE, SelectionController::RIGHT, WordGranularity, true);
    1089     return true;
    1090 }
    1091 
    1092 static bool execMoveWordRightAndModifySelection(Frame* frame, Event*)
    1093 {
    1094     frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::RIGHT, WordGranularity, true);
    1095     return true;
    1096 }
    1097 
    1098 static bool execPaste(Frame* frame, Event*)
    1099 {
    1100     frame->editor()->paste();
    1101     return true;
    1102 }
    1103 
    1104 static bool execSelectAll(Frame* frame, Event*)
    1105 {
    1106     frame->selectionController()->selectAll();
    1107     return true;
    1108 }
    1109 
    1110 static bool execToggleBold(Frame* frame, Event*)
    1111 {
    1112     ExceptionCode ec;
    1113    
    1114     RefPtr<CSSStyleDeclaration> style = frame->document()->createCSSStyleDeclaration();
    1115     style->setProperty(CSS_PROP_FONT_WEIGHT, "bold", false, ec);
    1116     if (frame->editor()->selectionStartHasStyle(style.get()))
    1117         style->setProperty(CSS_PROP_FONT_WEIGHT, "normal", false, ec);
    1118     frame->editor()->applyStyleToSelection(style.get(), EditActionSetFont);
    1119     return true;
    1120 }
    1121 
    1122 static bool execToggleItalic(Frame* frame, Event*)
    1123 {
    1124     ExceptionCode ec;
    1125    
    1126     RefPtr<CSSStyleDeclaration> style = frame->document()->createCSSStyleDeclaration();
    1127     style->setProperty(CSS_PROP_FONT_STYLE, "italic", false, ec);
    1128     if (frame->editor()->selectionStartHasStyle(style.get()))
    1129         style->setProperty(CSS_PROP_FONT_STYLE, "normal", false, ec);
    1130     frame->editor()->applyStyleToSelection(style.get(), EditActionSetFont);
    1131     return true;
    1132 }
    1133 
    1134 static bool execRedo(Frame* frame, Event*)
    1135 {
    1136     frame->editor()->redo();
    1137     return true;
    1138 }
    1139 
    1140 static bool execUndo(Frame* frame, Event*)
    1141 {
    1142     frame->editor()->undo();
    1143     return true;
    1144 }
    1145 
    1146 static bool execTranspose(Frame* frame, Event*)
    1147 {
    1148     frame->editor()->transpose();
    1149     return true;
    1150 }
    1151 
    1152 static inline Frame* targetFrame(Frame* frame, Event* evt)
    1153 {
    1154     Node* node = evt ? evt->target()->toNode() : 0;
    1155     if (!node)
    1156         return frame;
    1157     return node->document()->frame();
    1158 }
    1159 
    1160 static bool execInsertTab(Frame* frame, Event* evt)
    1161 {
    1162     return targetFrame(frame, evt)->eventHandler()->handleTextInputEvent("\t", evt, false, false);
    1163 }
    1164 
    1165 static bool execInsertBacktab(Frame* frame, Event* evt)
    1166 {
    1167     return targetFrame(frame, evt)->eventHandler()->handleTextInputEvent("\t", evt, false, true);
    1168 }
    1169 
    1170 static bool execInsertNewline(Frame* frame, Event* evt)
    1171 {
    1172     Frame* targetFrame = WebCore::targetFrame(frame, evt);
    1173     return targetFrame->eventHandler()->handleTextInputEvent("\n", evt, !targetFrame->editor()->canEditRichly());
    1174 }
    1175 
    1176 static bool execInsertLineBreak(Frame* frame, Event* evt)
    1177 {
    1178     return targetFrame(frame, evt)->eventHandler()->handleTextInputEvent("\n", evt, true);
    1179 }
    1180 
    1181 // Enabled functions
    1182 
    1183 static bool enabled(Frame*, Event*)
    1184 {
    1185     return true;
    1186 }
    1187 
    1188 static bool canPaste(Frame* frame, Event*)
    1189 {
    1190     return frame->editor()->canPaste();
    1191 }
    1192 
    1193 static bool hasEditableSelection(Frame* frame, Event* evt)
    1194 {
    1195     if (evt)
    1196         return selectionForEvent(frame, evt).isContentEditable();
    1197     return frame->selectionController()->isContentEditable();
    1198 }
    1199 
    1200 static bool hasEditableRangeSelection(Frame* frame, Event*)
    1201 {
    1202     return frame->selectionController()->isRange() && frame->selectionController()->isContentEditable();
    1203 }
    1204 
    1205 static bool hasRangeSelection(Frame* frame, Event*)
    1206 {
    1207     return frame->selectionController()->isRange();
    1208 }
    1209 
    1210 static bool hasRichlyEditableSelection(Frame* frame, Event*)
    1211 {
    1212     return frame->selectionController()->isCaretOrRange() && frame->selectionController()->isContentRichlyEditable();
    1213 }
    1214 
    1215 static bool canRedo(Frame* frame, Event*)
    1216 {
    1217     return frame->editor()->canRedo();
    1218 }
    1219 
    1220 static bool canUndo(Frame* frame, Event*)
    1221 {
    1222     return frame->editor()->canUndo();
    1223 }
    1224 
    1225 struct Command {
    1226     bool (*enabled)(Frame*, Event*);
    1227     bool (*exec)(Frame*, Event*);
    1228 };
    1229 
    1230 typedef HashMap<RefPtr<AtomicStringImpl>, const Command*> CommandMap;
    1231 
    1232 static CommandMap* createCommandMap()
    1233 {
    1234     struct CommandEntry { const char* name; Command command; };
    1235    
    1236     static const CommandEntry commands[] = {
    1237         { "BackwardDelete", { hasEditableSelection, execBackwardDelete } },
    1238         { "Copy", { hasRangeSelection, execCopy } },
    1239         { "Cut", { hasEditableRangeSelection, execCut } },
    1240         { "Delete", { hasEditableSelection, execDelete } },
    1241         { "DeleteWordBackward", { hasEditableSelection, execDeleteWordBackward } },
    1242         { "DeleteWordForward", { hasEditableSelection, execDeleteWordForward} },
    1243         { "ForwardDelete", { hasEditableSelection, execForwardDelete } },
    1244         { "InsertBacktab", { hasEditableSelection, execInsertBacktab } },
    1245         { "InsertTab", { hasEditableSelection, execInsertTab } },
    1246         { "InsertLineBreak", { hasEditableSelection, execInsertLineBreak } },       
    1247         { "InsertNewline", { hasEditableSelection, execInsertNewline } },       
    1248         { "MoveBackward", { hasEditableSelection, execMoveBackward } },
    1249         { "MoveBackwardAndModifySelection", { hasEditableSelection, execMoveBackwardAndModifySelection } },
    1250         { "MoveUpByPageAndModifyCaret", { hasEditableSelection, execMoveUpByPageAndModifyCaret } },
    1251         { "MoveDown", { hasEditableSelection, execMoveDown } },
    1252         { "MoveDownAndModifySelection", { hasEditableSelection, execMoveDownAndModifySelection } },
    1253         { "MoveForward", { hasEditableSelection, execMoveForward } },
    1254         { "MoveForwardAndModifySelection", { hasEditableSelection, execMoveForwardAndModifySelection } },
    1255         { "MoveDownByPageAndModifyCaret", { hasEditableSelection, execMoveDownByPageAndModifyCaret } },
    1256         { "MoveLeft", { hasEditableSelection, execMoveLeft } },
    1257         { "MoveLeftAndModifySelection", { hasEditableSelection, execMoveLeftAndModifySelection } },
    1258         { "MoveRight", { hasEditableSelection, execMoveRight } },
    1259         { "MoveRightAndModifySelection", { hasEditableSelection, execMoveRightAndModifySelection } },
    1260         { "MoveToBeginningOfDocument", { hasEditableSelection, execMoveToBeginningOfDocument } },
    1261         { "MoveToBeginningOfDocumentAndModifySelection", { hasEditableSelection, execMoveToBeginningOfDocumentAndModifySelection } },
    1262         { "MoveToBeginningOfSentence", { hasEditableSelection, execMoveToBeginningOfSentence } },
    1263         { "MoveToBeginningOfSentenceAndModifySelection", { hasEditableSelection, execMoveToBeginningOfSentenceAndModifySelection } },
    1264         { "MoveToBeginningOfLine", { hasEditableSelection, execMoveToBeginningOfLine } },
    1265         { "MoveToBeginningOfLineAndModifySelection", { hasEditableSelection, execMoveToBeginningOfLineAndModifySelection } },
    1266         { "MoveToBeginningOfParagraph", { hasEditableSelection, execMoveToBeginningOfParagraph } },
    1267         { "MoveToBeginningOfParagraphAndModifySelection", { hasEditableSelection, execMoveToBeginningOfParagraphAndModifySelection } },
    1268         { "MoveToEndOfDocument", { hasEditableSelection, execMoveToEndOfDocument } },
    1269         { "MoveToEndOfDocumentAndModifySelection", { hasEditableSelection, execMoveToEndOfDocumentAndModifySelection } },
    1270         { "MoveToEndOfSentence", { hasEditableSelection, execMoveToEndOfSentence } },
    1271         { "MoveToEndOfSentenceAndModifySelection", { hasEditableSelection, execMoveToEndOfSentenceAndModifySelection } },
    1272         { "MoveToEndOfLine", { hasEditableSelection, execMoveToEndOfLine } },
    1273         { "MoveToEndOfLineAndModifySelection", { hasEditableSelection, execMoveToEndOfLineAndModifySelection } },
    1274         { "MoveToEndOfParagraph", { hasEditableSelection, execMoveToEndOfParagraph } },
    1275         { "MoveToEndOfParagraphAndModifySelection", { hasEditableSelection, execMoveToEndOfParagraphAndModifySelection } },
    1276         { "MoveParagraphBackwardAndModifySelection", { hasEditableSelection, execMoveParagraphBackwardAndModifySelection } },
    1277         { "MoveParagraphForwardAndModifySelection", { hasEditableSelection, execMoveParagraphForwardAndModifySelection } },
    1278         { "MoveUp", { hasEditableSelection, execMoveUp } },
    1279         { "MoveUpAndModifySelection", { hasEditableSelection, execMoveUpAndModifySelection } },
    1280         { "MoveWordBackward", { hasEditableSelection, execMoveWordBackward } },
    1281         { "MoveWordBackwardAndModifySelection", { hasEditableSelection, execMoveWordBackwardAndModifySelection } },
    1282         { "MoveWordForward", { hasEditableSelection, execMoveWordForward } },
    1283         { "MoveWordForwardAndModifySelection", { hasEditableSelection, execMoveWordForwardAndModifySelection } },
    1284         { "MoveWordLeft", { hasEditableSelection, execMoveWordLeft } },
    1285         { "MoveWordLeftAndModifySelection", { hasEditableSelection, execMoveWordLeftAndModifySelection } },
    1286         { "MoveWordRight", { hasEditableSelection, execMoveWordRight } },
    1287         { "MoveWordRightAndModifySelection", { hasEditableSelection, execMoveWordRightAndModifySelection } },
    1288         { "Paste", { canPaste, execPaste } },
    1289         { "Redo", { canRedo, execRedo } },
    1290         { "SelectAll", { enabled, execSelectAll } },
    1291         { "ToggleBold", { hasRichlyEditableSelection, execToggleBold } },
    1292         { "ToggleItalic", { hasRichlyEditableSelection, execToggleItalic } },
    1293         { "Transpose", { hasEditableSelection, execTranspose } },
    1294         { "Undo", { canUndo, execUndo } }
    1295     };
    1296 
    1297     CommandMap* commandMap = new CommandMap;
    1298 
    1299     const unsigned numCommands = sizeof(commands) / sizeof(commands[0]);
    1300     for (unsigned i = 0; i < numCommands; i++)
    1301         commandMap->set(AtomicString(commands[i].name).impl(), &commands[i].command);
    1302 
    1303     return commandMap;
    1304 }
    1305 
    1306 // =============================================================================
    1307 //
    1308 // public editing commands
    1309 //
    1310 // =============================================================================
    1311 
    1312827Editor::Editor(Frame* frame)
    1313828    : m_frame(frame)
    1314829    , m_deleteButtonController(new DeleteButtonController(frame))
    1315830    , m_ignoreCompositionSelectionChange(false)
     831    , m_shouldStartNewKillRingSequence(false)
    1316832{
    1317833}
     
    1327843}
    1328844
    1329 bool Editor::isTextInsertionCommand(const AtomicString& command)
    1330 {
    1331     return command == "InsertBacktab"
    1332         || command == "InsertTab"
    1333         || command == "InsertLineBreak"
    1334         || command == "InsertNewline";
    1335 }
    1336 
    1337 bool Editor::execCommand(const AtomicString& command, Event* triggeringEvent)
    1338 {
    1339     if (!m_frame->document())
    1340         return false;
    1341 
    1342     static CommandMap* commandMap;
    1343     if (!commandMap)
    1344         commandMap = createCommandMap();
    1345    
    1346     const Command* c = commandMap->get(command.impl());
    1347     if (!c)
    1348         return false;
    1349    
    1350     bool handled = false;
    1351    
    1352     if (c->enabled(m_frame, triggeringEvent)) {
    1353         m_frame->document()->updateLayoutIgnorePendingStylesheets();
    1354         handled = c->exec(m_frame, triggeringEvent);
    1355     }
    1356    
    1357     return handled;
    1358 }
    1359 
    1360845bool Editor::insertText(const String& text, Event* triggeringEvent)
    1361846{
     
    1368853        return false;
    1369854
    1370     Selection selection = selectionForEvent(m_frame, triggeringEvent);
     855    Selection selection = selectionForCommand(triggeringEvent);
    1371856    if (!selection.isContentEditable())
    1372857        return false;
     
    1379864    // If the event handler changed the selection, we may want to use a different selection
    1380865    // that is contained in the event target.
    1381     selection = selectionForEvent(m_frame, triggeringEvent);
     866    selection = selectionForCommand(triggeringEvent);
    1382867    if (selection.isContentEditable()) {
    1383868        if (Node* selectionStart = selection.start().node()) {
     
    1452937   
    1453938    Document* document = m_frame->document();
    1454     if (Node* node = imageNodeFromImageDocument(document))
    1455         Pasteboard::generalPasteboard()->writeImage(node, document->URL(), document->title());
     939    if (HTMLImageElement* imageElement = imageElementFromImageDocument(document))
     940        Pasteboard::generalPasteboard()->writeImage(imageElement, document->URL(), document->title());
    1456941    else
    1457942        Pasteboard::generalPasteboard()->writeSelection(selectedRange().get(), canSmartCopyOrDelete(), m_frame);
     
    16051090void Editor::toggleBold()
    16061091{
    1607     execToggleBold(frame(), 0);
     1092    command("ToggleBold").execute();
    16081093}
    16091094
    16101095void Editor::toggleUnderline()
    16111096{
     1097    command("ToggleUnderline").execute();
     1098}
     1099
     1100void Editor::setBaseWritingDirection(const String& direction)
     1101{
    16121102    ExceptionCode ec = 0;
    16131103
    1614     RefPtr<CSSStyleDeclaration> style = frame()->document()->createCSSStyleDeclaration();
    1615     style->setProperty(CSS_PROP__WEBKIT_TEXT_DECORATIONS_IN_EFFECT, "underline", false, ec);
    1616     if (selectionStartHasStyle(style.get()))
    1617         style->setProperty(CSS_PROP__WEBKIT_TEXT_DECORATIONS_IN_EFFECT, "none", false, ec);
    1618     applyStyleToSelection(style.get(), EditActionUnderline);
    1619 }
    1620 
    1621 void Editor::setBaseWritingDirection(String direction)
    1622 {
    1623     ExceptionCode ec = 0;
    1624 
    1625     RefPtr<CSSStyleDeclaration> style = frame()->document()->createCSSStyleDeclaration();
     1104    RefPtr<CSSMutableStyleDeclaration> style = new CSSMutableStyleDeclaration;
    16261105    style->setProperty(CSS_PROP_DIRECTION, direction, false, ec);
    16271106    applyParagraphStyleToSelection(style.get(), EditActionSetWritingDirection);
     
    24161895}
    24171896
     1897void Editor::addToKillRing(Range* range, bool prepend)
     1898{
     1899    if (m_shouldStartNewKillRingSequence)
     1900        startNewKillRingSequence();
     1901
     1902    String text = plainText(range);
     1903    text.replace('\\', m_frame->backslashAsCurrencySymbol());
     1904    if (prepend)
     1905        prependToKillRing(text);
     1906    else
     1907        appendToKillRing(text);
     1908    m_shouldStartNewKillRingSequence = false;
     1909}
     1910
     1911#if !PLATFORM(MAC)
     1912
     1913void Editor::appendToKillRing(const String&)
     1914{
     1915}
     1916
     1917void Editor::prependToKillRing(const String&)
     1918{
     1919}
     1920
     1921String Editor::yankFromKillRing()
     1922{
     1923}
     1924
     1925void Editor::startNewKillRingSequence()
     1926{
     1927}
     1928
     1929void Editor::setKillRingToYankedState()
     1930{
     1931}
     1932
     1933#endif
     1934
    24181935} // namespace WebCore
  • trunk/WebCore/editing/Editor.h

    r28620 r28626  
    4747class DocumentFragment;
    4848class EditCommand;
     49class EditorInternalCommand;
    4950class EditorClient;
    5051class EventTargetNode;
     
    6869};
    6970
     71enum TriState { FalseTriState, TrueTriState, MixedTriState };
     72enum EditorCommandSource { CommandFromMenuOrKeyBinding, CommandFromDOM, CommandFromDOMWithUserInterface };
     73
    7074class Editor {
    7175public:
     
    118122    void respondToChangedSelection(const Selection& oldSelection);
    119123    void respondToChangedContents(const Selection& endingSelection);
    120    
     124
     125    TriState selectionHasStyle(CSSStyleDeclaration*) const;
    121126    const FontData* fontForSelection(bool&) const;
    122127   
    123     Frame::TriState selectionUnorderedListState() const;
    124     Frame::TriState selectionOrderedListState() const;
     128    TriState selectionUnorderedListState() const;
     129    TriState selectionOrderedListState() const;
    125130    PassRefPtr<Node> insertOrderedList();
    126131    PassRefPtr<Node> insertUnorderedList();
     
    158163    bool clientIsEditable() const;
    159164
    160     static bool isTextInsertionCommand(const AtomicString&);
    161 
    162     bool execCommand(const AtomicString&, Event* triggeringEvent = 0);
    163    
     165    class Command {
     166    public:
     167        Command();
     168        Command(PassRefPtr<Frame>, const EditorInternalCommand*, EditorCommandSource);
     169
     170        bool execute(const String& parameter = String(), Event* triggeringEvent = 0) const;
     171        bool execute(Event* triggeringEvent) const;
     172
     173        bool isSupported() const;
     174        bool isEnabled(Event* triggeringEvent = 0) const;
     175
     176        TriState state(Event* triggeringEvent = 0) const;
     177        String value(Event* triggeringEvent = 0) const;
     178
     179        bool isTextInsertion() const;
     180
     181    private:
     182        RefPtr<Frame> m_frame;
     183        const EditorInternalCommand* m_command;
     184        EditorCommandSource m_source;
     185    };
     186    Command command(const String& commandName); // Default is CommandFromMenuOrKeyBinding.
     187    Command command(const String& commandName, EditorCommandSource);
     188
     189    // Deprecated, but used by old key binding code. Keep around until we have eliminated all callers.
     190    bool execCommand(const AtomicString& commandName, Event* triggeringEvent = 0);
     191
    164192    bool insertText(const String&, Event* triggeringEvent);
    165193    bool insertTextWithoutSendingTextEvent(const String&, bool selectInsertedText, Event* triggeringEvent = 0);
     
    203231    void toggleBold();
    204232    void toggleUnderline();
    205     void setBaseWritingDirection(String);
     233    void setBaseWritingDirection(const String&);
    206234
    207235    bool smartInsertDeleteEnabled();
     
    227255    void setStartNewKillRingSequence(bool);
    228256
     257    PassRefPtr<Range> rangeForPoint(const IntPoint& windowPoint);
     258
     259    void clear();
     260
     261    Selection selectionForCommand(Event*);
     262
    229263#if PLATFORM(MAC)
    230264    NSString* userVisibleString(NSURL*);
    231 
    232     void yank();
    233     void yankAndSelect();
    234     void setMark();
    235     void deleteToMark();
    236     void selectToMark();
    237     void swapWithMark();
    238 
    239265#endif
    240266
    241     PassRefPtr<Range> rangeForPoint(const IntPoint& windowPoint);
    242 
    243     void clear();
     267    void appendToKillRing(const String&);
     268    void prependToKillRing(const String&);
     269    String yankFromKillRing();
     270    void startNewKillRingSequence();
     271    void setKillRingToYankedState();
     272
     273    PassRefPtr<Range> selectedRange();
    244274
    245275private:
     
    254284    Vector<CompositionUnderline> m_customCompositionUnderlines;
    255285    bool m_ignoreCompositionSelectionChange;
     286    bool m_shouldStartNewKillRingSequence;
    256287
    257288    bool canDeleteRange(Range*) const;
    258289    bool canSmartReplaceWithPasteboard(Pasteboard*);
    259290    PassRefPtr<Clipboard> newGeneralClipboard(ClipboardAccessPolicy);
    260     PassRefPtr<Range> selectedRange();
    261291    void pasteAsPlainTextWithPasteboard(Pasteboard*);
    262292    void pasteWithPasteboard(Pasteboard*, bool allowPlainText);
     
    271301
    272302    void addToKillRing(Range*, bool prepend);
    273 
    274 #if PLATFORM(MAC)
    275     bool m_startNewKillRingSequence;
    276 #endif
    277303};
    278 
    279 #if PLATFORM(MAC)
    280304
    281305inline void Editor::setStartNewKillRingSequence(bool flag)
    282306{
    283     m_startNewKillRingSequence = flag;
     307    m_shouldStartNewKillRingSequence = flag;
    284308}
    285309
    286 #else
    287 
    288 inline void Editor::setStartNewKillRingSequence(bool) { }
    289 inline void Editor::addToKillRing(Range*, bool) { }
    290 
    291 #endif
    292 
    293310} // namespace WebCore
    294311
  • trunk/WebCore/editing/EditorCommand.cpp

    r28608 r28626  
    2626
    2727#include "config.h"
     28
     29#include "AtomicString.h"
     30#include "CSSPropertyNames.h"
     31#include "CreateLinkCommand.h"
     32#include "DocumentFragment.h"
    2833#include "Editor.h"
    29 
    30 #include "AXObjectCache.h"
    31 #include "ApplyStyleCommand.h"
    32 #include "CSSComputedStyleDeclaration.h"
    33 #include "CSSProperty.h"
    34 #include "CSSPropertyNames.h"
    35 #include "CharacterData.h"
    36 #include "Clipboard.h"
    37 #include "ClipboardEvent.h"
    38 #include "DeleteButtonController.h"
    39 #include "DeleteSelectionCommand.h"
    40 #include "DocLoader.h"
    41 #include "Document.h"
    42 #include "DocumentFragment.h"
    43 #include "EditCommand.h"
    44 #include "Editor.h"
    45 #include "EditorClient.h"
    4634#include "Event.h"
    4735#include "EventHandler.h"
    48 #include "EventNames.h"
    49 #include "FocusController.h"
    50 #include "FrameView.h"
    51 #include "HTMLElement.h"
    52 #include "HTMLInputElement.h"
    53 #include "HTMLNames.h"
    54 #include "HTMLTextAreaElement.h"
    55 #include "HitTestResult.h"
     36#include "FormatBlockCommand.h"
     37#include "HTMLFontElement.h"
     38#include "HTMLImageElement.h"
    5639#include "IndentOutdentCommand.h"
    5740#include "InsertListCommand.h"
    58 #include "KeyboardEvent.h"
    59 #include "KURL.h"
    60 #include "ModifySelectionListLevel.h"
    6141#include "Page.h"
    62 #include "Pasteboard.h"
    63 #include "Range.h"
    64 #include "RemoveFormatCommand.h"
    6542#include "ReplaceSelectionCommand.h"
    66 #include "SelectionController.h"
     43#include "Settings.h"
    6744#include "Sound.h"
    68 #include "Text.h"
    69 #include "TextIterator.h"
    7045#include "TypingCommand.h"
     46#include "UnlinkCommand.h"
    7147#include "htmlediting.h"
    7248#include "markup.h"
    73 #include "visible_units.h"
    7449
    7550namespace WebCore {
    7651
    77 class FontData;
    78 
    79 using namespace std;
    80 using namespace EventNames;
    8152using namespace HTMLNames;
    8253
    83 // When an event handler has moved the selection outside of a text control
    84 // we should use the target control's selection for this editing operation.
    85 static Selection selectionForEvent(Frame* frame, Event* event)
    86 {
    87     Page* page = frame->page();
    88     if (!page)
    89         return Selection();
    90     Selection selection = page->selection();
     54class EditorInternalCommand {
     55public:
     56    bool (*execute)(Frame*, Event*, EditorCommandSource, const String&);
     57    bool (*isSupported)(Frame*, EditorCommandSource);
     58    bool (*isEnabled)(Frame*, Event*);
     59    TriState (*state)(Frame*, Event*);
     60    String (*value)(Frame*, Event*);
     61    bool isTextInsertion;
     62};
     63
     64typedef HashMap<String, const EditorInternalCommand*, CaseFoldingHash> CommandMap;
     65
     66static const bool notTextInsertion = false;
     67static const bool isTextInsertion = true;
     68
     69// Related to Editor::selectionForCommand.
     70// Certain operations continue to use the target control's selection even if the event handler
     71// already moved the selection outside of the text control.
     72static Frame* targetFrame(Frame* frame, Event* event)
     73{
    9174    if (!event)
    92         return selection;
    93     Node* target = event->target()->toNode();
    94     Node* selectionStart = selection.start().node();
    95    
    96     // If the target is a text control, and the current selection is outside of its shadow tree,
    97     // then use the saved selection for that text control.
    98     if (target && (!selectionStart || target->shadowAncestorNode() != selectionStart->shadowAncestorNode())) {
    99         if (target->hasTagName(inputTag) && static_cast<HTMLInputElement*>(target)->isTextField())
    100             return static_cast<HTMLInputElement*>(target)->selection();
    101         if (target->hasTagName(textareaTag))
    102             return static_cast<HTMLTextAreaElement*>(target)->selection();
    103     }
    104     return selection;
    105 }
    106 
    107 EditorClient* Editor::client() const
    108 {
    109     if (Page* page = m_frame->page())
    110         return page->editorClient();
    111     return 0;
    112 }
    113 
    114 void Editor::handleKeypress(KeyboardEvent* event)
    115 {
    116     if (EditorClient* c = client())
    117         if (selectionForEvent(m_frame, event).isContentEditable())
    118             c->handleKeypress(event);
    119 }
    120 
    121 void Editor::handleInputMethodKeypress(KeyboardEvent* event)
    122 {
    123     if (EditorClient* c = client())
    124         if (selectionForEvent(m_frame, event).isContentEditable())
    125             c->handleInputMethodKeypress(event);
    126 }
    127 
    128 bool Editor::canEdit() const
    129 {
    130     return m_frame->selectionController()->isContentEditable();
    131 }
    132 
    133 bool Editor::canEditRichly() const
    134 {
    135     return m_frame->selectionController()->isContentRichlyEditable();
    136 }
    137 
    138 // WinIE uses onbeforecut and onbeforepaste to enables the cut and paste menu items.  They
    139 // also send onbeforecopy, apparently for symmetry, but it doesn't affect the menu items.
    140 // We need to use onbeforecopy as a real menu enabler because we allow elements that are not
    141 // normally selectable to implement copy/paste (like divs, or a document body).
    142 
    143 bool Editor::canDHTMLCut()
    144 {
    145     return !m_frame->selectionController()->isInPasswordField() && !dispatchCPPEvent(beforecutEvent, ClipboardNumb);
    146 }
    147 
    148 bool Editor::canDHTMLCopy()
    149 {
    150     return !m_frame->selectionController()->isInPasswordField() && !dispatchCPPEvent(beforecopyEvent, ClipboardNumb);
    151 }
    152 
    153 bool Editor::canDHTMLPaste()
    154 {
    155     return !dispatchCPPEvent(beforepasteEvent, ClipboardNumb);
    156 }
    157 
    158 bool Editor::canCut() const
    159 {
    160     return canCopy() && canDelete();
    161 }
    162 
    163 static Node* imageNodeFromImageDocument(Document* document)
    164 {
    165     if (!document)
    166         return 0;
    167    
    168     if (!document->isImageDocument())
    169         return 0;
    170    
    171     HTMLElement* body = document->body();
    172     if (!body)
    173         return 0;
    174    
    175     Node* node = body->firstChild();
    176     if (!node)
    177         return 0;
    178    
    179     if (!node->hasTagName(imgTag))
    180         return 0;
    181    
    182     return node;
    183 }
    184 
    185 bool Editor::canCopy() const
    186 {
    187     if (imageNodeFromImageDocument(m_frame->document()))
    188         return true;
    189        
    190     SelectionController* selectionController = m_frame->selectionController();
    191     return selectionController->isRange() && !selectionController->isInPasswordField();
    192 }
    193 
    194 bool Editor::canPaste() const
    195 {
    196     return canEdit();
    197 }
    198 
    199 bool Editor::canDelete() const
    200 {
    201     SelectionController* selectionController = m_frame->selectionController();
    202     return selectionController->isRange() && selectionController->isContentEditable();
    203 }
    204 
    205 bool Editor::canDeleteRange(Range* range) const
    206 {
    207     ExceptionCode ec = 0;
    208     Node* startContainer = range->startContainer(ec);
    209     Node* endContainer = range->endContainer(ec);
    210     if (!startContainer || !endContainer)
    211         return false;
    212    
    213     if (!startContainer->isContentEditable() || !endContainer->isContentEditable())
    214         return false;
    215    
    216     if (range->collapsed(ec)) {
    217         VisiblePosition start(startContainer, range->startOffset(ec), DOWNSTREAM);
    218         VisiblePosition previous = start.previous();
    219         // FIXME: We sometimes allow deletions at the start of editable roots, like when the caret is in an empty list item.
    220         if (previous.isNull() || previous.deepEquivalent().node()->rootEditableElement() != startContainer->rootEditableElement())
    221             return false;
    222     }
    223     return true;
    224 }
    225 
    226 bool Editor::smartInsertDeleteEnabled()
    227 {   
    228     return client() && client()->smartInsertDeleteEnabled();
    229 }
    230    
    231 bool Editor::canSmartCopyOrDelete()
    232 {
    233     return client() && client()->smartInsertDeleteEnabled() && m_frame->selectionGranularity() == WordGranularity;
    234 }
    235 
    236 bool Editor::deleteWithDirection(SelectionController::EDirection direction, TextGranularity granularity, bool killRing, bool isTypingAction)
    237 {
    238     // Delete the selection, if there is one.
    239     // If not, make a selection using the passed-in direction and granularity.
    240 
    241     if (!canEdit())
    242         return false;
    243 
    244     if (m_frame->selectionController()->isRange()) {
    245         if (killRing)
    246             addToKillRing(selectedRange().get(), false);
    247         if (isTypingAction) {
    248             if (m_frame->document()) {
    249                 TypingCommand::deleteKeyPressed(m_frame->document(), true, granularity);
    250                 revealSelectionAfterEditingOperation();
    251             }
    252         } else {
    253             deleteSelectionWithSmartDelete(canSmartCopyOrDelete());
    254             // Implicitly calls revealSelectionAfterEditingOperation().
    255         }
    256     } else {
    257         SelectionController selectionToDelete;
    258         selectionToDelete.setSelection(m_frame->selectionController()->selection());
    259         selectionToDelete.modify(SelectionController::EXTEND, direction, granularity);
    260         if (killRing && selectionToDelete.isCaret() && granularity != CharacterGranularity)
    261             selectionToDelete.modify(SelectionController::EXTEND, direction, CharacterGranularity);
    262 
    263         RefPtr<Range> range = selectionToDelete.toRange();
    264 
    265         if (killRing)
    266             addToKillRing(range.get(), false);
    267 
    268         if (!m_frame->selectionController()->setSelectedRange(range.get(), DOWNSTREAM, (granularity != CharacterGranularity)))
    269             return true;
    270 
    271         switch (direction) {
    272             case SelectionController::FORWARD:
    273             case SelectionController::RIGHT:
    274                 if (m_frame->document())
    275                     TypingCommand::forwardDeleteKeyPressed(m_frame->document(), false, granularity);
    276                 break;
    277             case SelectionController::BACKWARD:
    278             case SelectionController::LEFT:
    279                 if (m_frame->document())
    280                     TypingCommand::deleteKeyPressed(m_frame->document(), false, granularity);
    281                 break;
    282         }
    283         revealSelectionAfterEditingOperation();
    284     }
    285 
    286     // clear the "start new kill ring sequence" setting, because it was set to true
    287     // when the selection was updated by deleting the range
    288     if (killRing)
    289         setStartNewKillRingSequence(false);
    290 
    291     return true;
    292 }
    293 
    294 void Editor::deleteSelectionWithSmartDelete(bool smartDelete)
    295 {
    296     if (m_frame->selectionController()->isNone())
    297         return;
    298    
    299     applyCommand(new DeleteSelectionCommand(m_frame->document(), smartDelete));
    300 }
    301 
    302 void Editor::pasteAsPlainTextWithPasteboard(Pasteboard* pasteboard)
    303 {
    304     String text = pasteboard->plainText(m_frame);
    305     if (client() && client()->shouldInsertText(text, selectedRange().get(), EditorInsertActionPasted))
    306         replaceSelectionWithText(text, false, canSmartReplaceWithPasteboard(pasteboard));
    307 }
    308 
    309 void Editor::pasteWithPasteboard(Pasteboard* pasteboard, bool allowPlainText)
    310 {
    311     RefPtr<Range> range = selectedRange();
    312     bool chosePlainText;
    313     RefPtr<DocumentFragment> fragment = pasteboard->documentFragment(m_frame, range, allowPlainText, chosePlainText);
    314     if (fragment && shouldInsertFragment(fragment, range, EditorInsertActionPasted))
    315         replaceSelectionWithFragment(fragment, false, canSmartReplaceWithPasteboard(pasteboard), chosePlainText);
    316 }
    317 
    318 bool Editor::canSmartReplaceWithPasteboard(Pasteboard* pasteboard)
    319 {
    320     return client() && client()->smartInsertDeleteEnabled() && pasteboard->canSmartReplace();
    321 }
    322 
    323 bool Editor::shouldInsertFragment(PassRefPtr<DocumentFragment> fragment, PassRefPtr<Range> replacingDOMRange, EditorInsertAction givenAction)
    324 {
    325     if (!client())
    326         return false;
    327        
    328     Node* child = fragment->firstChild();
    329     if (child && fragment->lastChild() == child && child->isCharacterDataNode())
    330         return client()->shouldInsertText(static_cast<CharacterData*>(child)->data(), replacingDOMRange.get(), givenAction);
    331 
    332     return client()->shouldInsertNode(fragment.get(), replacingDOMRange.get(), givenAction);
    333 }
    334 
    335 void Editor::replaceSelectionWithFragment(PassRefPtr<DocumentFragment> fragment, bool selectReplacement, bool smartReplace, bool matchStyle)
    336 {
    337     if (m_frame->selectionController()->isNone() || !fragment)
    338         return;
    339    
    340     applyCommand(new ReplaceSelectionCommand(m_frame->document(), fragment, selectReplacement, smartReplace, matchStyle));
    341     revealSelectionAfterEditingOperation();
    342 }
    343 
    344 void Editor::replaceSelectionWithText(const String& text, bool selectReplacement, bool smartReplace)
    345 {
    346     replaceSelectionWithFragment(createFragmentFromText(selectedRange().get(), text), selectReplacement, smartReplace, true);
    347 }
    348 
    349 PassRefPtr<Range> Editor::selectedRange()
    350 {
    351     if (!m_frame)
    352         return 0;
    353     return m_frame->selectionController()->toRange();
    354 }
    355 
    356 bool Editor::shouldDeleteRange(Range* range) const
    357 {
    358     ExceptionCode ec;
    359     if (!range || range->collapsed(ec))
    360         return false;
    361    
    362     if (!canDeleteRange(range))
    363         return false;
    364 
    365     return client() && client()->shouldDeleteRange(range);
    366 }
    367 
    368 bool Editor::tryDHTMLCopy()
    369 {   
    370     if (m_frame->selectionController()->isInPasswordField())
    371         return false;
    372 
    373     // Must be done before oncopy adds types and data to the pboard,
    374     // also done for security, as it erases data from the last copy/paste.
    375     Pasteboard::generalPasteboard()->clear();
    376 
    377     return !dispatchCPPEvent(copyEvent, ClipboardWritable);
    378 }
    379 
    380 bool Editor::tryDHTMLCut()
    381 {
    382     if (m_frame->selectionController()->isInPasswordField())
    383         return false;
    384 
    385     // Must be done before oncut adds types and data to the pboard,
    386     // also done for security, as it erases data from the last copy/paste.
    387     Pasteboard::generalPasteboard()->clear();
    388 
    389     return !dispatchCPPEvent(cutEvent, ClipboardWritable);
    390 }
    391 
    392 bool Editor::tryDHTMLPaste()
    393 {
    394     return !dispatchCPPEvent(pasteEvent, ClipboardReadable);
    395 }
    396 
    397 void Editor::writeSelectionToPasteboard(Pasteboard* pasteboard)
    398 {
    399     pasteboard->writeSelection(selectedRange().get(), canSmartCopyOrDelete(), m_frame);
    400 }
    401 
    402 bool Editor::shouldInsertText(const String& text, Range* range, EditorInsertAction action) const
    403 {
    404     return client() && client()->shouldInsertText(text, range, action);
    405 }
    406 
    407 bool Editor::shouldShowDeleteInterface(HTMLElement* element) const
    408 {
    409     return client() && client()->shouldShowDeleteInterface(element);
    410 }
    411 
    412 void Editor::respondToChangedSelection(const Selection& oldSelection)
    413 {
    414     if (client())
    415         client()->respondToChangedSelection();
    416     m_deleteButtonController->respondToChangedSelection(oldSelection);
    417 }
    418 
    419 void Editor::respondToChangedContents(const Selection& endingSelection)
    420 {
    421     if (AXObjectCache::accessibilityEnabled()) {
    422         Node* node = endingSelection.start().node();
    423         if (node)
    424             m_frame->renderer()->document()->axObjectCache()->postNotification(node->renderer(), "AXValueChanged");
    425     }
    426    
    427     if (client())
    428         client()->respondToChangedContents(); 
    429 }
    430 
    431 const FontData* Editor::fontForSelection(bool& hasMultipleFonts) const
    432 {
    433 #if !PLATFORM(QT)
    434     hasMultipleFonts = false;
    435 
    436     if (!m_frame->selectionController()->isRange()) {
    437         Node* nodeToRemove;
    438         RenderStyle* style = m_frame->styleForSelectionStart(nodeToRemove); // sets nodeToRemove
    439 
    440         const FontData* result = 0;
    441         if (style)
    442             result = style->font().primaryFont();
    443        
    444         if (nodeToRemove) {
    445             ExceptionCode ec;
    446             nodeToRemove->remove(ec);
    447             ASSERT(ec == 0);
    448         }
    449 
    450         return result;
    451     }
    452 
    453     const FontData* font = 0;
    454 
    455     RefPtr<Range> range = m_frame->selectionController()->toRange();
    456     Node* startNode = range->editingStartPosition().node();
    457     if (startNode) {
    458         Node* pastEnd = range->pastEndNode();
    459         // In the loop below, n should eventually match pastEnd and not become nil, but we've seen at least one
    460         // unreproducible case where this didn't happen, so check for nil also.
    461         for (Node* n = startNode; n && n != pastEnd; n = n->traverseNextNode()) {
    462             RenderObject *renderer = n->renderer();
    463             if (!renderer)
    464                 continue;
    465             // FIXME: Are there any node types that have renderers, but that we should be skipping?
    466             const FontData* f = renderer->style()->font().primaryFont();
    467             if (!font)
    468                 font = f;
    469             else if (font != f) {
    470                 hasMultipleFonts = true;
    471                 break;
    472             }
    473         }
    474     }
    475 
    476     return font;
    477 #else
    478     return 0;
    479 #endif
    480 }
    481 
    482 Frame::TriState Editor::selectionUnorderedListState() const
    483 {
    484     if (m_frame->selectionController()->isCaret()) {
    485         Node* selectionNode = m_frame->selectionController()->selection().start().node();
    486         if (enclosingNodeWithTag(selectionNode, ulTag))
    487             return Frame::trueTriState;
    488     } else if (m_frame->selectionController()->isRange()) {
    489         Node* startNode = enclosingNodeWithTag(m_frame->selectionController()->selection().start().node(), ulTag);
    490         Node* endNode = enclosingNodeWithTag(m_frame->selectionController()->selection().end().node(), ulTag);
    491         if (startNode && endNode && startNode == endNode)
    492             return Frame::trueTriState;
    493     }
    494 
    495     return Frame::falseTriState;
    496 }
    497 
    498 Frame::TriState Editor::selectionOrderedListState() const
    499 {
    500     if (m_frame->selectionController()->isCaret()) {
    501         Node* selectionNode = m_frame->selectionController()->selection().start().node();
    502         if (enclosingNodeWithTag(selectionNode, olTag))
    503             return Frame::trueTriState;
    504     } else if (m_frame->selectionController()->isRange()) {
    505         Node* startNode = enclosingNodeWithTag(m_frame->selectionController()->selection().start().node(), olTag);
    506         Node* endNode = enclosingNodeWithTag(m_frame->selectionController()->selection().end().node(), olTag);
    507         if (startNode && endNode && startNode == endNode)
    508             return Frame::trueTriState;
    509     }
    510 
    511     return Frame::falseTriState;
    512 }
    513 
    514 PassRefPtr<Node> Editor::insertOrderedList()
    515 {
    516     if (!canEditRichly())
    517         return 0;
    518        
    519     RefPtr<Node> newList = InsertListCommand::insertList(m_frame->document(), InsertListCommand::OrderedList);
    520     revealSelectionAfterEditingOperation();
    521     return newList;
    522 }
    523 
    524 PassRefPtr<Node> Editor::insertUnorderedList()
    525 {
    526     if (!canEditRichly())
    527         return 0;
    528        
    529     RefPtr<Node> newList = InsertListCommand::insertList(m_frame->document(), InsertListCommand::UnorderedList);
    530     revealSelectionAfterEditingOperation();
    531     return newList;
    532 }
    533 
    534 bool Editor::canIncreaseSelectionListLevel()
    535 {
    536     return canEditRichly() && IncreaseSelectionListLevelCommand::canIncreaseSelectionListLevel(m_frame->document());
    537 }
    538 
    539 bool Editor::canDecreaseSelectionListLevel()
    540 {
    541     return canEditRichly() && DecreaseSelectionListLevelCommand::canDecreaseSelectionListLevel(m_frame->document());
    542 }
    543 
    544 PassRefPtr<Node> Editor::increaseSelectionListLevel()
    545 {
    546     if (!canEditRichly() || m_frame->selectionController()->isNone())
    547         return 0;
    548    
    549     RefPtr<Node> newList = IncreaseSelectionListLevelCommand::increaseSelectionListLevel(m_frame->document());
    550     revealSelectionAfterEditingOperation();
    551     return newList;
    552 }
    553 
    554 PassRefPtr<Node> Editor::increaseSelectionListLevelOrdered()
    555 {
    556     if (!canEditRichly() || m_frame->selectionController()->isNone())
    557         return 0;
    558    
    559     PassRefPtr<Node> newList = IncreaseSelectionListLevelCommand::increaseSelectionListLevelOrdered(m_frame->document());
    560     revealSelectionAfterEditingOperation();
    561     return newList;
    562 }
    563 
    564 PassRefPtr<Node> Editor::increaseSelectionListLevelUnordered()
    565 {
    566     if (!canEditRichly() || m_frame->selectionController()->isNone())
    567         return 0;
    568    
    569     PassRefPtr<Node> newList = IncreaseSelectionListLevelCommand::increaseSelectionListLevelUnordered(m_frame->document());
    570     revealSelectionAfterEditingOperation();
    571     return newList;
    572 }
    573 
    574 void Editor::decreaseSelectionListLevel()
    575 {
    576     if (!canEditRichly() || m_frame->selectionController()->isNone())
    577         return;
    578    
    579     DecreaseSelectionListLevelCommand::decreaseSelectionListLevel(m_frame->document());
    580     revealSelectionAfterEditingOperation();
    581 }
    582 
    583 void Editor::removeFormattingAndStyle()
    584 {
    585     applyCommand(new RemoveFormatCommand(m_frame->document()));
    586 }
    587 
    588 void Editor::setLastEditCommand(PassRefPtr<EditCommand> lastEditCommand)
    589 {
    590     m_lastEditCommand = lastEditCommand;
    591 }
    592 
    593 // Returns whether caller should continue with "the default processing", which is the same as
    594 // the event handler NOT setting the return value to false
    595 bool Editor::dispatchCPPEvent(const AtomicString &eventType, ClipboardAccessPolicy policy)
    596 {
    597     Node* target = m_frame->selectionController()->start().element();
    598     if (!target && m_frame->document())
    599         target = m_frame->document()->body();
    600     if (!target)
    601         return true;
    602     target = target->shadowAncestorNode();
    603    
    604     RefPtr<Clipboard> clipboard = newGeneralClipboard(policy);
    605 
    606     ExceptionCode ec = 0;
    607     RefPtr<Event> evt = new ClipboardEvent(eventType, true, true, clipboard.get());
    608     EventTargetNodeCast(target)->dispatchEvent(evt, ec, true);
    609     bool noDefaultProcessing = evt->defaultPrevented();
    610 
    611     // invalidate clipboard here for security
    612     clipboard->setAccessPolicy(ClipboardNumb);
    613    
    614     return !noDefaultProcessing;
    615 }
    616 
    617 void Editor::applyStyle(CSSStyleDeclaration* style, EditAction editingAction)
    618 {
    619     switch (m_frame->selectionController()->state()) {
    620         case Selection::NONE:
    621             // do nothing
    622             break;
    623         case Selection::CARET: {
    624             m_frame->computeAndSetTypingStyle(style, editingAction);
    625             break;
    626         }
    627         case Selection::RANGE:
    628             if (m_frame->document() && style)
    629                 applyCommand(new ApplyStyleCommand(m_frame->document(), style, editingAction));
    630             break;
    631     }
    632 }
    633    
    634 bool Editor::shouldApplyStyle(CSSStyleDeclaration* style, Range* range)
    635 {   
    636     return client()->shouldApplyStyle(style, range);
    637 }
    638    
    639 void Editor::applyParagraphStyle(CSSStyleDeclaration* style, EditAction editingAction)
    640 {
    641     switch (m_frame->selectionController()->state()) {
    642         case Selection::NONE:
    643             // do nothing
    644             break;
    645         case Selection::CARET:
    646         case Selection::RANGE:
    647             if (m_frame->document() && style)
    648                 applyCommand(new ApplyStyleCommand(m_frame->document(), style, editingAction, ApplyStyleCommand::ForceBlockProperties));
    649             break;
    650     }
    651 }
    652 
    653 void Editor::applyStyleToSelection(CSSStyleDeclaration* style, EditAction editingAction)
    654 {
    655     if (!style || style->length() == 0 || !canEditRichly())
    656         return;
    657 
    658     if (client() && client()->shouldApplyStyle(style, m_frame->selectionController()->toRange().get()))
    659         applyStyle(style, editingAction);
    660 }
    661 
    662 void Editor::applyParagraphStyleToSelection(CSSStyleDeclaration* style, EditAction editingAction)
    663 {
    664     if (!style || style->length() == 0 || !canEditRichly())
    665         return;
    666    
    667     if (client() && client()->shouldApplyStyle(style, m_frame->selectionController()->toRange().get()))
    668         applyParagraphStyle(style, editingAction);
    669 }
    670 
    671 bool Editor::clientIsEditable() const
    672 {
    673     return client() && client()->isEditable();
    674 }
    675 
    676 bool Editor::selectionStartHasStyle(CSSStyleDeclaration* style) const
    677 {
    678     Node* nodeToRemove;
    679     RefPtr<CSSStyleDeclaration> selectionStyle = m_frame->selectionComputedStyle(nodeToRemove);
    680     if (!selectionStyle)
    681         return false;
    682    
    683     RefPtr<CSSMutableStyleDeclaration> mutableStyle = style->makeMutable();
    684    
    685     bool match = true;
    686     DeprecatedValueListConstIterator<CSSProperty> end;
    687     for (DeprecatedValueListConstIterator<CSSProperty> it = mutableStyle->valuesIterator(); it != end; ++it) {
    688         int propertyID = (*it).id();
    689         if (!equalIgnoringCase(mutableStyle->getPropertyValue(propertyID), selectionStyle->getPropertyValue(propertyID))) {
    690             match = false;
    691             break;
    692         }
    693     }
    694    
    695     if (nodeToRemove) {
    696         ExceptionCode ec = 0;
    697         nodeToRemove->remove(ec);
    698         ASSERT(ec == 0);
    699     }
    700    
    701     return match;
    702 }
    703 
    704 void Editor::indent()
    705 {
    706     applyCommand(new IndentOutdentCommand(m_frame->document(), IndentOutdentCommand::Indent));
    707 }
    708 
    709 void Editor::outdent()
    710 {
    711     applyCommand(new IndentOutdentCommand(m_frame->document(), IndentOutdentCommand::Outdent));
    712 }
    713 
    714 static void dispatchEditableContentChangedEvents(const EditCommand& command)
    715 {
    716     Element* startRoot = command.startingRootEditableElement();
    717     Element* endRoot = command.endingRootEditableElement();
    718     ExceptionCode ec;
    719     if (startRoot)
    720         startRoot->dispatchEvent(new Event(webkitEditableContentChangedEvent, false, false), ec, true);
    721     if (endRoot && endRoot != startRoot)
    722         endRoot->dispatchEvent(new Event(webkitEditableContentChangedEvent, false, false), ec, true);
    723 }
    724 
    725 void Editor::appliedEditing(PassRefPtr<EditCommand> cmd)
    726 {
    727     dispatchEditableContentChangedEvents(*cmd);
    728    
    729     // FIXME: We shouldn't tell setSelection to clear the typing style or removed anchor here.
    730     // If we didn't, we wouldn't have to save/restore the removedAnchor, and we wouldn't have to have
    731     // the typing style stored in two places (the Frame and commands).
    732     RefPtr<Node> anchor = removedAnchor();
    733    
    734     Selection newSelection(cmd->endingSelection());
    735     // If there is no selection change, don't bother sending shouldChangeSelection, but still call setSelection,
    736     // because there is work that it must do in this situation.
    737     if (newSelection == m_frame->selectionController()->selection() || m_frame->shouldChangeSelection(newSelection))
    738         m_frame->selectionController()->setSelection(newSelection, false);
    739    
    740     setRemovedAnchor(anchor);
    741    
    742     // Now set the typing style from the command. Clear it when done.
    743     // This helps make the case work where you completely delete a piece
    744     // of styled text and then type a character immediately after.
    745     // That new character needs to take on the style of the just-deleted text.
    746     // FIXME: Improve typing style.
    747     // See this bug: <rdar://problem/3769899> Implementation of typing style needs improvement
    748     if (cmd->typingStyle()) {
    749         m_frame->setTypingStyle(cmd->typingStyle());
    750         cmd->setTypingStyle(0);
    751     }
    752    
    753     // Command will be equal to last edit command only in the case of typing
    754     if (m_lastEditCommand.get() == cmd)
    755         ASSERT(cmd->isTypingCommand());
    756     else {
    757         // Only register a new undo command if the command passed in is
    758         // different from the last command
    759         m_lastEditCommand = cmd;
    760         if (client())
    761             client()->registerCommandForUndo(m_lastEditCommand);
    762     }
    763     respondToChangedContents(newSelection);   
    764 }
    765 
    766 void Editor::unappliedEditing(PassRefPtr<EditCommand> cmd)
    767 {
    768     dispatchEditableContentChangedEvents(*cmd);
    769    
    770     Selection newSelection(cmd->startingSelection());
    771     // If there is no selection change, don't bother sending shouldChangeSelection, but still call setSelection,
    772     // because there is work that it must do in this situation.
    773     if (newSelection == m_frame->selectionController()->selection() || m_frame->shouldChangeSelection(newSelection))
    774         m_frame->selectionController()->setSelection(newSelection, true);
    775    
    776     m_lastEditCommand = 0;
    777     if (client())
    778         client()->registerCommandForRedo(cmd);
    779     respondToChangedContents(newSelection);   
    780 }
    781 
    782 void Editor::reappliedEditing(PassRefPtr<EditCommand> cmd)
    783 {
    784     dispatchEditableContentChangedEvents(*cmd);
    785    
    786     Selection newSelection(cmd->endingSelection());
    787     // If there is no selection change, don't bother sending shouldChangeSelection, but still call setSelection,
    788     // because there is work that it must do in this situation.
    789     if (newSelection == m_frame->selectionController()->selection() || m_frame->shouldChangeSelection(newSelection))
    790         m_frame->selectionController()->setSelection(newSelection, true);
    791    
    792     m_lastEditCommand = 0;
    793     if (client())
    794         client()->registerCommandForUndo(cmd);
    795     respondToChangedContents(newSelection);   
    796 }
    797 
    798 // Execute command functions
    799 
    800 static bool execCopy(Frame* frame, Event*)
    801 {
    802     frame->editor()->copy();
    803     return true;
    804 }
    805 
    806 static bool execCut(Frame* frame, Event*)
    807 {
    808     frame->editor()->cut();
    809     return true;
    810 }
    811 
    812 static bool execDelete(Frame* frame, Event*)
    813 {
    814     frame->editor()->performDelete();
    815     return true;
    816 }
    817 
    818 static bool execDeleteWordBackward(Frame* frame, Event*)
    819 {
    820     frame->editor()->deleteWithDirection(SelectionController::BACKWARD, WordGranularity, true, false);
    821     return true;
    822 }
    823 
    824 static bool execDeleteWordForward(Frame* frame, Event*)
    825 {
    826     frame->editor()->deleteWithDirection(SelectionController::FORWARD, WordGranularity, true, false);
    827     return true;
    828 }
    829 
    830 static bool execBackwardDelete(Frame* frame, Event*)
    831 {
    832     frame->editor()->deleteWithDirection(SelectionController::BACKWARD, CharacterGranularity, false, true);
    833     return true;
    834 }
    835 
    836 static bool execForwardDelete(Frame* frame, Event*)
    837 {
    838     frame->editor()->deleteWithDirection(SelectionController::FORWARD, CharacterGranularity, false, true);
    839     return true;
    840 }
    841 
    842 static bool execMoveBackward(Frame* frame, Event*)
    843 {
    844     frame->selectionController()->modify(SelectionController::MOVE, SelectionController::BACKWARD, CharacterGranularity, true);
    845     return true;
    846 }
    847 
    848 static bool execMoveBackwardAndModifySelection(Frame* frame, Event*)
    849 {
    850     frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::BACKWARD, CharacterGranularity, true);
    851     return true;
    852 }
    853 
    854 static bool execMoveUpByPageAndModifyCaret(Frame* frame, Event*)
    855 {
    856     RenderObject* renderer = frame->document()->focusedNode()->renderer();
    857     if (renderer->style()->overflowY() == OSCROLL
    858         || renderer->style()->overflowY() == OAUTO
    859         || renderer->isTextArea()) {
    860         int height = -(frame->document()->focusedNode()->renderer()->clientHeight()-PAGE_KEEP);
    861         bool handledScroll = renderer->scroll(ScrollUp, ScrollByPage);
    862         bool handledCaretMove = frame->selectionController()->modify(SelectionController::MOVE, height);
    863         return handledScroll || handledCaretMove;
    864     }
    865     return false;
    866 }
    867 
    868 static bool execMoveDown(Frame* frame, Event*)
    869 {
    870     frame->selectionController()->modify(SelectionController::MOVE, SelectionController::FORWARD, LineGranularity, true);
    871     return true;
    872 }
    873 
    874 static bool execMoveDownAndModifySelection(Frame* frame, Event*)
    875 {
    876     frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::FORWARD, LineGranularity, true);
    877     return true;
    878 }
    879 
    880 static bool execMoveForward(Frame* frame, Event*)
    881 {
    882     frame->selectionController()->modify(SelectionController::MOVE, SelectionController::FORWARD, CharacterGranularity, true);
    883     return true;
    884 }
    885 
    886 static bool execMoveForwardAndModifySelection(Frame* frame, Event*)
    887 {
    888     frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::FORWARD, CharacterGranularity, true);
    889     return true;
    890 }
    891 
    892 static bool execMoveDownByPageAndModifyCaret(Frame* frame, Event*)
    893 {
    894     RenderObject* renderer = frame->document()->focusedNode()->renderer();
    895     if (renderer->style()->overflowY() == OSCROLL
    896         || renderer->style()->overflowY() == OAUTO
    897         || renderer->isTextArea()) {
    898         int height = frame->document()->focusedNode()->renderer()->clientHeight()-PAGE_KEEP;
    899         bool handledScroll = renderer->scroll(ScrollDown, ScrollByPage);
    900         bool handledCaretMove = frame->selectionController()->modify(SelectionController::MOVE, height);
    901         return handledScroll || handledCaretMove;
    902     }
    903     return false;
    904 }
    905 
    906 static bool execMoveLeft(Frame* frame, Event*)
    907 {
    908     frame->selectionController()->modify(SelectionController::MOVE, SelectionController::LEFT, CharacterGranularity, true);
    909     return true;
    910 }
    911 
    912 static bool execMoveLeftAndModifySelection(Frame* frame, Event*)
    913 {
    914     frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::LEFT, CharacterGranularity, true);
    915     return true;
    916 }
    917 
    918 static bool execMoveRight(Frame* frame, Event*)
    919 {
    920     frame->selectionController()->modify(SelectionController::MOVE, SelectionController::RIGHT, CharacterGranularity, true);
    921     return true;
    922 }
    923 
    924 static bool execMoveRightAndModifySelection(Frame* frame, Event*)
    925 {
    926     frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::RIGHT, CharacterGranularity, true);
    927     return true;
    928 }
    929 
    930 static bool execMoveToBeginningOfDocument(Frame* frame, Event*)
    931 {
    932     frame->selectionController()->modify(SelectionController::MOVE, SelectionController::BACKWARD, DocumentBoundary, true);
    933     return true;
    934 }
    935 
    936 static bool execMoveToBeginningOfDocumentAndModifySelection(Frame* frame, Event*)
    937 {
    938     frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::BACKWARD, DocumentBoundary, true);
    939     return true;
    940 }
    941 
    942 static bool execMoveToBeginningOfSentence(Frame* frame, Event*)
    943 {
    944     frame->selectionController()->modify(SelectionController::MOVE, SelectionController::BACKWARD, SentenceBoundary, true);
    945     return true;
    946 }
    947 
    948 static bool execMoveToBeginningOfSentenceAndModifySelection(Frame* frame, Event*)
    949 {
    950     frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::BACKWARD, SentenceBoundary, true);
    951     return true;
    952 }
    953 
    954 static bool execMoveToBeginningOfLine(Frame* frame, Event*)
    955 {
    956     frame->selectionController()->modify(SelectionController::MOVE, SelectionController::BACKWARD, LineBoundary, true);
    957     return true;
    958 }
    959 
    960 static bool execMoveToBeginningOfLineAndModifySelection(Frame* frame, Event*)
    961 {
    962     frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::BACKWARD, LineBoundary, true);
    963     return true;
    964 }
    965 
    966 static bool execMoveToBeginningOfParagraph(Frame* frame, Event*)
    967 {
    968     frame->selectionController()->modify(SelectionController::MOVE, SelectionController::BACKWARD, ParagraphBoundary, true);
    969     return true;
    970 }
    971 
    972 static bool execMoveToBeginningOfParagraphAndModifySelection(Frame* frame, Event*)
    973 {
    974     frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::BACKWARD, ParagraphBoundary, true);
    975     return true;
    976 }
    977 
    978 static bool execMoveToEndOfDocument(Frame* frame, Event*)
    979 {
    980     frame->selectionController()->modify(SelectionController::MOVE, SelectionController::FORWARD, DocumentBoundary, true);
    981     return true;
    982 }
    983 
    984 static bool execMoveToEndOfDocumentAndModifySelection(Frame* frame, Event*)
    985 {
    986     frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::FORWARD, DocumentBoundary, true);
    987     return true;
    988 }
    989 
    990 static bool execMoveToEndOfSentence(Frame* frame, Event*)
    991 {
    992     frame->selectionController()->modify(SelectionController::MOVE, SelectionController::FORWARD, SentenceBoundary, true);
    993     return true;
    994 }
    995 
    996 static bool execMoveToEndOfSentenceAndModifySelection(Frame* frame, Event*)
    997 {
    998     frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::FORWARD, SentenceBoundary, true);
    999     return true;
    1000 }
    1001 
    1002 static bool execMoveToEndOfLine(Frame* frame, Event*)
    1003 {
    1004     frame->selectionController()->modify(SelectionController::MOVE, SelectionController::FORWARD, LineBoundary, true);
    1005     return true;
    1006 }
    1007 
    1008 static bool execMoveToEndOfLineAndModifySelection(Frame* frame, Event*)
    1009 {
    1010     frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::FORWARD, LineBoundary, true);
    1011     return true;
    1012 }
    1013 
    1014 static bool execMoveToEndOfParagraph(Frame* frame, Event*)
    1015 {
    1016     frame->selectionController()->modify(SelectionController::MOVE, SelectionController::FORWARD, ParagraphBoundary, true);
    1017     return true;
    1018 }
    1019 
    1020 static bool execMoveToEndOfParagraphAndModifySelection(Frame* frame, Event*)
    1021 {
    1022     frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::FORWARD, ParagraphBoundary, true);
    1023     return true;
    1024 }
    1025 
    1026 static bool execMoveParagraphBackwardAndModifySelection(Frame* frame, Event*)
    1027 {
    1028     frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::BACKWARD, ParagraphGranularity, true);
    1029     return true;
    1030 }
    1031 
    1032 static bool execMoveParagraphForwardAndModifySelection(Frame* frame, Event*)
    1033 {
    1034     frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::FORWARD, ParagraphGranularity, true);
    1035     return true;
    1036 }
    1037 
    1038 static bool execMoveUp(Frame* frame, Event*)
    1039 {
    1040     frame->selectionController()->modify(SelectionController::MOVE, SelectionController::BACKWARD, LineGranularity, true);
    1041     return true;
    1042 }
    1043 
    1044 static bool execMoveUpAndModifySelection(Frame* frame, Event*)
    1045 {
    1046     frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::BACKWARD, LineGranularity, true);
    1047     return true;
    1048 }
    1049 
    1050 static bool execMoveWordBackward(Frame* frame, Event*)
    1051 {
    1052     frame->selectionController()->modify(SelectionController::MOVE, SelectionController::BACKWARD, WordGranularity, true);
    1053     return true;
    1054 }
    1055 
    1056 static bool execMoveWordBackwardAndModifySelection(Frame* frame, Event*)
    1057 {
    1058     frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::BACKWARD, WordGranularity, true);
    1059     return true;
    1060 }
    1061 
    1062 static bool execMoveWordForward(Frame* frame, Event*)
    1063 {
    1064     frame->selectionController()->modify(SelectionController::MOVE, SelectionController::FORWARD, WordGranularity, true);
    1065     return true;
    1066 }
    1067 
    1068 static bool execMoveWordForwardAndModifySelection(Frame* frame, Event*)
    1069 {
    1070     frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::FORWARD, WordGranularity, true);
    1071     return true;
    1072 }
    1073 
    1074 static bool execMoveWordLeft(Frame* frame, Event*)
    1075 {
    1076     frame->selectionController()->modify(SelectionController::MOVE, SelectionController::LEFT, WordGranularity, true);
    1077     return true;
    1078 }
    1079 
    1080 static bool execMoveWordLeftAndModifySelection(Frame* frame, Event*)
    1081 {
    1082     frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::LEFT, WordGranularity, true);
    1083     return true;
    1084 }
    1085 
    1086 static bool execMoveWordRight(Frame* frame, Event*)
    1087 {
    1088     frame->selectionController()->modify(SelectionController::MOVE, SelectionController::RIGHT, WordGranularity, true);
    1089     return true;
    1090 }
    1091 
    1092 static bool execMoveWordRightAndModifySelection(Frame* frame, Event*)
    1093 {
    1094     frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::RIGHT, WordGranularity, true);
    1095     return true;
    1096 }
    1097 
    1098 static bool execPaste(Frame* frame, Event*)
    1099 {
    1100     frame->editor()->paste();
    1101     return true;
    1102 }
    1103 
    1104 static bool execSelectAll(Frame* frame, Event*)
    1105 {
    1106     frame->selectionController()->selectAll();
    1107     return true;
    1108 }
    1109 
    1110 static bool execToggleBold(Frame* frame, Event*)
    1111 {
    1112     ExceptionCode ec;
    1113    
    1114     RefPtr<CSSStyleDeclaration> style = frame->document()->createCSSStyleDeclaration();
    1115     style->setProperty(CSS_PROP_FONT_WEIGHT, "bold", false, ec);
    1116     if (frame->editor()->selectionStartHasStyle(style.get()))
    1117         style->setProperty(CSS_PROP_FONT_WEIGHT, "normal", false, ec);
    1118     frame->editor()->applyStyleToSelection(style.get(), EditActionSetFont);
    1119     return true;
    1120 }
    1121 
    1122 static bool execToggleItalic(Frame* frame, Event*)
    1123 {
    1124     ExceptionCode ec;
    1125    
    1126     RefPtr<CSSStyleDeclaration> style = frame->document()->createCSSStyleDeclaration();
    1127     style->setProperty(CSS_PROP_FONT_STYLE, "italic", false, ec);
    1128     if (frame->editor()->selectionStartHasStyle(style.get()))
    1129         style->setProperty(CSS_PROP_FONT_STYLE, "normal", false, ec);
    1130     frame->editor()->applyStyleToSelection(style.get(), EditActionSetFont);
    1131     return true;
    1132 }
    1133 
    1134 static bool execRedo(Frame* frame, Event*)
    1135 {
    1136     frame->editor()->redo();
    1137     return true;
    1138 }
    1139 
    1140 static bool execUndo(Frame* frame, Event*)
    1141 {
    1142     frame->editor()->undo();
    1143     return true;
    1144 }
    1145 
    1146 static bool execTranspose(Frame* frame, Event*)
    1147 {
    1148     frame->editor()->transpose();
    1149     return true;
    1150 }
    1151 
    1152 static inline Frame* targetFrame(Frame* frame, Event* evt)
    1153 {
    1154     Node* node = evt ? evt->target()->toNode() : 0;
     75        return frame;
     76    Node* node = event->target()->toNode();
    115577    if (!node)
    115678        return frame;
     
    115880}
    115981
    1160 static bool execInsertTab(Frame* frame, Event* evt)
    1161 {
    1162     return targetFrame(frame, evt)->eventHandler()->handleTextInputEvent("\t", evt, false, false);
    1163 }
    1164 
    1165 static bool execInsertBacktab(Frame* frame, Event* evt)
    1166 {
    1167     return targetFrame(frame, evt)->eventHandler()->handleTextInputEvent("\t", evt, false, true);
    1168 }
    1169 
    1170 static bool execInsertNewline(Frame* frame, Event* evt)
    1171 {
    1172     Frame* targetFrame = WebCore::targetFrame(frame, evt);
    1173     return targetFrame->eventHandler()->handleTextInputEvent("\n", evt, !targetFrame->editor()->canEditRichly());
    1174 }
    1175 
    1176 static bool execInsertLineBreak(Frame* frame, Event* evt)
    1177 {
    1178     return targetFrame(frame, evt)->eventHandler()->handleTextInputEvent("\n", evt, true);
     82static bool executeApplyStyle(Frame* frame, EditorCommandSource source, EditAction action, int propertyID, const String& propertyValue)
     83{
     84    RefPtr<CSSMutableStyleDeclaration> style = new CSSMutableStyleDeclaration;
     85    style->setProperty(propertyID, propertyValue);
     86    // FIXME: We don't call shouldApplyStyle when the source is DOM; is there a good reason for that?
     87    switch (source) {
     88        case CommandFromMenuOrKeyBinding:
     89            frame->editor()->applyStyleToSelection(style.get(), action);
     90            return true;
     91        case CommandFromDOM:
     92        case CommandFromDOMWithUserInterface:
     93            frame->editor()->applyStyle(style.get());
     94            return true;
     95    }
     96    ASSERT_NOT_REACHED();
     97    return false;
     98}
     99
     100static bool executeApplyStyle(Frame* frame, EditorCommandSource source, EditAction action, int propertyID, const char* propertyValue)
     101{
     102    return executeApplyStyle(frame, source, action, propertyID, String(propertyValue));
     103}
     104
     105static bool executeApplyStyle(Frame* frame, EditorCommandSource source, EditAction action, int propertyID, int propertyValue)
     106{
     107    RefPtr<CSSMutableStyleDeclaration> style = new CSSMutableStyleDeclaration;
     108    style->setProperty(propertyID, propertyValue);
     109    // FIXME: We don't call shouldApplyStyle when the source is DOM; is there a good reason for that?
     110    switch (source) {
     111        case CommandFromMenuOrKeyBinding:
     112            frame->editor()->applyStyleToSelection(style.get(), action);
     113            return true;
     114        case CommandFromDOM:
     115        case CommandFromDOMWithUserInterface:
     116            frame->editor()->applyStyle(style.get());
     117            return true;
     118    }
     119    ASSERT_NOT_REACHED();
     120    return false;
     121}
     122
     123static bool executeToggleStyle(Frame* frame, EditorCommandSource source, EditAction action, int propertyID, const char* offValue, const char* onValue)
     124{
     125    RefPtr<CSSMutableStyleDeclaration> style = new CSSMutableStyleDeclaration;
     126    style->setProperty(propertyID, onValue);
     127    style->setProperty(propertyID, frame->editor()->selectionStartHasStyle(style.get()) ? offValue : onValue);
     128    // FIXME: We don't call shouldApplyStyle when the source is DOM; is there a good reason for that?
     129    switch (source) {
     130        case CommandFromMenuOrKeyBinding:
     131            frame->editor()->applyStyleToSelection(style.get(), action);
     132            return true;
     133        case CommandFromDOM:
     134        case CommandFromDOMWithUserInterface:
     135            frame->editor()->applyStyle(style.get());
     136            return true;
     137    }
     138    ASSERT_NOT_REACHED();
     139    return false;
     140}
     141
     142static bool executeApplyParagraphStyle(Frame* frame, EditorCommandSource source, EditAction action, int propertyID, const String& propertyValue)
     143{
     144    RefPtr<CSSMutableStyleDeclaration> style = new CSSMutableStyleDeclaration;
     145    style->setProperty(propertyID, propertyValue);
     146    // FIXME: We don't call shouldApplyStyle when the source is DOM; is there a good reason for that?
     147    switch (source) {
     148        case CommandFromMenuOrKeyBinding:
     149            frame->editor()->applyParagraphStyleToSelection(style.get(), action);
     150            return true;
     151        case CommandFromDOM:
     152        case CommandFromDOMWithUserInterface:
     153            frame->editor()->applyParagraphStyle(style.get());
     154            return true;
     155    }
     156    ASSERT_NOT_REACHED();
     157    return false;
     158}
     159
     160static bool executeInsertFragment(Frame* frame, PassRefPtr<DocumentFragment> fragment)
     161{
     162    applyCommand(new ReplaceSelectionCommand(frame->document(), fragment,
     163        false, false, false, true, false, EditActionUnspecified));
     164    return true;
     165}
     166
     167static bool executeInsertNode(Frame* frame, PassRefPtr<Node> content)
     168{
     169    RefPtr<DocumentFragment> fragment = new DocumentFragment(frame->document());
     170    ExceptionCode ec = 0;
     171    fragment->appendChild(content, ec);
     172    if (ec)
     173        return false;
     174    return executeInsertFragment(frame, fragment.release());
     175}
     176
     177static TriState stateStyle(Frame* frame, int propertyID, const char* desiredValue)
     178{
     179    RefPtr<CSSMutableStyleDeclaration> style = new CSSMutableStyleDeclaration;
     180    style->setProperty(propertyID, desiredValue);
     181    return frame->editor()->selectionHasStyle(style.get());
     182}
     183
     184static String valueStyle(Frame* frame, int propertyID)
     185{
     186    return frame->selectionStartStylePropertyValue(propertyID);
     187}
     188
     189static bool canScroll(RenderObject* renderer)
     190{
     191    if (!renderer)
     192        return false;
     193    RenderStyle* style = renderer->style();
     194    if (!style)
     195        return false;
     196    return style->overflowY() == OSCROLL || style->overflowY() == OAUTO || renderer->isTextArea();
     197}
     198
     199static RefPtr<Range> unionDOMRanges(Range* a, Range* b)
     200{
     201    ExceptionCode ec = 0;
     202    Range* start = a->compareBoundaryPoints(Range::START_TO_START, b, ec) <= 0 ? a : b;
     203    ASSERT(!ec);
     204    Range* end = a->compareBoundaryPoints(Range::END_TO_END, b, ec) <= 0 ? b : a;
     205    ASSERT(!ec);
     206
     207    return new Range(a->startContainer(ec)->ownerDocument(), start->startContainer(ec), start->startOffset(ec), end->endContainer(ec), end->endOffset(ec));
     208}
     209
     210// Execute command functions
     211
     212static bool executeBackColor(Frame* frame, Event*, EditorCommandSource source, const String& value)
     213{
     214    return executeApplyStyle(frame, source, EditActionSetBackgroundColor, CSS_PROP_BACKGROUND_COLOR, value);
     215}
     216
     217static bool executeBackwardDelete(Frame* frame, Event*, EditorCommandSource, const String&)
     218{
     219    frame->editor()->deleteWithDirection(SelectionController::BACKWARD, CharacterGranularity, false, true);
     220    return true;
     221}
     222
     223static bool executeCopy(Frame* frame, Event*, EditorCommandSource, const String&)
     224{
     225    frame->editor()->copy();
     226    return true;
     227}
     228
     229static bool executeCreateLink(Frame* frame, Event*, EditorCommandSource, const String& value)
     230{
     231    // FIXME: If userInterface is true, we should display a dialog box to let the user enter a URL.
     232    if (value.isEmpty())
     233        return false;
     234    applyCommand(new CreateLinkCommand(frame->document(), value));
     235    return true;
     236}
     237
     238static bool executeCut(Frame* frame, Event*, EditorCommandSource, const String&)
     239{
     240    frame->editor()->cut();
     241    return true;
     242}
     243
     244static bool executeDelete(Frame* frame, Event*, EditorCommandSource source, const String&)
     245{
     246    // FIXME: Not sure there's a real reason to have this do something different when invoked from DOM.
     247    // At some point we should either merge these or remove this comment.
     248    switch (source) {
     249        case CommandFromMenuOrKeyBinding:
     250            frame->editor()->performDelete();
     251            return true;
     252        case CommandFromDOM:
     253        case CommandFromDOMWithUserInterface:
     254            TypingCommand::deleteKeyPressed(frame->document(), frame->selectionGranularity() == WordGranularity);
     255            return true;
     256    }
     257    ASSERT_NOT_REACHED();
     258    return false;
     259}
     260
     261static bool executeDeleteToMark(Frame* frame, Event*, EditorCommandSource, const String&)
     262{
     263    RefPtr<Range> mark = frame->mark().toRange();
     264    if (mark) {
     265        SelectionController* selectionController = frame->selectionController();
     266        bool selected = selectionController->setSelectedRange(unionDOMRanges(mark.get(), frame->editor()->selectedRange().get()).get(), DOWNSTREAM, true);
     267        ASSERT(selected);
     268        if (!selected)
     269            return false;
     270    }
     271    frame->editor()->performDelete();
     272    frame->setMark(frame->selectionController()->selection());
     273    return true;
     274}
     275
     276static bool executeDeleteWordBackward(Frame* frame, Event*, EditorCommandSource, const String&)
     277{
     278    frame->editor()->deleteWithDirection(SelectionController::BACKWARD, WordGranularity, true, false);
     279    return true;
     280}
     281
     282static bool executeDeleteWordForward(Frame* frame, Event*, EditorCommandSource, const String&)
     283{
     284    frame->editor()->deleteWithDirection(SelectionController::FORWARD, WordGranularity, true, false);
     285    return true;
     286}
     287
     288static bool executeFindString(Frame* frame, Event*, EditorCommandSource, const String& value)
     289{
     290    return frame->findString(value, true, false, true, false);
     291}
     292
     293static bool executeFontName(Frame* frame, Event*, EditorCommandSource source, const String& value)
     294{
     295    return executeApplyStyle(frame, source, EditActionSetFont, CSS_PROP_FONT_FAMILY, value);
     296}
     297
     298static bool executeFontSize(Frame* frame, Event*, EditorCommandSource source, const String& value)
     299{
     300    int size;
     301    if (!HTMLFontElement::cssValueFromFontSizeNumber(value, size))
     302        return false;
     303    return executeApplyStyle(frame, source, EditActionChangeAttributes, CSS_PROP_FONT_SIZE, size);
     304}
     305
     306static bool executeFontSizeDelta(Frame* frame, Event*, EditorCommandSource source, const String& value)
     307{
     308    return executeApplyStyle(frame, source, EditActionChangeAttributes, CSS_PROP__WEBKIT_FONT_SIZE_DELTA, value);
     309}
     310
     311static bool executeForeColor(Frame* frame, Event*, EditorCommandSource source, const String& value)
     312{
     313    return executeApplyStyle(frame, source, EditActionSetColor, CSS_PROP_COLOR, value);
     314}
     315
     316static bool executeFormatBlock(Frame* frame, Event*, EditorCommandSource, const String& value)
     317{
     318    String tagName = value.lower();
     319    if (tagName[0] == '<' && tagName[tagName.length() - 1] == '>')
     320        tagName = tagName.substring(1, tagName.length() - 2);
     321    if (!validBlockTag(tagName))
     322        return false;
     323    applyCommand(new FormatBlockCommand(frame->document(), tagName));
     324    return true;
     325}
     326
     327static bool executeForwardDelete(Frame* frame, Event*, EditorCommandSource source, const String&)
     328{
     329    // FIXME: Not sure there's a real reason to have this do something different when invoked from DOM.
     330    // At some point we should either merge these or remove this comment.
     331    switch (source) {
     332        case CommandFromMenuOrKeyBinding:
     333            frame->editor()->deleteWithDirection(SelectionController::FORWARD, CharacterGranularity, false, true);
     334            return true;
     335        case CommandFromDOM:
     336        case CommandFromDOMWithUserInterface:
     337            TypingCommand::forwardDeleteKeyPressed(frame->document());
     338            return true;
     339    }
     340    ASSERT_NOT_REACHED();
     341    return false;
     342}
     343
     344static bool executeIndent(Frame* frame, Event*, EditorCommandSource, const String&)
     345{
     346    applyCommand(new IndentOutdentCommand(frame->document(), IndentOutdentCommand::Indent));
     347    return true;
     348}
     349
     350static bool executeInsertBacktab(Frame* frame, Event* event, EditorCommandSource, const String&)
     351{
     352    return targetFrame(frame, event)->eventHandler()->handleTextInputEvent("\t", event, false, true);
     353}
     354
     355static bool executeInsertHorizontalRule(Frame* frame, Event*, EditorCommandSource, const String& value)
     356{
     357    RefPtr<HTMLElement> hr = new HTMLElement(hrTag, frame->document());
     358    if (!value.isEmpty())
     359        hr->setId(value);
     360    return executeInsertNode(frame, hr.release());
     361}
     362
     363static bool executeInsertHTML(Frame* frame, Event*, EditorCommandSource, const String& value)
     364{
     365    return executeInsertFragment(frame, createFragmentFromMarkup(frame->document(), value, ""));
     366}
     367
     368static bool executeInsertImage(Frame* frame, Event*, EditorCommandSource, const String& value)
     369{
     370    // FIXME: If userInterface is true, we should display a dialog box and let the user choose a local image.
     371    RefPtr<HTMLImageElement> image = new HTMLImageElement(imgTag, frame->document());
     372    image->setSrc(value);
     373    return executeInsertNode(frame, image.release());
     374}
     375
     376static bool executeInsertLineBreak(Frame* frame, Event* event, EditorCommandSource source, const String&)
     377{
     378    // FIXME: Not sure there's a real reason to have this do something different when invoked from DOM.
     379    // At some point we should either merge these or remove this comment.
     380    switch (source) {
     381        case CommandFromMenuOrKeyBinding:
     382            return targetFrame(frame, event)->eventHandler()->handleTextInputEvent("\n", event, true);
     383        case CommandFromDOM:
     384        case CommandFromDOMWithUserInterface:
     385            TypingCommand::insertLineBreak(frame->document());
     386            return true;
     387    }
     388    ASSERT_NOT_REACHED();
     389    return false;
     390}
     391
     392static bool executeInsertNewline(Frame* frame, Event* event, EditorCommandSource, const String&)
     393{
     394    Frame* targetFrame = WebCore::targetFrame(frame, event);
     395    return targetFrame->eventHandler()->handleTextInputEvent("\n", event, !targetFrame->editor()->canEditRichly());
     396}
     397
     398static bool executeInsertNewlineInQuotedContent(Frame* frame, Event*, EditorCommandSource, const String&)
     399{
     400    TypingCommand::insertParagraphSeparatorInQuotedContent(frame->document());
     401    return true;
     402}
     403
     404static bool executeInsertOrderedList(Frame* frame, Event*, EditorCommandSource, const String& value)
     405{
     406    applyCommand(new InsertListCommand(frame->document(), InsertListCommand::OrderedList, value));
     407    return true;
     408}
     409
     410static bool executeInsertParagraph(Frame* frame, Event*, EditorCommandSource, const String&)
     411{
     412    TypingCommand::insertParagraphSeparator(frame->document());
     413    return true;
     414}
     415
     416static bool executeInsertTab(Frame* frame, Event* event, EditorCommandSource, const String&)
     417{
     418    return targetFrame(frame, event)->eventHandler()->handleTextInputEvent("\t", event, false, false);
     419}
     420
     421static bool executeInsertText(Frame* frame, Event*, EditorCommandSource, const String& value)
     422{
     423    TypingCommand::insertText(frame->document(), value);
     424    return true;
     425}
     426
     427static bool executeInsertUnorderedList(Frame* frame, Event*, EditorCommandSource, const String& value)
     428{
     429    applyCommand(new InsertListCommand(frame->document(), InsertListCommand::UnorderedList, value));
     430    return true;
     431}
     432
     433static bool executeJustifyCenter(Frame* frame, Event*, EditorCommandSource source, const String&)
     434{
     435    return executeApplyParagraphStyle(frame, source, EditActionCenter, CSS_PROP_TEXT_ALIGN, "center");
     436}
     437
     438static bool executeJustifyFull(Frame* frame, Event*, EditorCommandSource source, const String&)
     439{
     440    return executeApplyParagraphStyle(frame, source, EditActionJustify, CSS_PROP_TEXT_ALIGN, "justify");
     441}
     442
     443static bool executeJustifyLeft(Frame* frame, Event*, EditorCommandSource source, const String&)
     444{
     445    return executeApplyParagraphStyle(frame, source, EditActionAlignLeft, CSS_PROP_TEXT_ALIGN, "left");
     446}
     447
     448static bool executeJustifyRight(Frame* frame, Event*, EditorCommandSource source, const String&)
     449{
     450    return executeApplyParagraphStyle(frame, source, EditActionAlignRight, CSS_PROP_TEXT_ALIGN, "right");
     451}
     452
     453static bool executeMoveBackward(Frame* frame, Event*, EditorCommandSource, const String&)
     454{
     455    frame->selectionController()->modify(SelectionController::MOVE, SelectionController::BACKWARD, CharacterGranularity, true);
     456    return true;
     457}
     458
     459static bool executeMoveBackwardAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&)
     460{
     461    frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::BACKWARD, CharacterGranularity, true);
     462    return true;
     463}
     464
     465static bool executeMoveDown(Frame* frame, Event*, EditorCommandSource, const String&)
     466{
     467    frame->selectionController()->modify(SelectionController::MOVE, SelectionController::FORWARD, LineGranularity, true);
     468    return true;
     469}
     470
     471static bool executeMoveDownAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&)
     472{
     473    frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::FORWARD, LineGranularity, true);
     474    return true;
     475}
     476
     477static bool executeMoveDownByPageAndModifyCaret(Frame* frame, Event*, EditorCommandSource, const String&)
     478{
     479    Node* focusedNode = frame->document()->focusedNode();
     480    if (!focusedNode)
     481        return false;
     482    RenderObject* renderer = focusedNode->renderer();
     483    if (!canScroll(renderer))
     484        return false;
     485    bool handledScroll = renderer->scroll(ScrollDown, ScrollByPage);
     486    bool handledCaretMove = frame->selectionController()->modify(SelectionController::MOVE, renderer->clientHeight() - PAGE_KEEP);
     487    return handledScroll || handledCaretMove;
     488}
     489
     490static bool executeMoveForward(Frame* frame, Event*, EditorCommandSource, const String&)
     491{
     492    frame->selectionController()->modify(SelectionController::MOVE, SelectionController::FORWARD, CharacterGranularity, true);
     493    return true;
     494}
     495
     496static bool executeMoveForwardAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&)
     497{
     498    frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::FORWARD, CharacterGranularity, true);
     499    return true;
     500}
     501
     502static bool executeMoveLeft(Frame* frame, Event*, EditorCommandSource, const String&)
     503{
     504    frame->selectionController()->modify(SelectionController::MOVE, SelectionController::LEFT, CharacterGranularity, true);
     505    return true;
     506}
     507
     508static bool executeMoveLeftAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&)
     509{
     510    frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::LEFT, CharacterGranularity, true);
     511    return true;
     512}
     513
     514static bool executeMoveRight(Frame* frame, Event*, EditorCommandSource, const String&)
     515{
     516    frame->selectionController()->modify(SelectionController::MOVE, SelectionController::RIGHT, CharacterGranularity, true);
     517    return true;
     518}
     519
     520static bool executeMoveRightAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&)
     521{
     522    frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::RIGHT, CharacterGranularity, true);
     523    return true;
     524}
     525
     526static bool executeMoveToBeginningOfDocument(Frame* frame, Event*, EditorCommandSource, const String&)
     527{
     528    frame->selectionController()->modify(SelectionController::MOVE, SelectionController::BACKWARD, DocumentBoundary, true);
     529    return true;
     530}
     531
     532static bool executeMoveToBeginningOfDocumentAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&)
     533{
     534    frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::BACKWARD, DocumentBoundary, true);
     535    return true;
     536}
     537
     538static bool executeMoveToBeginningOfLine(Frame* frame, Event*, EditorCommandSource, const String&)
     539{
     540    frame->selectionController()->modify(SelectionController::MOVE, SelectionController::BACKWARD, LineBoundary, true);
     541    return true;
     542}
     543
     544static bool executeMoveToBeginningOfLineAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&)
     545{
     546    frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::BACKWARD, LineBoundary, true);
     547    return true;
     548}
     549
     550static bool executeMoveToBeginningOfParagraph(Frame* frame, Event*, EditorCommandSource, const String&)
     551{
     552    frame->selectionController()->modify(SelectionController::MOVE, SelectionController::BACKWARD, ParagraphBoundary, true);
     553    return true;
     554}
     555
     556static bool executeMoveToBeginningOfParagraphAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&)
     557{
     558    frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::BACKWARD, ParagraphBoundary, true);
     559    return true;
     560}
     561
     562static bool executeMoveToBeginningOfSentence(Frame* frame, Event*, EditorCommandSource, const String&)
     563{
     564    frame->selectionController()->modify(SelectionController::MOVE, SelectionController::BACKWARD, SentenceBoundary, true);
     565    return true;
     566}
     567
     568static bool executeMoveToBeginningOfSentenceAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&)
     569{
     570    frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::BACKWARD, SentenceBoundary, true);
     571    return true;
     572}
     573
     574static bool executeMoveToEndOfDocument(Frame* frame, Event*, EditorCommandSource, const String&)
     575{
     576    frame->selectionController()->modify(SelectionController::MOVE, SelectionController::FORWARD, DocumentBoundary, true);
     577    return true;
     578}
     579
     580static bool executeMoveToEndOfDocumentAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&)
     581{
     582    frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::FORWARD, DocumentBoundary, true);
     583    return true;
     584}
     585
     586static bool executeMoveToEndOfSentence(Frame* frame, Event*, EditorCommandSource, const String&)
     587{
     588    frame->selectionController()->modify(SelectionController::MOVE, SelectionController::FORWARD, SentenceBoundary, true);
     589    return true;
     590}
     591
     592static bool executeMoveToEndOfSentenceAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&)
     593{
     594    frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::FORWARD, SentenceBoundary, true);
     595    return true;
     596}
     597
     598static bool executeMoveToEndOfLine(Frame* frame, Event*, EditorCommandSource, const String&)
     599{
     600    frame->selectionController()->modify(SelectionController::MOVE, SelectionController::FORWARD, LineBoundary, true);
     601    return true;
     602}
     603
     604static bool executeMoveToEndOfLineAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&)
     605{
     606    frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::FORWARD, LineBoundary, true);
     607    return true;
     608}
     609
     610static bool executeMoveToEndOfParagraph(Frame* frame, Event*, EditorCommandSource, const String&)
     611{
     612    frame->selectionController()->modify(SelectionController::MOVE, SelectionController::FORWARD, ParagraphBoundary, true);
     613    return true;
     614}
     615
     616static bool executeMoveToEndOfParagraphAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&)
     617{
     618    frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::FORWARD, ParagraphBoundary, true);
     619    return true;
     620}
     621
     622static bool executeMoveParagraphBackwardAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&)
     623{
     624    frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::BACKWARD, ParagraphGranularity, true);
     625    return true;
     626}
     627
     628static bool executeMoveParagraphForwardAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&)
     629{
     630    frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::FORWARD, ParagraphGranularity, true);
     631    return true;
     632}
     633
     634static bool executeMoveUp(Frame* frame, Event*, EditorCommandSource, const String&)
     635{
     636    frame->selectionController()->modify(SelectionController::MOVE, SelectionController::BACKWARD, LineGranularity, true);
     637    return true;
     638}
     639
     640static bool executeMoveUpAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&)
     641{
     642    frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::BACKWARD, LineGranularity, true);
     643    return true;
     644}
     645
     646static bool executeMoveUpByPageAndModifyCaret(Frame* frame, Event*, EditorCommandSource, const String&)
     647{
     648    Node* focusedNode = frame->document()->focusedNode();
     649    if (!focusedNode)
     650        return false;
     651    RenderObject* renderer = focusedNode->renderer();
     652    if (!canScroll(renderer))
     653        return false;
     654    bool handledScroll = renderer->scroll(ScrollDown, ScrollByPage);
     655    bool handledCaretMove = frame->selectionController()->modify(SelectionController::MOVE, -(renderer->clientHeight() - PAGE_KEEP));
     656    return handledScroll || handledCaretMove;
     657}
     658
     659static bool executeMoveWordBackward(Frame* frame, Event*, EditorCommandSource, const String&)
     660{
     661    frame->selectionController()->modify(SelectionController::MOVE, SelectionController::BACKWARD, WordGranularity, true);
     662    return true;
     663}
     664
     665static bool executeMoveWordBackwardAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&)
     666{
     667    frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::BACKWARD, WordGranularity, true);
     668    return true;
     669}
     670
     671static bool executeMoveWordForward(Frame* frame, Event*, EditorCommandSource, const String&)
     672{
     673    frame->selectionController()->modify(SelectionController::MOVE, SelectionController::FORWARD, WordGranularity, true);
     674    return true;
     675}
     676
     677static bool executeMoveWordForwardAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&)
     678{
     679    frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::FORWARD, WordGranularity, true);
     680    return true;
     681}
     682
     683static bool executeMoveWordLeft(Frame* frame, Event*, EditorCommandSource, const String&)
     684{
     685    frame->selectionController()->modify(SelectionController::MOVE, SelectionController::LEFT, WordGranularity, true);
     686    return true;
     687}
     688
     689static bool executeMoveWordLeftAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&)
     690{
     691    frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::LEFT, WordGranularity, true);
     692    return true;
     693}
     694
     695static bool executeMoveWordRight(Frame* frame, Event*, EditorCommandSource, const String&)
     696{
     697    frame->selectionController()->modify(SelectionController::MOVE, SelectionController::RIGHT, WordGranularity, true);
     698    return true;
     699}
     700
     701static bool executeMoveWordRightAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&)
     702{
     703    frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::RIGHT, WordGranularity, true);
     704    return true;
     705}
     706
     707static bool executeOutdent(Frame* frame, Event*, EditorCommandSource, const String&)
     708{
     709    applyCommand(new IndentOutdentCommand(frame->document(), IndentOutdentCommand::Outdent));
     710    return true;
     711}
     712
     713static bool executePaste(Frame* frame, Event*, EditorCommandSource, const String&)
     714{
     715    frame->editor()->paste();
     716    return true;
     717}
     718
     719static bool executePasteAndMatchStyle(Frame* frame, Event*, EditorCommandSource, const String&)
     720{
     721    frame->editor()->pasteAsPlainText();
     722    return true;
     723}
     724
     725static bool executePrint(Frame* frame, Event*, EditorCommandSource, const String&)
     726{
     727    Page* page = frame->page();
     728    if (!page)
     729        return false;
     730    page->chrome()->print(frame);
     731    return true;
     732}
     733
     734static bool executeRedo(Frame* frame, Event*, EditorCommandSource, const String&)
     735{
     736    frame->editor()->redo();
     737    return true;
     738}
     739
     740static bool executeRemoveFormat(Frame* frame, Event*, EditorCommandSource, const String&)
     741{
     742    frame->editor()->removeFormattingAndStyle();
     743    return true;
     744}
     745
     746static bool executeSelectAll(Frame* frame, Event*, EditorCommandSource, const String&)
     747{
     748    frame->selectionController()->selectAll();
     749    return true;
     750}
     751
     752static bool executeSelectToMark(Frame* frame, Event*, EditorCommandSource, const String&)
     753{
     754    RefPtr<Range> mark = frame->mark().toRange();
     755    RefPtr<Range> selection = frame->editor()->selectedRange();
     756    if (!mark || !selection) {
     757        systemBeep();
     758        return false;
     759    }
     760    frame->selectionController()->setSelectedRange(unionDOMRanges(mark.get(), selection.get()).get(), DOWNSTREAM, true);
     761    return true;
     762}
     763
     764static bool executeSetMark(Frame* frame, Event*, EditorCommandSource, const String&)
     765{
     766    frame->setMark(frame->selectionController()->selection());
     767    return true;
     768}
     769
     770static bool executeStrikethrough(Frame* frame, Event*, EditorCommandSource source, const String&)
     771{
     772    return executeToggleStyle(frame, source, EditActionChangeAttributes, CSS_PROP__WEBKIT_TEXT_DECORATIONS_IN_EFFECT, "none", "line-through");
     773}
     774
     775static bool executeSubscript(Frame* frame, Event*, EditorCommandSource source, const String&)
     776{
     777    return executeApplyStyle(frame, source, EditActionSubscript, CSS_PROP_VERTICAL_ALIGN, "sub");
     778}
     779
     780static bool executeSuperscript(Frame* frame, Event*, EditorCommandSource source, const String&)
     781{
     782    return executeApplyStyle(frame, source, EditActionSuperscript, CSS_PROP_VERTICAL_ALIGN, "super");
     783}
     784
     785static bool executeSwapWithMark(Frame* frame, Event*, EditorCommandSource, const String&)
     786{
     787    const Selection& mark = frame->mark();
     788    Selection selection = frame->selectionController()->selection();
     789    if (mark.isNone() || selection.isNone()) {
     790        systemBeep();
     791        return false;
     792    }
     793
     794    frame->selectionController()->setSelection(mark);
     795    frame->setMark(selection);
     796    return true;
     797}
     798
     799static bool executeToggleBold(Frame* frame, Event*, EditorCommandSource source, const String&)
     800{
     801    return executeToggleStyle(frame, source, EditActionChangeAttributes, CSS_PROP_FONT_WEIGHT, "normal", "bold");
     802}
     803
     804static bool executeToggleItalic(Frame* frame, Event*, EditorCommandSource source, const String&)
     805{
     806    return executeToggleStyle(frame, source, EditActionChangeAttributes, CSS_PROP_FONT_STYLE, "normal", "italic");
     807}
     808
     809static bool executeTranspose(Frame* frame, Event*, EditorCommandSource, const String&)
     810{
     811    frame->editor()->transpose();
     812    return true;
     813}
     814
     815static bool executeUnderline(Frame* frame, Event*, EditorCommandSource source, const String&)
     816{
     817    // FIXME: This currently clears overline, line-through, and blink as an unwanted side effect.
     818    return executeToggleStyle(frame, source, EditActionUnderline, CSS_PROP__WEBKIT_TEXT_DECORATIONS_IN_EFFECT, "none", "underline");
     819}
     820
     821static bool executeUndo(Frame* frame, Event*, EditorCommandSource, const String&)
     822{
     823    frame->editor()->undo();
     824    return true;
     825}
     826
     827static bool executeUnlink(Frame* frame, Event*, EditorCommandSource, const String&)
     828{
     829    applyCommand(new UnlinkCommand(frame->document()));
     830    return true;
     831}
     832
     833static bool executeUnscript(Frame* frame, Event*, EditorCommandSource source, const String&)
     834{
     835    return executeApplyStyle(frame, source, EditActionUnscript, CSS_PROP_VERTICAL_ALIGN, "baseline");
     836}
     837
     838static bool executeUnselect(Frame* frame, Event*, EditorCommandSource, const String&)
     839{
     840    frame->selectionController()->clear();
     841    return true;
     842}
     843
     844static bool executeYank(Frame* frame, Event*, EditorCommandSource, const String&)
     845{
     846    frame->editor()->insertTextWithoutSendingTextEvent(frame->editor()->yankFromKillRing(), false);
     847    frame->editor()->setKillRingToYankedState();
     848    return true;
     849}
     850
     851static bool executeYankAndSelect(Frame* frame, Event*, EditorCommandSource, const String&)
     852{
     853    frame->editor()->insertTextWithoutSendingTextEvent(frame->editor()->yankFromKillRing(), true);
     854    frame->editor()->setKillRingToYankedState();
     855    return true;
     856}
     857
     858// Supported functions
     859
     860static bool supported(Frame*, EditorCommandSource)
     861{
     862    return true;
     863}
     864
     865static bool supportedPaste(Frame* frame, EditorCommandSource source)
     866{
     867    switch (source) {
     868        case CommandFromMenuOrKeyBinding:
     869            return true;
     870        case CommandFromDOM:
     871        case CommandFromDOMWithUserInterface: {
     872            Settings* settings = frame ? frame->settings() : 0;
     873            return settings && settings->isDOMPasteAllowed();
     874        }
     875    }
     876    ASSERT_NOT_REACHED();
     877    return false;
    1179878}
    1180879
     
    1186885}
    1187886
    1188 static bool canPaste(Frame* frame, Event*)
     887static bool enabledAnySelection(Frame* frame, Event*)
     888{
     889    return frame->selectionController()->isCaretOrRange();
     890}
     891
     892static bool enabledAnySelectionAndMark(Frame* frame, Event*)
     893{
     894    return frame->selectionController()->isCaretOrRange() && frame->mark().isCaretOrRange();
     895}
     896
     897static bool enableCaretInEditableText(Frame* frame, Event* event)
     898{
     899    const Selection& selection = frame->editor()->selectionForCommand(event);
     900    return selection.isCaret() && selection.isContentEditable();
     901}
     902
     903static bool enabledCopy(Frame* frame, Event* source)
     904{
     905    return frame->editor()->canDHTMLCopy() || frame->editor()->canCopy();
     906}
     907
     908static bool enabledCut(Frame* frame, Event* source)
     909{
     910    return frame->editor()->canDHTMLCut() || frame->editor()->canCut();
     911}
     912
     913static bool enabledInEditableText(Frame* frame, Event* event)
     914{
     915    return frame->editor()->selectionForCommand(event).isContentEditable();
     916}
     917
     918static bool enabledInRichlyEditableText(Frame* frame, Event*)
     919{
     920    return frame->selectionController()->isCaretOrRange() && frame->selectionController()->isContentRichlyEditable();
     921}
     922
     923static bool enabledPaste(Frame* frame, Event*)
    1189924{
    1190925    return frame->editor()->canPaste();
    1191926}
    1192927
    1193 static bool hasEditableSelection(Frame* frame, Event* evt)
    1194 {
    1195     if (evt)
    1196         return selectionForEvent(frame, evt).isContentEditable();
    1197     return frame->selectionController()->isContentEditable();
    1198 }
    1199 
    1200 static bool hasEditableRangeSelection(Frame* frame, Event*)
     928static bool enabledRangeInEditableText(Frame* frame, Event*)
    1201929{
    1202930    return frame->selectionController()->isRange() && frame->selectionController()->isContentEditable();
    1203931}
    1204932
    1205 static bool hasRangeSelection(Frame* frame, Event*)
    1206 {
    1207     return frame->selectionController()->isRange();
    1208 }
    1209 
    1210 static bool hasRichlyEditableSelection(Frame* frame, Event*)
    1211 {
    1212     return frame->selectionController()->isCaretOrRange() && frame->selectionController()->isContentRichlyEditable();
    1213 }
    1214 
    1215 static bool canRedo(Frame* frame, Event*)
     933static bool enabledRangeInRichlyEditableText(Frame* frame, Event*)
     934{
     935    return frame->selectionController()->isRange() && frame->selectionController()->isContentRichlyEditable();
     936}
     937
     938static bool enabledRedo(Frame* frame, Event*)
    1216939{
    1217940    return frame->editor()->canRedo();
    1218941}
    1219942
    1220 static bool canUndo(Frame* frame, Event*)
     943static bool enabledUndo(Frame* frame, Event*)
    1221944{
    1222945    return frame->editor()->canUndo();
    1223946}
    1224947
    1225 struct Command {
    1226     bool (*enabled)(Frame*, Event*);
    1227     bool (*exec)(Frame*, Event*);
    1228 };
    1229 
    1230 typedef HashMap<RefPtr<AtomicStringImpl>, const Command*> CommandMap;
    1231 
    1232 static CommandMap* createCommandMap()
    1233 {
    1234     struct CommandEntry { const char* name; Command command; };
     948// State functions
     949
     950static TriState stateNone(Frame*, Event*)
     951{
     952    return FalseTriState;
     953}
     954
     955static TriState stateBold(Frame* frame, Event*)
     956{
     957    return stateStyle(frame, CSS_PROP_FONT_WEIGHT, "bold");
     958}
     959
     960static TriState stateItalic(Frame* frame, Event*)
     961{
     962    return stateStyle(frame, CSS_PROP_FONT_STYLE, "italic");
     963}
     964
     965static TriState stateOrderedList(Frame* frame, Event*)
     966{
     967    return frame->editor()->selectionOrderedListState();
     968}
     969
     970static TriState stateStrikethrough(Frame* frame, Event*)
     971{
     972    return stateStyle(frame, CSS_PROP_TEXT_DECORATION, "line-through");
     973}
     974
     975static TriState stateSubscript(Frame* frame, Event*)
     976{
     977    return stateStyle(frame, CSS_PROP_VERTICAL_ALIGN, "sub");
     978}
     979
     980static TriState stateSuperscript(Frame* frame, Event*)
     981{
     982    return stateStyle(frame, CSS_PROP_VERTICAL_ALIGN, "super");
     983}
     984
     985static TriState stateUnderline(Frame* frame, Event*)
     986{
     987    return stateStyle(frame, CSS_PROP_TEXT_DECORATION, "underline");
     988}
     989
     990static TriState stateUnorderedList(Frame* frame, Event*)
     991{
     992    return frame->editor()->selectionUnorderedListState();
     993}
     994
     995// Value functions
     996
     997static String valueNull(Frame*, Event*)
     998{
     999    return String();
     1000}
     1001
     1002String valueBackColor(Frame* frame, Event*)
     1003{
     1004    return valueStyle(frame, CSS_PROP_BACKGROUND_COLOR);
     1005}
     1006
     1007String valueFontName(Frame* frame, Event*)
     1008{
     1009    return valueStyle(frame, CSS_PROP_FONT_FAMILY);
     1010}
     1011
     1012String valueFontSize(Frame* frame, Event*)
     1013{
     1014    return valueStyle(frame, CSS_PROP_FONT_SIZE);
     1015}
     1016
     1017String valueFontSizeDelta(Frame* frame, Event*)
     1018{
     1019    return valueStyle(frame, CSS_PROP__WEBKIT_FONT_SIZE_DELTA);
     1020}
     1021
     1022String valueForeColor(Frame* frame, Event*)
     1023{
     1024    return valueStyle(frame, CSS_PROP_COLOR);
     1025}
     1026
     1027// Map of functions
     1028
     1029static const CommandMap& createCommandMap()
     1030{
     1031    struct CommandEntry { const char* name; EditorInternalCommand command; };
    12351032   
    12361033    static const CommandEntry commands[] = {
    1237         { "BackwardDelete", { hasEditableSelection, execBackwardDelete } },
    1238         { "Copy", { hasRangeSelection, execCopy } },
    1239         { "Cut", { hasEditableRangeSelection, execCut } },
    1240         { "Delete", { hasEditableSelection, execDelete } },
    1241         { "DeleteWordBackward", { hasEditableSelection, execDeleteWordBackward } },
    1242         { "DeleteWordForward", { hasEditableSelection, execDeleteWordForward} },
    1243         { "ForwardDelete", { hasEditableSelection, execForwardDelete } },
    1244         { "InsertBacktab", { hasEditableSelection, execInsertBacktab } },
    1245         { "InsertTab", { hasEditableSelection, execInsertTab } },
    1246         { "InsertLineBreak", { hasEditableSelection, execInsertLineBreak } },       
    1247         { "InsertNewline", { hasEditableSelection, execInsertNewline } },       
    1248         { "MoveBackward", { hasEditableSelection, execMoveBackward } },
    1249         { "MoveBackwardAndModifySelection", { hasEditableSelection, execMoveBackwardAndModifySelection } },
    1250         { "MoveUpByPageAndModifyCaret", { hasEditableSelection, execMoveUpByPageAndModifyCaret } },
    1251         { "MoveDown", { hasEditableSelection, execMoveDown } },
    1252         { "MoveDownAndModifySelection", { hasEditableSelection, execMoveDownAndModifySelection } },
    1253         { "MoveForward", { hasEditableSelection, execMoveForward } },
    1254         { "MoveForwardAndModifySelection", { hasEditableSelection, execMoveForwardAndModifySelection } },
    1255         { "MoveDownByPageAndModifyCaret", { hasEditableSelection, execMoveDownByPageAndModifyCaret } },
    1256         { "MoveLeft", { hasEditableSelection, execMoveLeft } },
    1257         { "MoveLeftAndModifySelection", { hasEditableSelection, execMoveLeftAndModifySelection } },
    1258         { "MoveRight", { hasEditableSelection, execMoveRight } },
    1259         { "MoveRightAndModifySelection", { hasEditableSelection, execMoveRightAndModifySelection } },
    1260         { "MoveToBeginningOfDocument", { hasEditableSelection, execMoveToBeginningOfDocument } },
    1261         { "MoveToBeginningOfDocumentAndModifySelection", { hasEditableSelection, execMoveToBeginningOfDocumentAndModifySelection } },
    1262         { "MoveToBeginningOfSentence", { hasEditableSelection, execMoveToBeginningOfSentence } },
    1263         { "MoveToBeginningOfSentenceAndModifySelection", { hasEditableSelection, execMoveToBeginningOfSentenceAndModifySelection } },
    1264         { "MoveToBeginningOfLine", { hasEditableSelection, execMoveToBeginningOfLine } },
    1265         { "MoveToBeginningOfLineAndModifySelection", { hasEditableSelection, execMoveToBeginningOfLineAndModifySelection } },
    1266         { "MoveToBeginningOfParagraph", { hasEditableSelection, execMoveToBeginningOfParagraph } },
    1267         { "MoveToBeginningOfParagraphAndModifySelection", { hasEditableSelection, execMoveToBeginningOfParagraphAndModifySelection } },
    1268         { "MoveToEndOfDocument", { hasEditableSelection, execMoveToEndOfDocument } },
    1269         { "MoveToEndOfDocumentAndModifySelection", { hasEditableSelection, execMoveToEndOfDocumentAndModifySelection } },
    1270         { "MoveToEndOfSentence", { hasEditableSelection, execMoveToEndOfSentence } },
    1271         { "MoveToEndOfSentenceAndModifySelection", { hasEditableSelection, execMoveToEndOfSentenceAndModifySelection } },
    1272         { "MoveToEndOfLine", { hasEditableSelection, execMoveToEndOfLine } },
    1273         { "MoveToEndOfLineAndModifySelection", { hasEditableSelection, execMoveToEndOfLineAndModifySelection } },
    1274         { "MoveToEndOfParagraph", { hasEditableSelection, execMoveToEndOfParagraph } },
    1275         { "MoveToEndOfParagraphAndModifySelection", { hasEditableSelection, execMoveToEndOfParagraphAndModifySelection } },
    1276         { "MoveParagraphBackwardAndModifySelection", { hasEditableSelection, execMoveParagraphBackwardAndModifySelection } },
    1277         { "MoveParagraphForwardAndModifySelection", { hasEditableSelection, execMoveParagraphForwardAndModifySelection } },
    1278         { "MoveUp", { hasEditableSelection, execMoveUp } },
    1279         { "MoveUpAndModifySelection", { hasEditableSelection, execMoveUpAndModifySelection } },
    1280         { "MoveWordBackward", { hasEditableSelection, execMoveWordBackward } },
    1281         { "MoveWordBackwardAndModifySelection", { hasEditableSelection, execMoveWordBackwardAndModifySelection } },
    1282         { "MoveWordForward", { hasEditableSelection, execMoveWordForward } },
    1283         { "MoveWordForwardAndModifySelection", { hasEditableSelection, execMoveWordForwardAndModifySelection } },
    1284         { "MoveWordLeft", { hasEditableSelection, execMoveWordLeft } },
    1285         { "MoveWordLeftAndModifySelection", { hasEditableSelection, execMoveWordLeftAndModifySelection } },
    1286         { "MoveWordRight", { hasEditableSelection, execMoveWordRight } },
    1287         { "MoveWordRightAndModifySelection", { hasEditableSelection, execMoveWordRightAndModifySelection } },
    1288         { "Paste", { canPaste, execPaste } },
    1289         { "Redo", { canRedo, execRedo } },
    1290         { "SelectAll", { enabled, execSelectAll } },
    1291         { "ToggleBold", { hasRichlyEditableSelection, execToggleBold } },
    1292         { "ToggleItalic", { hasRichlyEditableSelection, execToggleItalic } },
    1293         { "Transpose", { hasEditableSelection, execTranspose } },
    1294         { "Undo", { canUndo, execUndo } }
     1034        { "AlignCenter", { executeJustifyCenter, supported, enabledInRichlyEditableText, stateNone, valueNull, notTextInsertion } },
     1035        { "AlignJustified", { executeJustifyFull, supported, enabledInRichlyEditableText, stateNone, valueNull, notTextInsertion } },
     1036        { "AlignLeft", { executeJustifyLeft, supported, enabledInRichlyEditableText, stateNone, valueNull, notTextInsertion } },
     1037        { "AlignRight", { executeJustifyRight, supported, enabledInRichlyEditableText, stateNone, valueNull, notTextInsertion } },
     1038        { "BackColor", { executeBackColor, supported, enabledRangeInRichlyEditableText, stateNone, valueBackColor, notTextInsertion } },
     1039        { "BackwardDelete", { executeBackwardDelete, supported, enabledInEditableText, stateNone, valueNull, notTextInsertion } },
     1040        { "Bold", { executeToggleBold, supported, enabledInRichlyEditableText, stateBold, valueNull, notTextInsertion } },
     1041        { "Copy", { executeCopy, supported, enabledCopy, stateNone, valueNull, notTextInsertion } },
     1042        { "CreateLink", { executeCreateLink, supported, enabledInRichlyEditableText, stateNone, valueNull, notTextInsertion } },
     1043        { "Cut", { executeCut, supported, enabledCut, stateNone, valueNull, notTextInsertion } },
     1044        { "Delete", { executeDelete, supported, enabledInEditableText, stateNone, valueNull, notTextInsertion } },
     1045        { "DeleteToMark", { executeDeleteToMark, supported, enabledInEditableText, stateNone, valueNull, notTextInsertion } },
     1046        { "DeleteWordBackward", { executeDeleteWordBackward, supported, enabledInEditableText, stateNone, valueNull, notTextInsertion } },
     1047        { "DeleteWordForward", { executeDeleteWordForward, supported, enabledInEditableText, stateNone, valueNull, notTextInsertion } },
     1048        { "FindString", { executeFindString, supported, enabled, stateNone, valueNull, notTextInsertion } },
     1049        { "FontName", { executeFontName, supported, enabledInEditableText, stateNone, valueFontName, notTextInsertion } },
     1050        { "FontSize", { executeFontSize, supported, enabledInEditableText, stateNone, valueFontSize, notTextInsertion } },
     1051        { "FontSizeDelta", { executeFontSizeDelta, supported, enabledInEditableText, stateNone, valueFontSizeDelta, notTextInsertion } },
     1052        { "ForeColor", { executeForeColor, supported, enabledInEditableText, stateNone, valueForeColor, notTextInsertion } },
     1053        { "FormatBlock", { executeFormatBlock, supported, enabledInRichlyEditableText, stateNone, valueNull, notTextInsertion } },
     1054        { "ForwardDelete", { executeForwardDelete, supported, enabledInEditableText, stateNone, valueNull, notTextInsertion } },
     1055        { "HiliteColor", { executeBackColor, supported, enabledInRichlyEditableText, stateNone, valueNull, notTextInsertion } },
     1056        { "Indent", { executeIndent, supported, enabledInRichlyEditableText, stateNone, valueNull, notTextInsertion } },
     1057        { "InsertBacktab", { executeInsertBacktab, supported, enabledInEditableText, stateNone, valueNull, isTextInsertion } },
     1058        { "InsertHTML", { executeInsertHTML, supported, enabledInEditableText, stateNone, valueNull, notTextInsertion } },
     1059        { "InsertHorizontalRule", { executeInsertHorizontalRule, supported, enabledInRichlyEditableText, stateNone, valueNull, notTextInsertion } },
     1060        { "InsertImage", { executeInsertImage, supported, enabledInRichlyEditableText, stateNone, valueNull, notTextInsertion } },
     1061        { "InsertLineBreak", { executeInsertLineBreak, supported, enabledInEditableText, stateNone, valueNull, isTextInsertion } },
     1062        { "InsertNewline", { executeInsertNewline, supported, enabledInEditableText, stateNone, valueNull, isTextInsertion } },   
     1063        { "InsertNewlineInQuotedContent", { executeInsertNewlineInQuotedContent, supported, enabledInRichlyEditableText, stateNone, valueNull, notTextInsertion } },
     1064        { "InsertOrderedList", { executeInsertOrderedList, supported, enabledInRichlyEditableText, stateOrderedList, valueNull, notTextInsertion } },
     1065        { "InsertParagraph", { executeInsertParagraph, supported, enabledInEditableText, stateNone, valueNull, notTextInsertion } },
     1066        { "InsertTab", { executeInsertTab, supported, enabledInEditableText, stateNone, valueNull, isTextInsertion } },
     1067        { "InsertText", { executeInsertText, supported, enabledInEditableText, stateNone, valueNull, notTextInsertion } },
     1068        { "InsertUnorderedList", { executeInsertUnorderedList, supported, enabledInRichlyEditableText, stateUnorderedList, valueNull, notTextInsertion } },
     1069        { "Italic", { executeToggleItalic, supported, enabledInRichlyEditableText, stateItalic, valueNull, notTextInsertion } },
     1070        { "JustifyCenter", { executeJustifyCenter, supported, enabledInRichlyEditableText, stateNone, valueNull, notTextInsertion } },
     1071        { "JustifyFull", { executeJustifyFull, supported, enabledInRichlyEditableText, stateNone, valueNull, notTextInsertion } },
     1072        { "JustifyLeft", { executeJustifyLeft, supported, enabledInRichlyEditableText, stateNone, valueNull, notTextInsertion } },
     1073        { "JustifyNone", { executeJustifyLeft, supported, enabledInRichlyEditableText, stateNone, valueNull, notTextInsertion } },
     1074        { "JustifyRight", { executeJustifyRight, supported, enabledInRichlyEditableText, stateNone, valueNull, notTextInsertion } },
     1075        { "MoveBackward", { executeMoveBackward, supported, enabledInEditableText, stateNone, valueNull, notTextInsertion } },
     1076        { "MoveBackwardAndModifySelection", { executeMoveBackwardAndModifySelection, supported, enabledInEditableText, stateNone, valueNull, notTextInsertion } },
     1077        { "MoveDown", { executeMoveDown, supported, enabledInEditableText, stateNone, valueNull, notTextInsertion } },
     1078        { "MoveDownAndModifySelection", { executeMoveDownAndModifySelection, supported, enabledInEditableText, stateNone, valueNull, notTextInsertion } },
     1079        { "MoveDownByPageAndModifyCaret", { executeMoveDownByPageAndModifyCaret, supported, enabledInEditableText, stateNone, valueNull, notTextInsertion } },
     1080        { "MoveForward", { executeMoveForward, supported, enabledInEditableText, stateNone, valueNull, notTextInsertion } },
     1081        { "MoveForwardAndModifySelection", { executeMoveForwardAndModifySelection, supported, enabledInEditableText, stateNone, valueNull, notTextInsertion } },
     1082        { "MoveLeft", { executeMoveLeft, supported, enabledInEditableText, stateNone, valueNull, notTextInsertion } },
     1083        { "MoveLeftAndModifySelection", { executeMoveLeftAndModifySelection, supported, enabledInEditableText, stateNone, valueNull, notTextInsertion } },
     1084        { "MoveParagraphBackwardAndModifySelection", { executeMoveParagraphBackwardAndModifySelection, supported, enabledInEditableText, stateNone, valueNull, notTextInsertion } },
     1085        { "MoveParagraphForwardAndModifySelection", { executeMoveParagraphForwardAndModifySelection, supported, enabledInEditableText, stateNone, valueNull, notTextInsertion } },
     1086        { "MoveRight", { executeMoveRight, supported, enabledInEditableText, stateNone, valueNull, notTextInsertion } },
     1087        { "MoveRightAndModifySelection", { executeMoveRightAndModifySelection, supported, enabledInEditableText, stateNone, valueNull, notTextInsertion } },
     1088        { "MoveToBeginningOfDocument", { executeMoveToBeginningOfDocument, supported, enabledInEditableText, stateNone, valueNull, notTextInsertion } },
     1089        { "MoveToBeginningOfDocumentAndModifySelection", { executeMoveToBeginningOfDocumentAndModifySelection, supported, enabledInEditableText, stateNone, valueNull, notTextInsertion } },
     1090        { "MoveToBeginningOfLine", { executeMoveToBeginningOfLine, supported, enabledInEditableText, stateNone, valueNull, notTextInsertion } },
     1091        { "MoveToBeginningOfLineAndModifySelection", { executeMoveToBeginningOfLineAndModifySelection, supported, enabledInEditableText, stateNone, valueNull, notTextInsertion } },
     1092        { "MoveToBeginningOfParagraph", { executeMoveToBeginningOfParagraph, supported, enabledInEditableText, stateNone, valueNull, notTextInsertion } },
     1093        { "MoveToBeginningOfParagraphAndModifySelection", { executeMoveToBeginningOfParagraphAndModifySelection, supported, enabledInEditableText, stateNone, valueNull, notTextInsertion } },
     1094        { "MoveToBeginningOfSentence", { executeMoveToBeginningOfSentence, supported, enabledInEditableText, stateNone, valueNull, notTextInsertion } },
     1095        { "MoveToBeginningOfSentenceAndModifySelection", { executeMoveToBeginningOfSentenceAndModifySelection, supported, enabledInEditableText, stateNone, valueNull, notTextInsertion } },
     1096        { "MoveToEndOfDocument", { executeMoveToEndOfDocument, supported, enabledInEditableText, stateNone, valueNull, notTextInsertion } },
     1097        { "MoveToEndOfDocumentAndModifySelection", { executeMoveToEndOfDocumentAndModifySelection, supported, enabledInEditableText, stateNone, valueNull, notTextInsertion } },
     1098        { "MoveToEndOfLine", { executeMoveToEndOfLine, supported, enabledInEditableText, stateNone, valueNull, notTextInsertion } },
     1099        { "MoveToEndOfLineAndModifySelection", { executeMoveToEndOfLineAndModifySelection, supported, enabledInEditableText, stateNone, valueNull, notTextInsertion } },
     1100        { "MoveToEndOfParagraph", { executeMoveToEndOfParagraph, supported, enabledInEditableText, stateNone, valueNull, notTextInsertion } },
     1101        { "MoveToEndOfParagraphAndModifySelection", { executeMoveToEndOfParagraphAndModifySelection, supported, enabledInEditableText, stateNone, valueNull, notTextInsertion } },
     1102        { "MoveToEndOfSentence", { executeMoveToEndOfSentence, supported, enabledInEditableText, stateNone, valueNull, notTextInsertion } },
     1103        { "MoveToEndOfSentenceAndModifySelection", { executeMoveToEndOfSentenceAndModifySelection, supported, enabledInEditableText, stateNone, valueNull, notTextInsertion } },
     1104        { "MoveUp", { executeMoveUp, supported, enabledInEditableText, stateNone, valueNull, notTextInsertion } },
     1105        { "MoveUpAndModifySelection", { executeMoveUpAndModifySelection, supported, enabledInEditableText, stateNone, valueNull, notTextInsertion } },
     1106        { "MoveUpByPageAndModifyCaret", { executeMoveUpByPageAndModifyCaret, supported, enabledInEditableText, stateNone, valueNull, notTextInsertion } },
     1107        { "MoveWordBackward", { executeMoveWordBackward, supported, enabledInEditableText, stateNone, valueNull, notTextInsertion } },
     1108        { "MoveWordBackwardAndModifySelection", { executeMoveWordBackwardAndModifySelection, supported, enabledInEditableText, stateNone, valueNull, notTextInsertion } },
     1109        { "MoveWordForward", { executeMoveWordForward, supported, enabledInEditableText, stateNone, valueNull, notTextInsertion } },
     1110        { "MoveWordForwardAndModifySelection", { executeMoveWordForwardAndModifySelection, supported, enabledInEditableText, stateNone, valueNull, notTextInsertion } },
     1111        { "MoveWordLeft", { executeMoveWordLeft, supported, enabledInEditableText, stateNone, valueNull, notTextInsertion } },
     1112        { "MoveWordLeftAndModifySelection", { executeMoveWordLeftAndModifySelection, supported, enabledInEditableText, stateNone, valueNull, notTextInsertion } },
     1113        { "MoveWordRight", { executeMoveWordRight, supported, enabledInEditableText, stateNone, valueNull, notTextInsertion } },
     1114        { "MoveWordRightAndModifySelection", { executeMoveWordRightAndModifySelection, supported, enabledInEditableText, stateNone, valueNull, notTextInsertion } },
     1115        { "Outdent", { executeOutdent, supported, enabledInRichlyEditableText, stateNone, valueNull, notTextInsertion } },
     1116        { "Paste", { executePaste, supportedPaste, enabledPaste, stateNone, valueNull, notTextInsertion } },
     1117        { "PasteAndMatchStyle", { executePasteAndMatchStyle, supportedPaste, enabledPaste, stateNone, valueNull, notTextInsertion } },
     1118        { "Print", { executePrint, supported, enabled, stateNone, valueNull, notTextInsertion } },
     1119        { "Redo", { executeRedo, supported, enabledRedo, stateNone, valueNull, notTextInsertion } },
     1120        { "RemoveFormat", { executeRemoveFormat, supported, enabledRangeInEditableText, stateNone, valueNull, notTextInsertion } },
     1121        { "SelectAll", { executeSelectAll, supported, enabled, stateNone, valueNull, notTextInsertion } },
     1122        { "SelectToMark", { executeSelectToMark, supported, enabledAnySelectionAndMark, stateNone, valueNull, notTextInsertion } },
     1123        { "SetMark", { executeSetMark, supported, enabledAnySelection, stateNone, valueNull, notTextInsertion } },
     1124        { "Strikethrough", { executeStrikethrough, supported, enabledInRichlyEditableText, stateStrikethrough, valueNull, notTextInsertion } },
     1125        { "Subscript", { executeSubscript, supported, enabledInRichlyEditableText, stateSubscript, valueNull, notTextInsertion } },
     1126        { "Superscript", { executeSuperscript, supported, enabledInRichlyEditableText, stateSuperscript, valueNull, notTextInsertion } },
     1127        { "SwapWithMark", { executeSwapWithMark, supported, enabledAnySelectionAndMark, stateNone, valueNull, notTextInsertion } },
     1128        { "ToggleBold", { executeToggleBold, supported, enabledInRichlyEditableText, stateBold, valueNull, notTextInsertion } },
     1129        { "ToggleItalic", { executeToggleItalic, supported, enabledInRichlyEditableText, stateItalic, valueNull, notTextInsertion } },
     1130        { "ToggleUnderline", { executeUnderline, supported, enabledInRichlyEditableText, stateUnderline, valueNull, notTextInsertion } },
     1131        { "Transpose", { executeTranspose, supported, enableCaretInEditableText, stateNone, valueNull, notTextInsertion } },
     1132        { "Underline", { executeUnderline, supported, enabledInRichlyEditableText, stateUnderline, valueNull, notTextInsertion } },
     1133        { "Undo", { executeUndo, supported, enabledUndo, stateNone, valueNull, notTextInsertion } },
     1134        { "Unlink", { executeUnlink, supported, enabledRangeInRichlyEditableText, stateNone, valueNull, notTextInsertion } },
     1135        { "Unscript", { executeUnscript, supported, enabledInRichlyEditableText, stateNone, valueNull, notTextInsertion } },
     1136        { "Unselect", { executeUnselect, supported, enabledAnySelection, stateNone, valueNull, notTextInsertion } },
     1137        { "Yank", { executeYank, supported, enabledInEditableText, stateNone, valueNull, notTextInsertion } },
     1138        { "YankAndSelect", { executeYankAndSelect, supported, enabledInEditableText, stateNone, valueNull, notTextInsertion } },
    12951139    };
    12961140
    1297     CommandMap* commandMap = new CommandMap;
     1141    // These unsupported commands are listed here since they appear in the Microsoft
     1142    // documentation used as the starting point for our DOM executeCommand support.
     1143    //
     1144    // 2D-Position (not supported)
     1145    // AbsolutePosition (not supported)
     1146    // BlockDirLTR (not supported)
     1147    // BlockDirRTL (not supported)
     1148    // BrowseMode (not supported)
     1149    // ClearAuthenticationCache (not supported)
     1150    // CreateBookmark (not supported)
     1151    // DirLTR (not supported)
     1152    // DirRTL (not supported)
     1153    // EditMode (not supported)
     1154    // InlineDirLTR (not supported)
     1155    // InlineDirRTL (not supported)
     1156    // InsertButton (not supported)
     1157    // InsertFieldSet (not supported)
     1158    // InsertIFrame (not supported)
     1159    // InsertInputButton (not supported)
     1160    // InsertInputCheckbox (not supported)
     1161    // InsertInputFileUpload (not supported)
     1162    // InsertInputHidden (not supported)
     1163    // InsertInputImage (not supported)
     1164    // InsertInputPassword (not supported)
     1165    // InsertInputRadio (not supported)
     1166    // InsertInputReset (not supported)
     1167    // InsertInputSubmit (not supported)
     1168    // InsertInputText (not supported)
     1169    // InsertMarquee (not supported)
     1170    // InsertSelectDropDown (not supported)
     1171    // InsertSelectListBox (not supported)
     1172    // InsertTextArea (not supported)
     1173    // LiveResize (not supported)
     1174    // MultipleSelection (not supported)
     1175    // Open (not supported)
     1176    // Overwrite (not supported)
     1177    // PlayImage (not supported)
     1178    // Refresh (not supported)
     1179    // RemoveParaFormat (not supported)
     1180    // SaveAs (not supported)
     1181    // SizeToControl (not supported)
     1182    // SizeToControlHeight (not supported)
     1183    // SizeToControlWidth (not supported)
     1184    // Stop (not supported)
     1185    // StopImage (not supported)
     1186    // Unbookmark (not supported)
     1187
     1188    CommandMap& commandMap = *new CommandMap;
    12981189
    12991190    const unsigned numCommands = sizeof(commands) / sizeof(commands[0]);
    1300     for (unsigned i = 0; i < numCommands; i++)
    1301         commandMap->set(AtomicString(commands[i].name).impl(), &commands[i].command);
     1191    for (unsigned i = 0; i < numCommands; i++) {
     1192        ASSERT(!commandMap.get(commands[i].name));
     1193        commandMap.set(commands[i].name, &commands[i].command);
     1194    }
    13021195
    13031196    return commandMap;
    13041197}
    13051198
    1306 // =============================================================================
    1307 //
    1308 // public editing commands
    1309 //
    1310 // =============================================================================
    1311 
    1312 Editor::Editor(Frame* frame)
     1199Editor::Command Editor::command(const String& commandName)
     1200{
     1201    return command(commandName, CommandFromMenuOrKeyBinding);
     1202}
     1203
     1204Editor::Command Editor::command(const String& commandName, EditorCommandSource source)
     1205{
     1206    static const CommandMap& commandMap = createCommandMap();
     1207    const EditorInternalCommand* internalCommand = commandMap.get(commandName);
     1208    return internalCommand ? Command(m_frame, internalCommand, source) : Command();
     1209}
     1210
     1211Editor::Command::Command()
     1212    : m_command(0)
     1213    , m_source()
     1214{
     1215}
     1216
     1217Editor::Command::Command(PassRefPtr<Frame> frame, const EditorInternalCommand* command, EditorCommandSource source)
    13131218    : m_frame(frame)
    1314     , m_deleteButtonController(new DeleteButtonController(frame))
    1315     , m_ignoreCompositionSelectionChange(false)
    1316 {
    1317 }
    1318 
    1319 Editor::~Editor()
    1320 {
    1321 }
    1322 
    1323 void Editor::clear()
    1324 {
    1325     m_compositionNode = 0;
    1326     m_customCompositionUnderlines.clear();
    1327 }
    1328 
    1329 bool Editor::execCommand(const AtomicString& command, Event* triggeringEvent)
    1330 {
    1331     if (!m_frame->document())
    1332         return false;
    1333 
    1334     static CommandMap* commandMap;
    1335     if (!commandMap)
    1336         commandMap = createCommandMap();
    1337    
    1338     const Command* c = commandMap->get(command.impl());
    1339     if (!c)
    1340         return false;
    1341    
    1342     bool handled = false;
    1343    
    1344     if (c->enabled(m_frame, triggeringEvent)) {
    1345         m_frame->document()->updateLayoutIgnorePendingStylesheets();
    1346         handled = c->exec(m_frame, triggeringEvent);
    1347     }
    1348    
    1349     return handled;
    1350 }
    1351 
    1352 bool Editor::insertText(const String& text, Event* triggeringEvent)
    1353 {
    1354     return m_frame->eventHandler()->handleTextInputEvent(text, triggeringEvent);
    1355 }
    1356 
    1357 bool Editor::insertTextWithoutSendingTextEvent(const String& text, bool selectInsertedText, Event* triggeringEvent)
    1358 {
    1359     if (text.isEmpty())
    1360         return false;
    1361 
    1362     Selection selection = selectionForEvent(m_frame, triggeringEvent);
    1363     if (!selection.isContentEditable())
    1364         return false;
    1365     RefPtr<Range> range = selection.toRange();
    1366 
    1367     if (!shouldInsertText(text, range.get(), EditorInsertActionTyped))
    1368         return true;
    1369 
    1370     // Get the selection to use for the event that triggered this insertText.
    1371     // If the event handler changed the selection, we may want to use a different selection
    1372     // that is contained in the event target.
    1373     selection = selectionForEvent(m_frame, triggeringEvent);
    1374     if (selection.isContentEditable()) {
    1375         if (Node* selectionStart = selection.start().node()) {
    1376             RefPtr<Document> document = selectionStart->document();
    1377            
    1378             // Insert the text
    1379             TypingCommand::insertText(document.get(), text, selection, selectInsertedText);
    1380 
    1381             // Reveal the current selection
    1382             if (Frame* editedFrame = document->frame())
    1383                 if (Page* page = editedFrame->page())
    1384                     page->focusController()->focusedOrMainFrame()->revealSelection(RenderLayer::gAlignToEdgeIfNeeded);
    1385         }
    1386     }
    1387 
    1388     return true;
    1389 }
    1390 
    1391 bool Editor::insertLineBreak()
    1392 {
    1393     if (!canEdit())
    1394         return false;
    1395 
    1396     if (!shouldInsertText("\n", m_frame->selectionController()->toRange().get(), EditorInsertActionTyped))
    1397         return true;
    1398 
    1399     TypingCommand::insertLineBreak(m_frame->document());
    1400     revealSelectionAfterEditingOperation();
    1401     return true;
    1402 }
    1403 
    1404 bool Editor::insertParagraphSeparator()
    1405 {
    1406     if (!canEdit())
    1407         return false;
    1408 
    1409     if (!canEditRichly())
    1410         return insertLineBreak();
    1411 
    1412     if (!shouldInsertText("\n", m_frame->selectionController()->toRange().get(), EditorInsertActionTyped))
    1413         return true;
    1414 
    1415     TypingCommand::insertParagraphSeparator(m_frame->document());
    1416     revealSelectionAfterEditingOperation();
    1417     return true;
    1418 }
    1419 
    1420 void Editor::cut()
    1421 {
    1422     if (tryDHTMLCut())
    1423         return; // DHTML did the whole operation
    1424     if (!canCut()) {
    1425         systemBeep();
    1426         return;
    1427     }
    1428     RefPtr<Range> selection = selectedRange();
    1429     if (shouldDeleteRange(selection.get())) {
    1430         Pasteboard::generalPasteboard()->writeSelection(selection.get(), canSmartCopyOrDelete(), m_frame);
    1431         didWriteSelectionToPasteboard();
    1432         deleteSelectionWithSmartDelete(canSmartCopyOrDelete());
    1433     }
    1434 }
    1435 
    1436 void Editor::copy()
    1437 {
    1438     if (tryDHTMLCopy())
    1439         return; // DHTML did the whole operation
    1440     if (!canCopy()) {
    1441         systemBeep();
    1442         return;
    1443     }
    1444    
    1445     Document* document = m_frame->document();
    1446     if (Node* node = imageNodeFromImageDocument(document))
    1447         Pasteboard::generalPasteboard()->writeImage(node, document->URL(), document->title());
    1448     else
    1449         Pasteboard::generalPasteboard()->writeSelection(selectedRange().get(), canSmartCopyOrDelete(), m_frame);
    1450    
    1451     didWriteSelectionToPasteboard();
    1452 }
    1453 
    1454 void Editor::paste()
    1455 {
    1456     ASSERT(m_frame->document());
    1457     DocLoader* loader = m_frame->document()->docLoader();
    1458 #if PLATFORM(MAC)
    1459     // using the platform independent code below requires moving all of
    1460     // WEBHTMLView: _documentFragmentFromPasteboard over to PasteboardMac.
    1461     loader->setAllowStaleResources(true);
    1462     m_frame->issuePasteCommand();
    1463     loader->setAllowStaleResources(false);
    1464 #else
    1465     if (tryDHTMLPaste())
    1466         return;     // DHTML did the whole operation
    1467     if (!canPaste())
    1468         return;
    1469     loader->setAllowStaleResources(true);
    1470     if (m_frame->selectionController()->isContentRichlyEditable())
    1471         pasteWithPasteboard(Pasteboard::generalPasteboard(), true);
    1472     else
    1473         pasteAsPlainTextWithPasteboard(Pasteboard::generalPasteboard());
    1474     loader->setAllowStaleResources(false);
    1475 #endif
    1476 }
    1477 
    1478 void Editor::pasteAsPlainText()
    1479 {
    1480    if (!canPaste())
    1481         return;
    1482    pasteAsPlainTextWithPasteboard(Pasteboard::generalPasteboard());
    1483 }
    1484 
    1485 void Editor::performDelete()
    1486 {
    1487     if (!canDelete()) {
    1488         systemBeep();
    1489         return;
    1490     }
    1491 
    1492     addToKillRing(selectedRange().get(), false);
    1493     deleteSelectionWithSmartDelete(canSmartCopyOrDelete());
    1494 
    1495     // clear the "start new kill ring sequence" setting, because it was set to true
    1496     // when the selection was updated by deleting the range
    1497     setStartNewKillRingSequence(false);
    1498 }
    1499 
    1500 void Editor::copyURL(const KURL& url, const String& title)
    1501 {
    1502     Pasteboard::generalPasteboard()->writeURL(url, title, m_frame);
    1503 }
    1504 
    1505 void Editor::copyImage(const HitTestResult& result)
    1506 {
    1507     KURL url = result.absoluteLinkURL();
    1508     if (url.isEmpty())
    1509         url = result.absoluteImageURL();
    1510 
    1511     Pasteboard::generalPasteboard()->writeImage(result.innerNonSharedNode(), url, result.altDisplayString());
    1512 }
    1513 
    1514 bool Editor::isContinuousSpellCheckingEnabled()
    1515 {
    1516     return client() && client()->isContinuousSpellCheckingEnabled();
    1517 }
    1518 
    1519 void Editor::toggleContinuousSpellChecking()
    1520 {
    1521     if (client())
    1522         client()->toggleContinuousSpellChecking();
    1523 }
    1524 
    1525 bool Editor::isGrammarCheckingEnabled()
    1526 {
    1527     return client() && client()->isGrammarCheckingEnabled();
    1528 }
    1529 
    1530 void Editor::toggleGrammarChecking()
    1531 {
    1532     if (client())
    1533         client()->toggleGrammarChecking();
    1534 }
    1535 
    1536 int Editor::spellCheckerDocumentTag()
    1537 {
    1538     return client() ? client()->spellCheckerDocumentTag() : 0;
    1539 }
    1540 
    1541 bool Editor::shouldEndEditing(Range* range)
    1542 {
    1543     return client() && client()->shouldEndEditing(range);
    1544 }
    1545 
    1546 bool Editor::shouldBeginEditing(Range* range)
    1547 {
    1548     return client() && client()->shouldBeginEditing(range);
    1549 }
    1550 
    1551 void Editor::clearUndoRedoOperations()
    1552 {
    1553     if (client())
    1554         client()->clearUndoRedoOperations();
    1555 }
    1556 
    1557 bool Editor::canUndo()
    1558 {
    1559     return client() && client()->canUndo();
    1560 }
    1561 
    1562 void Editor::undo()
    1563 {
    1564     if (client())
    1565         client()->undo();
    1566 }
    1567 
    1568 bool Editor::canRedo()
    1569 {
    1570     return client() && client()->canRedo();
    1571 }
    1572 
    1573 void Editor::redo()
    1574 {
    1575     if (client())
    1576         client()->redo();
    1577 }
    1578 
    1579 void Editor::didBeginEditing()
    1580 {
    1581     if (client())
    1582         client()->didBeginEditing();
    1583 }
    1584 
    1585 void Editor::didEndEditing()
    1586 {
    1587     if (client())
    1588         client()->didEndEditing();
    1589 }
    1590 
    1591 void Editor::didWriteSelectionToPasteboard()
    1592 {
    1593     if (client())
    1594         client()->didWriteSelectionToPasteboard();
    1595 }
    1596 
    1597 void Editor::toggleBold()
    1598 {
    1599     execToggleBold(frame(), 0);
    1600 }
    1601 
    1602 void Editor::toggleUnderline()
    1603 {
    1604     ExceptionCode ec = 0;
    1605 
    1606     RefPtr<CSSStyleDeclaration> style = frame()->document()->createCSSStyleDeclaration();
    1607     style->setProperty(CSS_PROP__WEBKIT_TEXT_DECORATIONS_IN_EFFECT, "underline", false, ec);
    1608     if (selectionStartHasStyle(style.get()))
    1609         style->setProperty(CSS_PROP__WEBKIT_TEXT_DECORATIONS_IN_EFFECT, "none", false, ec);
    1610     applyStyleToSelection(style.get(), EditActionUnderline);
    1611 }
    1612 
    1613 void Editor::setBaseWritingDirection(String direction)
    1614 {
    1615     ExceptionCode ec = 0;
    1616 
    1617     RefPtr<CSSStyleDeclaration> style = frame()->document()->createCSSStyleDeclaration();
    1618     style->setProperty(CSS_PROP_DIRECTION, direction, false, ec);
    1619     applyParagraphStyleToSelection(style.get(), EditActionSetWritingDirection);
    1620 }
    1621 
    1622 void Editor::selectComposition()
    1623 {
    1624     RefPtr<Range> range = compositionRange();
    1625     if (!range)
    1626         return;
    1627    
    1628     // The composition can start inside a composed character sequence, so we have to override checks.
    1629     // See <http://bugs.webkit.org/show_bug.cgi?id=15781>
    1630     Selection selection;
    1631     selection.setWithoutValidation(range->startPosition(), range->endPosition());
    1632     m_frame->selectionController()->setSelection(selection, false, false);
    1633 }
    1634 
    1635 void Editor::confirmComposition()
    1636 {
    1637     if (!m_compositionNode)
    1638         return;
    1639     confirmComposition(m_compositionNode->data().substring(m_compositionStart, m_compositionEnd - m_compositionStart), false);
    1640 }
    1641 
    1642 void Editor::confirmCompositionWithoutDisturbingSelection()
    1643 {
    1644     if (!m_compositionNode)
    1645         return;
    1646     confirmComposition(m_compositionNode->data().substring(m_compositionStart, m_compositionEnd - m_compositionStart), true);
    1647 }
    1648 
    1649 void Editor::confirmComposition(const String& text)
    1650 {
    1651     confirmComposition(text, false);
    1652 }
    1653 
    1654 void Editor::confirmComposition(const String& text, bool preserveSelection)
    1655 {
    1656     setIgnoreCompositionSelectionChange(true);
    1657 
    1658     Selection oldSelection = m_frame->selectionController()->selection();
    1659 
    1660     selectComposition();
    1661 
    1662     if (m_frame->selectionController()->isNone()) {
    1663         setIgnoreCompositionSelectionChange(false);
    1664         return;
    1665     }
    1666    
    1667     // If there is a composition to replace, remove it with a deletion that will be part of the
    1668     // same Undo step as the next and previous insertions.
    1669     TypingCommand::deleteSelection(m_frame->document(), false);
    1670 
    1671     m_compositionNode = 0;
    1672     m_customCompositionUnderlines.clear();
    1673 
    1674     insertText(text, 0);
    1675 
    1676     if (preserveSelection)
    1677         m_frame->selectionController()->setSelection(oldSelection, false, false);
    1678 
    1679     setIgnoreCompositionSelectionChange(false);
    1680 }
    1681 
    1682 void Editor::setComposition(const String& text, const Vector<CompositionUnderline>& underlines, unsigned selectionStart, unsigned selectionEnd)
    1683 {
    1684     setIgnoreCompositionSelectionChange(true);
    1685 
    1686     selectComposition();
    1687 
    1688     if (m_frame->selectionController()->isNone()) {
    1689         setIgnoreCompositionSelectionChange(false);
    1690         return;
    1691     }
    1692    
    1693     // If there is a composition to replace, remove it with a deletion that will be part of the
    1694     // same Undo step as the next and previous insertions.
    1695     TypingCommand::deleteSelection(m_frame->document(), false);
    1696 
    1697     m_compositionNode = 0;
    1698     m_customCompositionUnderlines.clear();
    1699 
    1700     if (!text.isEmpty()) {
    1701         TypingCommand::insertText(m_frame->document(), text, true, true);
    1702 
    1703         Node* baseNode = m_frame->selectionController()->base().node();
    1704         unsigned baseOffset = m_frame->selectionController()->base().offset();
    1705         Node* extentNode = m_frame->selectionController()->extent().node();
    1706         unsigned extentOffset = m_frame->selectionController()->extent().offset();
    1707 
    1708         if (baseNode && baseNode == extentNode && baseNode->isTextNode() && baseOffset + text.length() == extentOffset) {
    1709             m_compositionNode = static_cast<Text*>(baseNode);
    1710             m_compositionStart = baseOffset;
    1711             m_compositionEnd = extentOffset;
    1712             m_customCompositionUnderlines = underlines;
    1713             size_t numUnderlines = m_customCompositionUnderlines.size();
    1714             for (size_t i = 0; i < numUnderlines; ++i) {
    1715                 m_customCompositionUnderlines[i].startOffset += baseOffset;
    1716                 m_customCompositionUnderlines[i].endOffset += baseOffset;
    1717             }
    1718             if (baseNode->renderer())
    1719                 baseNode->renderer()->repaint();
    1720 
    1721             unsigned start = min(baseOffset + selectionStart, extentOffset);
    1722             unsigned end = min(max(start, baseOffset + selectionEnd), extentOffset);
    1723             RefPtr<Range> selectedRange = new Range(baseNode->document(), baseNode, start, baseNode, end);               
    1724             m_frame->selectionController()->setSelectedRange(selectedRange.get(), DOWNSTREAM, false);
    1725         }
    1726     }
    1727 
    1728     setIgnoreCompositionSelectionChange(false);
    1729 }
    1730 
    1731 void Editor::ignoreSpelling()
    1732 {
    1733     if (!client())
    1734         return;
    1735 
    1736     String text = frame()->selectedText();
    1737     ASSERT(text.length() != 0);
    1738     client()->ignoreWordInSpellDocument(text);
    1739 }
    1740 
    1741 void Editor::learnSpelling()
    1742 {
    1743     if (!client())
    1744         return;
    1745 
    1746     String text = frame()->selectedText();
    1747     ASSERT(text.length() != 0);
    1748     client()->learnWord(text);
    1749 }
    1750 
    1751 static String findFirstMisspellingInRange(EditorClient* client, Range* searchRange, int& firstMisspellingOffset, bool markAll)
    1752 {
    1753     ASSERT_ARG(client, client);
    1754     ASSERT_ARG(searchRange, searchRange);
    1755    
    1756     WordAwareIterator it(searchRange);
    1757     firstMisspellingOffset = 0;
    1758    
    1759     String firstMisspelling;
    1760     int currentChunkOffset = 0;
    1761 
    1762     while (!it.atEnd()) {
    1763         const UChar* chars = it.characters();
    1764         int len = it.length();
    1765        
    1766         // Skip some work for one-space-char hunks
    1767         if (!(len == 1 && chars[0] == ' ')) {
    1768            
    1769             int misspellingLocation = -1;
    1770             int misspellingLength = 0;
    1771             client->checkSpellingOfString(chars, len, &misspellingLocation, &misspellingLength);
    1772 
    1773             // 5490627 shows that there was some code path here where the String constructor below crashes.
    1774             // We don't know exactly what combination of bad input caused this, so we're making this much
    1775             // more robust against bad input on release builds.
    1776             ASSERT(misspellingLength >= 0);
    1777             ASSERT(misspellingLocation >= -1);
    1778             ASSERT(misspellingLength == 0 || misspellingLocation >= 0);
    1779             ASSERT(misspellingLocation < len);
    1780             ASSERT(misspellingLength <= len);
    1781             ASSERT(misspellingLocation + misspellingLength <= len);
    1782            
    1783             if (misspellingLocation >= 0 && misspellingLength > 0 && misspellingLocation < len && misspellingLength <= len && misspellingLocation + misspellingLength <= len) {
    1784                
    1785                 // Remember first-encountered misspelling and its offset
    1786                 if (!firstMisspelling) {
    1787                     firstMisspellingOffset = currentChunkOffset + misspellingLocation;
    1788                     firstMisspelling = String(chars + misspellingLocation, misspellingLength);
    1789                 }
    1790                
    1791                 // Mark this instance if we're marking all instances. Otherwise bail out because we found the first one.
    1792                 if (!markAll)
    1793                     break;
    1794                
    1795                 // Compute range of misspelled word
    1796                 RefPtr<Range> misspellingRange = TextIterator::subrange(searchRange, currentChunkOffset + misspellingLocation, misspellingLength);
    1797                
    1798                 // Store marker for misspelled word
    1799                 ExceptionCode ec = 0;
    1800                 misspellingRange->startContainer(ec)->document()->addMarker(misspellingRange.get(), DocumentMarker::Spelling);
    1801                 ASSERT(ec == 0);
    1802             }
    1803         }
    1804        
    1805         currentChunkOffset += len;
    1806         it.advance();
    1807     }
    1808    
    1809     return firstMisspelling;
    1810 }
    1811 
    1812 #ifndef BUILDING_ON_TIGER
    1813 
    1814 static PassRefPtr<Range> paragraphAlignedRangeForRange(Range* arbitraryRange, int& offsetIntoParagraphAlignedRange, String& paragraphString)
    1815 {
    1816     ASSERT_ARG(arbitraryRange, arbitraryRange);
    1817    
    1818     ExceptionCode ec = 0;
    1819    
    1820     // Expand range to paragraph boundaries
    1821     RefPtr<Range> paragraphRange = arbitraryRange->cloneRange(ec);
    1822     setStart(paragraphRange.get(), startOfParagraph(arbitraryRange->startPosition()));
    1823     setEnd(paragraphRange.get(), endOfParagraph(arbitraryRange->endPosition()));
    1824    
    1825     // Compute offset from start of expanded range to start of original range
    1826     RefPtr<Range> offsetAsRange = new Range(paragraphRange->startContainer(ec)->document(), paragraphRange->startPosition(), arbitraryRange->startPosition());
    1827     offsetIntoParagraphAlignedRange = TextIterator::rangeLength(offsetAsRange.get());
    1828    
    1829     // Fill in out parameter with string representing entire paragraph range.
    1830     // Someday we might have a caller that doesn't use this, but for now all callers do.
    1831     paragraphString = plainText(paragraphRange.get());
    1832 
    1833     return paragraphRange;
    1834 }
    1835 
    1836 static int findFirstGrammarDetailInRange(const Vector<GrammarDetail>& grammarDetails, int badGrammarPhraseLocation, int badGrammarPhraseLength, Range *searchRange, int startOffset, int endOffset, bool markAll)
    1837 {
    1838     // Found some bad grammar. Find the earliest detail range that starts in our search range (if any).
    1839     // Optionally add a DocumentMarker for each detail in the range.
    1840     int earliestDetailLocationSoFar = -1;
    1841     int earliestDetailIndex = -1;
    1842     for (unsigned i = 0; i < grammarDetails.size(); i++) {
    1843         const GrammarDetail* detail = &grammarDetails[i];
    1844         ASSERT(detail->length > 0 && detail->location >= 0);
    1845        
    1846         int detailStartOffsetInParagraph = badGrammarPhraseLocation + detail->location;
    1847        
    1848         // Skip this detail if it starts before the original search range
    1849         if (detailStartOffsetInParagraph < startOffset)
    1850             continue;
    1851        
    1852         // Skip this detail if it starts after the original search range
    1853         if (detailStartOffsetInParagraph >= endOffset)
    1854             continue;
    1855        
    1856         if (markAll) {
    1857             RefPtr<Range> badGrammarRange = TextIterator::subrange(searchRange, badGrammarPhraseLocation - startOffset + detail->location, detail->length);
    1858             ExceptionCode ec = 0;
    1859             badGrammarRange->startContainer(ec)->document()->addMarker(badGrammarRange.get(), DocumentMarker::Grammar, detail->userDescription);
    1860             ASSERT(ec == 0);
    1861         }
    1862        
    1863         // Remember this detail only if it's earlier than our current candidate (the details aren't in a guaranteed order)
    1864         if (earliestDetailIndex < 0 || earliestDetailLocationSoFar > detail->location) {
    1865             earliestDetailIndex = i;
    1866             earliestDetailLocationSoFar = detail->location;
    1867         }
    1868     }
    1869    
    1870     return earliestDetailIndex;
    1871 }
    1872    
    1873 static String findFirstBadGrammarInRange(EditorClient* client, Range* searchRange, GrammarDetail& outGrammarDetail, int& outGrammarPhraseOffset, bool markAll)
    1874 {
    1875     ASSERT_ARG(client, client);
    1876     ASSERT_ARG(searchRange, searchRange);
    1877    
    1878     // Initialize out parameters; these will be updated if we find something to return.
    1879     outGrammarDetail.location = -1;
    1880     outGrammarDetail.length = 0;
    1881     outGrammarDetail.guesses.clear();
    1882     outGrammarDetail.userDescription = "";
    1883     outGrammarPhraseOffset = 0;
    1884    
    1885     String firstBadGrammarPhrase;
    1886 
    1887     // Expand the search range to encompass entire paragraphs, since grammar checking needs that much context.
    1888     // Determine the character offset from the start of the paragraph to the start of the original search range,
    1889     // since we will want to ignore results in this area.
    1890     int searchRangeStartOffset;
    1891     String paragraphString;
    1892     RefPtr<Range> paragraphRange = paragraphAlignedRangeForRange(searchRange, searchRangeStartOffset, paragraphString);
    1893        
    1894     // Determine the character offset from the start of the paragraph to the end of the original search range,
    1895     // since we will want to ignore results in this area also.
    1896     int searchRangeEndOffset = searchRangeStartOffset + TextIterator::rangeLength(searchRange);
    1897        
    1898     // Start checking from beginning of paragraph, but skip past results that occur before the start of the original search range.
    1899     int startOffset = 0;
    1900     while (startOffset < searchRangeEndOffset) {
    1901         Vector<GrammarDetail> grammarDetails;
    1902         int badGrammarPhraseLocation = -1;
    1903         int badGrammarPhraseLength = 0;
    1904         client->checkGrammarOfString(paragraphString.characters() + startOffset, paragraphString.length() - startOffset, grammarDetails, &badGrammarPhraseLocation, &badGrammarPhraseLength);
    1905        
    1906         if (badGrammarPhraseLength == 0) {
    1907             ASSERT(badGrammarPhraseLocation == -1);
    1908             return String();
    1909         }
    1910 
    1911         ASSERT(badGrammarPhraseLocation >= 0);
    1912         badGrammarPhraseLocation += startOffset;
    1913 
    1914        
    1915         // Found some bad grammar. Find the earliest detail range that starts in our search range (if any).
    1916         int badGrammarIndex = findFirstGrammarDetailInRange(grammarDetails, badGrammarPhraseLocation, badGrammarPhraseLength, searchRange, searchRangeStartOffset, searchRangeEndOffset, markAll);
    1917         if (badGrammarIndex >= 0) {
    1918             ASSERT(static_cast<unsigned>(badGrammarIndex) < grammarDetails.size());
    1919             outGrammarDetail = grammarDetails[badGrammarIndex];
    1920         }
    1921 
    1922         // If we found a detail in range, then we have found the first bad phrase (unless we found one earlier but
    1923         // kept going so we could mark all instances).
    1924         if (badGrammarIndex >= 0 && firstBadGrammarPhrase.isEmpty()) {
    1925             outGrammarPhraseOffset = badGrammarPhraseLocation - searchRangeStartOffset;
    1926             firstBadGrammarPhrase = paragraphString.substring(badGrammarPhraseLocation, badGrammarPhraseLength);
    1927            
    1928             // Found one. We're done now, unless we're marking each instance.
    1929             if (!markAll)
    1930                 break;
    1931         }
    1932 
    1933         // These results were all between the start of the paragraph and the start of the search range; look
    1934         // beyond this phrase.
    1935         startOffset = badGrammarPhraseLocation + badGrammarPhraseLength;
    1936     }
    1937    
    1938     return firstBadGrammarPhrase;
    1939 }
    1940    
    1941 #endif /* not BUILDING_ON_TIGER */
    1942 
    1943 void Editor::advanceToNextMisspelling(bool startBeforeSelection)
    1944 {
    1945     ExceptionCode ec = 0;
    1946 
    1947     // The basic approach is to search in two phases - from the selection end to the end of the doc, and
    1948     // then we wrap and search from the doc start to (approximately) where we started.
    1949    
    1950     // Start at the end of the selection, search to edge of document.  Starting at the selection end makes
    1951     // repeated "check spelling" commands work.
    1952     Selection selection(frame()->selectionController()->selection());
    1953     RefPtr<Range> spellingSearchRange(rangeOfContents(frame()->document()));
    1954     bool startedWithSelection = false;
    1955     if (selection.start().node()) {
    1956         startedWithSelection = true;
    1957         if (startBeforeSelection) {
    1958             VisiblePosition start(selection.visibleStart());
    1959             // We match AppKit's rule: Start 1 character before the selection.
    1960             VisiblePosition oneBeforeStart = start.previous();
    1961             setStart(spellingSearchRange.get(), oneBeforeStart.isNotNull() ? oneBeforeStart : start);
    1962         } else
    1963             setStart(spellingSearchRange.get(), selection.visibleEnd());
    1964     }
    1965 
    1966     Position position = spellingSearchRange->startPosition();
    1967     if (!isEditablePosition(position)) {
    1968         // This shouldn't happen in very often because the Spelling menu items aren't enabled unless the
    1969         // selection is editable.
    1970         // This can happen in Mail for a mix of non-editable and editable content (like Stationary),
    1971         // when spell checking the whole document before sending the message.
    1972         // In that case the document might not be editable, but there are editable pockets that need to be spell checked.
    1973 
    1974         position = firstEditablePositionAfterPositionInRoot(position, frame()->document()->documentElement()).deepEquivalent();
    1975         if (position.isNull())
    1976             return;
    1977        
    1978         Position rangeCompliantPosition = rangeCompliantEquivalent(position);
    1979         spellingSearchRange->setStart(rangeCompliantPosition.node(), rangeCompliantPosition.offset(), ec);
    1980         startedWithSelection = false;   // won't need to wrap
    1981     }
    1982    
    1983     // topNode defines the whole range we want to operate on
    1984     Node* topNode = highestEditableRoot(position);
    1985     spellingSearchRange->setEnd(topNode, maxDeepOffset(topNode), ec);
    1986 
    1987     // If spellingSearchRange starts in the middle of a word, advance to the next word so we start checking
    1988     // at a word boundary. Going back by one char and then forward by a word does the trick.
    1989     if (startedWithSelection) {
    1990         VisiblePosition oneBeforeStart = startVisiblePosition(spellingSearchRange.get(), DOWNSTREAM).previous();
    1991         if (oneBeforeStart.isNotNull()) {
    1992             setStart(spellingSearchRange.get(), endOfWord(oneBeforeStart));
    1993         } // else we were already at the start of the editable node
    1994     }
    1995    
    1996     if (spellingSearchRange->collapsed(ec))
    1997         return;       // nothing to search in
    1998    
    1999     // Get the spell checker if it is available
    2000     if (!client())
    2001         return;
    2002        
    2003     // We go to the end of our first range instead of the start of it, just to be sure
    2004     // we don't get foiled by any word boundary problems at the start.  It means we might
    2005     // do a tiny bit more searching.
    2006     Node *searchEndNodeAfterWrap = spellingSearchRange->endContainer(ec);
    2007     int searchEndOffsetAfterWrap = spellingSearchRange->endOffset(ec);
    2008    
    2009     int misspellingOffset;
    2010     String misspelledWord = findFirstMisspellingInRange(client(), spellingSearchRange.get(), misspellingOffset, false);
    2011    
    2012     String badGrammarPhrase;
    2013 
    2014 #ifndef BUILDING_ON_TIGER
    2015     int grammarPhraseOffset = 0;
    2016     GrammarDetail grammarDetail;
    2017 
    2018     // Search for bad grammar that occurs prior to the next misspelled word (if any)
    2019     RefPtr<Range> grammarSearchRange = spellingSearchRange->cloneRange(ec);
    2020     if (!misspelledWord.isEmpty()) {
    2021         // Stop looking at start of next misspelled word
    2022         CharacterIterator chars(grammarSearchRange.get());
    2023         chars.advance(misspellingOffset);
    2024         grammarSearchRange->setEnd(chars.range()->startContainer(ec), chars.range()->startOffset(ec), ec);
    2025     }
    2026    
    2027     if (isGrammarCheckingEnabled())
    2028         badGrammarPhrase = findFirstBadGrammarInRange(client(), grammarSearchRange.get(), grammarDetail, grammarPhraseOffset, false);
    2029 #endif
    2030    
    2031     // If we found neither bad grammar nor a misspelled word, wrap and try again (but don't bother if we started at the beginning of the
    2032     // block rather than at a selection).
    2033     if (startedWithSelection && !misspelledWord && !badGrammarPhrase) {
    2034         spellingSearchRange->setStart(topNode, 0, ec);
    2035         // going until the end of the very first chunk we tested is far enough
    2036         spellingSearchRange->setEnd(searchEndNodeAfterWrap, searchEndOffsetAfterWrap, ec);
    2037        
    2038         misspelledWord = findFirstMisspellingInRange(client(), spellingSearchRange.get(), misspellingOffset, false);
    2039 
    2040 #ifndef BUILDING_ON_TIGER
    2041         grammarSearchRange = spellingSearchRange->cloneRange(ec);
    2042         if (!misspelledWord.isEmpty()) {
    2043             // Stop looking at start of next misspelled word
    2044             CharacterIterator chars(grammarSearchRange.get());
    2045             chars.advance(misspellingOffset);
    2046             grammarSearchRange->setEnd(chars.range()->startContainer(ec), chars.range()->startOffset(ec), ec);
    2047         }
    2048         if (isGrammarCheckingEnabled())
    2049             badGrammarPhrase = findFirstBadGrammarInRange(client(), grammarSearchRange.get(), grammarDetail, grammarPhraseOffset, false);
    2050 #endif
    2051     }
    2052    
    2053     if (!badGrammarPhrase.isEmpty()) {
    2054 #ifdef BUILDING_ON_TIGER
    2055         ASSERT_NOT_REACHED();
    2056 #else
    2057         // We found bad grammar. Since we only searched for bad grammar up to the first misspelled word, the bad grammar
    2058         // takes precedence and we ignore any potential misspelled word. Select the grammar detail, update the spelling
    2059         // panel, and store a marker so we draw the green squiggle later.
    2060        
    2061         ASSERT(badGrammarPhrase.length() > 0);
    2062         ASSERT(grammarDetail.location != -1 && grammarDetail.length > 0);
    2063        
    2064         // FIXME 4859190: This gets confused with doubled punctuation at the end of a paragraph
    2065         RefPtr<Range> badGrammarRange = TextIterator::subrange(grammarSearchRange.get(), grammarPhraseOffset + grammarDetail.location, grammarDetail.length);
    2066         frame()->selectionController()->setSelection(Selection(badGrammarRange.get(), SEL_DEFAULT_AFFINITY));
    2067         frame()->revealSelection();
    2068        
    2069         client()->updateSpellingUIWithGrammarString(badGrammarPhrase, grammarDetail);
    2070         frame()->document()->addMarker(badGrammarRange.get(), DocumentMarker::Grammar, grammarDetail.userDescription);
    2071 #endif       
    2072     } else if (!misspelledWord.isEmpty()) {
    2073         // We found a misspelling, but not any earlier bad grammar. Select the misspelling, update the spelling panel, and store
    2074         // a marker so we draw the red squiggle later.
    2075        
    2076         RefPtr<Range> misspellingRange = TextIterator::subrange(spellingSearchRange.get(), misspellingOffset, misspelledWord.length());
    2077         frame()->selectionController()->setSelection(Selection(misspellingRange.get(), DOWNSTREAM));
    2078         frame()->revealSelection();
    2079        
    2080         client()->updateSpellingUIWithMisspelledWord(misspelledWord);
    2081         frame()->document()->addMarker(misspellingRange.get(), DocumentMarker::Spelling);
    2082     }
    2083 }
    2084 
    2085 bool Editor::isSelectionMisspelled()
    2086 {
    2087     String selectedString = frame()->selectedText();
    2088     int length = selectedString.length();
    2089     if (length == 0)
    2090         return false;
    2091 
    2092     if (!client())
    2093         return false;
    2094    
    2095     int misspellingLocation = -1;
    2096     int misspellingLength = 0;
    2097     client()->checkSpellingOfString(selectedString.characters(), length, &misspellingLocation, &misspellingLength);
    2098    
    2099     // The selection only counts as misspelled if the selected text is exactly one misspelled word
    2100     if (misspellingLength != length)
    2101         return false;
    2102    
    2103     // Update the spelling panel to be displaying this error (whether or not the spelling panel is on screen).
    2104     // This is necessary to make a subsequent call to [NSSpellChecker ignoreWord:inSpellDocumentWithTag:] work
    2105     // correctly; that call behaves differently based on whether the spelling panel is displaying a misspelling
    2106     // or a grammar error.
    2107     client()->updateSpellingUIWithMisspelledWord(selectedString);
    2108    
    2109     return true;
    2110 }
    2111 
    2112 #ifndef BUILDING_ON_TIGER
    2113 static bool isRangeUngrammatical(EditorClient* client, Range *range, Vector<String>& guessesVector)
    2114 {
    2115     if (!client)
    2116         return false;
    2117 
    2118     ExceptionCode ec;
    2119     if (!range || range->collapsed(ec))
    2120         return false;
    2121    
    2122     // Returns true only if the passed range exactly corresponds to a bad grammar detail range. This is analogous
    2123     // to isSelectionMisspelled. It's not good enough for there to be some bad grammar somewhere in the range,
    2124     // or overlapping the range; the ranges must exactly match.
    2125     guessesVector.clear();
    2126     int grammarPhraseOffset;
    2127    
    2128     GrammarDetail grammarDetail;
    2129     String badGrammarPhrase = findFirstBadGrammarInRange(client, range, grammarDetail, grammarPhraseOffset, false);   
    2130    
    2131     // No bad grammar in these parts at all.
    2132     if (badGrammarPhrase.isEmpty())
    2133         return false;
    2134    
    2135     // Bad grammar, but phrase (e.g. sentence) starts beyond start of range.
    2136     if (grammarPhraseOffset > 0)
    2137         return false;
    2138    
    2139     ASSERT(grammarDetail.location >= 0 && grammarDetail.length > 0);
    2140    
    2141     // Bad grammar, but start of detail (e.g. ungrammatical word) doesn't match start of range
    2142     if (grammarDetail.location + grammarPhraseOffset != 0)
    2143         return false;
    2144    
    2145     // Bad grammar at start of range, but end of bad grammar is before or after end of range
    2146     if (grammarDetail.length != TextIterator::rangeLength(range))
    2147         return false;
    2148    
    2149     // Update the spelling panel to be displaying this error (whether or not the spelling panel is on screen).
    2150     // This is necessary to make a subsequent call to [NSSpellChecker ignoreWord:inSpellDocumentWithTag:] work
    2151     // correctly; that call behaves differently based on whether the spelling panel is displaying a misspelling
    2152     // or a grammar error.
    2153     client->updateSpellingUIWithGrammarString(badGrammarPhrase, grammarDetail);
    2154    
    2155     return true;
    2156 }
    2157 #endif
    2158 
    2159 bool Editor::isSelectionUngrammatical()
    2160 {
    2161 #ifdef BUILDING_ON_TIGER
    2162     return false;
    2163 #else
    2164     Vector<String> ignoredGuesses;
    2165     return isRangeUngrammatical(client(), frame()->selectionController()->toRange().get(), ignoredGuesses);
    2166 #endif
    2167 }
    2168 
    2169 Vector<String> Editor::guessesForUngrammaticalSelection()
    2170 {
    2171 #ifdef BUILDING_ON_TIGER
    2172     return Vector<String>();
    2173 #else
    2174     Vector<String> guesses;
    2175     // Ignore the result of isRangeUngrammatical; we just want the guesses, whether or not there are any
    2176     isRangeUngrammatical(client(), frame()->selectionController()->toRange().get(), guesses);
    2177     return guesses;
    2178 #endif
    2179 }
    2180 
    2181 Vector<String> Editor::guessesForMisspelledSelection()
    2182 {
    2183     String selectedString = frame()->selectedText();
    2184     ASSERT(selectedString.length() != 0);
    2185 
    2186     Vector<String> guesses;
    2187     if (client())
    2188         client()->getGuessesForWord(selectedString, guesses);
    2189     return guesses;
    2190 }
    2191 
    2192 void Editor::showSpellingGuessPanel()
    2193 {
    2194     if (!client()) {
    2195         LOG_ERROR("No NSSpellChecker");
    2196         return;
    2197     }
    2198 
    2199 #ifndef BUILDING_ON_TIGER
    2200     // Post-Tiger, this menu item is a show/hide toggle, to match AppKit. Leave Tiger behavior alone
    2201     // to match rest of OS X.
    2202     if (client()->spellingUIIsShowing()) {
    2203         client()->showSpellingUI(false);
    2204         return;
    2205     }
    2206 #endif
    2207    
    2208     advanceToNextMisspelling(true);
    2209     client()->showSpellingUI(true);
    2210 }
    2211 
    2212 bool Editor::spellingPanelIsShowing()
    2213 {
    2214     if (!client())
    2215         return false;
    2216     return client()->spellingUIIsShowing();
    2217 }
    2218 
    2219 void Editor::markMisspellingsAfterTypingToPosition(const VisiblePosition &p)
    2220 {
    2221     if (!isContinuousSpellCheckingEnabled())
    2222         return;
    2223    
    2224     // Check spelling of one word
    2225     markMisspellings(Selection(startOfWord(p, LeftWordIfOnBoundary), endOfWord(p, RightWordIfOnBoundary)));
    2226    
    2227     if (!isGrammarCheckingEnabled())
    2228         return;
    2229    
    2230     // Check grammar of entire sentence
    2231     markBadGrammar(Selection(startOfSentence(p), endOfSentence(p)));
    2232 }
    2233 
    2234 static void markAllMisspellingsInRange(EditorClient* client, Range* searchRange)
    2235 {
    2236     // Use the "markAll" feature of findFirstMisspellingInRange. Ignore the return value and the "out parameter";
    2237     // all we need to do is mark every instance.
    2238     int ignoredOffset;
    2239     findFirstMisspellingInRange(client, searchRange, ignoredOffset, true);
    2240 }
    2241 
    2242 #ifndef BUILDING_ON_TIGER
    2243 static void markAllBadGrammarInRange(EditorClient* client, Range* searchRange)
    2244 {
    2245     // Use the "markAll" feature of findFirstBadGrammarInRange. Ignore the return value and "out parameters"; all we need to
    2246     // do is mark every instance.
    2247     GrammarDetail ignoredGrammarDetail;
    2248     int ignoredOffset;
    2249     findFirstBadGrammarInRange(client, searchRange, ignoredGrammarDetail, ignoredOffset, true);
    2250 }
    2251 #endif
    2252    
    2253 static void markMisspellingsOrBadGrammar(Editor* editor, const Selection& selection, bool checkSpelling)
    2254 {
    2255     // This function is called with a selection already expanded to word boundaries.
    2256     // Might be nice to assert that here.
    2257    
    2258     // This function is used only for as-you-type checking, so if that's off we do nothing. Note that
    2259     // grammar checking can only be on if spell checking is also on.
    2260     if (!editor->isContinuousSpellCheckingEnabled())
    2261         return;
    2262    
    2263     RefPtr<Range> searchRange(selection.toRange());
    2264     if (!searchRange || searchRange->isDetached())
    2265         return;
    2266    
    2267     // If we're not in an editable node, bail.
    2268     int exception = 0;
    2269     Node *editableNode = searchRange->startContainer(exception);
    2270     if (!editableNode->isContentEditable())
    2271         return;
    2272    
    2273     // Get the spell checker if it is available
    2274     if (!editor->client())
    2275         return;
    2276    
    2277     if (checkSpelling)
    2278         markAllMisspellingsInRange(editor->client(), searchRange.get());
    2279     else {
    2280 #ifdef BUILDING_ON_TIGER
    2281         ASSERT_NOT_REACHED();
    2282 #else
    2283         if (editor->isGrammarCheckingEnabled())
    2284             markAllBadGrammarInRange(editor->client(), searchRange.get());
    2285 #endif
    2286     }   
    2287 }
    2288 
    2289 void Editor::markMisspellings(const Selection& selection)
    2290 {
    2291     markMisspellingsOrBadGrammar(this, selection, true);
    2292 }
    2293    
    2294 void Editor::markBadGrammar(const Selection& selection)
    2295 {
    2296 #ifndef BUILDING_ON_TIGER
    2297     markMisspellingsOrBadGrammar(this, selection, false);
    2298 #endif
    2299 }
    2300 
    2301 PassRefPtr<Range> Editor::rangeForPoint(const IntPoint& windowPoint)
    2302 {
    2303     Document* document = m_frame->documentAtPoint(windowPoint);
    2304     if (!document)
    2305         return 0;
    2306    
    2307     Frame* frame = document->frame();
    2308     ASSERT(frame);
    2309     FrameView* frameView = frame->view();
    2310     if (!frameView)
    2311         return 0;
    2312     IntPoint framePoint = frameView->windowToContents(windowPoint);
    2313     Selection selection(frame->visiblePositionForPoint(framePoint));
    2314     return avoidIntersectionWithNode(selection.toRange().get(), deleteButtonController() ? deleteButtonController()->containerElement() : 0);
    2315 }
    2316 
    2317 void Editor::revealSelectionAfterEditingOperation()
    2318 {
    2319     if (m_ignoreCompositionSelectionChange)
    2320         return;
    2321 
    2322     m_frame->revealSelection(RenderLayer::gAlignToEdgeIfNeeded);
    2323 }
    2324 
    2325 void Editor::setIgnoreCompositionSelectionChange(bool ignore)
    2326 {
    2327     if (m_ignoreCompositionSelectionChange == ignore)
    2328         return;
    2329 
    2330     m_ignoreCompositionSelectionChange = ignore;
    2331     if (!ignore)
    2332         revealSelectionAfterEditingOperation();
    2333 }
    2334 
    2335 PassRefPtr<Range> Editor::compositionRange() const
    2336 {
    2337     if (!m_compositionNode)
    2338         return 0;
    2339     unsigned length = m_compositionNode->length();
    2340     unsigned start = min(m_compositionStart, length);
    2341     unsigned end = min(max(start, m_compositionEnd), length);
    2342     if (start >= end)
    2343         return 0;
    2344     return new Range(m_compositionNode->document(), m_compositionNode.get(), start, m_compositionNode.get(), end);
    2345 }
    2346 
    2347 bool Editor::getCompositionSelection(unsigned& selectionStart, unsigned& selectionEnd) const
    2348 {
    2349     if (!m_compositionNode)
    2350         return false;
    2351     Position start = m_frame->selectionController()->start();
    2352     if (start.node() != m_compositionNode)
    2353         return false;
    2354     Position end = m_frame->selectionController()->end();
    2355     if (end.node() != m_compositionNode)
    2356         return false;
    2357 
    2358     if (static_cast<unsigned>(start.offset()) < m_compositionStart)
    2359         return false;
    2360     if (static_cast<unsigned>(end.offset()) > m_compositionEnd)
    2361         return false;
    2362 
    2363     selectionStart = start.offset() - m_compositionStart;
    2364     selectionEnd = start.offset() - m_compositionEnd;
    2365     return true;
    2366 }
    2367 
    2368 void Editor::transpose()
    2369 {
    2370     if (!canEdit())
    2371         return;
    2372 
    2373      Selection selection = m_frame->selectionController()->selection();
    2374      if (!selection.isCaret())
    2375          return;
    2376 
    2377     // Make a selection that goes back one character and forward two characters.
    2378     VisiblePosition caret = selection.visibleStart();
    2379     VisiblePosition next = isEndOfParagraph(caret) ? caret : caret.next();
    2380     VisiblePosition previous = next.previous();
    2381     if (next == previous)
    2382         return;
    2383     previous = previous.previous();
    2384     if (!inSameParagraph(next, previous))
    2385         return;
    2386     RefPtr<Range> range = makeRange(previous, next);
    2387     if (!range)
    2388         return;
    2389     Selection newSelection(range.get(), DOWNSTREAM);
    2390 
    2391     // Transpose the two characters.
    2392     String text = plainText(range.get());
    2393     if (text.length() != 2)
    2394         return;
    2395     String transposed = text.right(1) + text.left(1);
    2396 
    2397     // Select the two characters.
    2398     if (newSelection != m_frame->selectionController()->selection()) {
    2399         if (!m_frame->shouldChangeSelection(newSelection))
    2400             return;
    2401         m_frame->selectionController()->setSelection(newSelection);
    2402     }
    2403 
    2404     // Insert the transposed characters.
    2405     if (!shouldInsertText(transposed, range.get(), EditorInsertActionTyped))
    2406         return;
    2407     replaceSelectionWithText(transposed, false, false);
     1219    , m_command(command)
     1220    , m_source(source)
     1221{
     1222    ASSERT(m_frame);
     1223    ASSERT(m_command);
     1224}
     1225
     1226bool Editor::Command::execute(const String& parameter, Event* triggeringEvent) const
     1227{
     1228    if (!isEnabled(triggeringEvent))
     1229        return false;
     1230    m_frame->document()->updateLayoutIgnorePendingStylesheets();
     1231    return m_command->execute(m_frame.get(), triggeringEvent, m_source, parameter);
     1232}
     1233
     1234bool Editor::Command::execute(Event* triggeringEvent) const
     1235{
     1236    return execute(String(), triggeringEvent);
     1237}
     1238
     1239bool Editor::Command::isSupported() const
     1240{
     1241    return m_command && m_command->isSupported(m_frame.get(), m_source);
     1242}
     1243
     1244bool Editor::Command::isEnabled(Event* triggeringEvent) const
     1245{
     1246    if (!isSupported() || !m_frame || !m_frame->document())
     1247        return false;
     1248    return m_command->isEnabled(m_frame.get(), triggeringEvent);
     1249}
     1250
     1251TriState Editor::Command::state(Event* triggeringEvent) const
     1252{
     1253    if (!isSupported() || !m_frame || !m_frame->document())
     1254        return FalseTriState;
     1255    return m_command->state(m_frame.get(), triggeringEvent);
     1256}
     1257
     1258String Editor::Command::value(Event* triggeringEvent) const
     1259{
     1260    if (!isSupported() || !m_frame || !m_frame->document())
     1261        return String();
     1262    return m_command->value(m_frame.get(), triggeringEvent);
     1263}
     1264
     1265bool Editor::Command::isTextInsertion() const
     1266{
     1267    return m_command && m_command->isTextInsertion;
     1268}
     1269
     1270bool Editor::execCommand(const AtomicString& commandName, Event* triggeringEvent)
     1271{
     1272    return command(commandName).execute(triggeringEvent);
    24081273}
    24091274
  • trunk/WebCore/editing/mac/EditorMac.mm

    r27873 r28626  
    2727#import "Editor.h"
    2828
    29 #import "ClipboardAccessPolicy.h"
    30 #import "Clipboard.h"
    3129#import "ClipboardMac.h"
    32 #import "Document.h"
    3330#import "EditorClient.h"
    34 #import "Element.h"
    35 #import "ExceptionHandlers.h"
    36 #import "Frame.h"
    37 #import "PlatformString.h"
    38 #import "Selection.h"
    39 #import "SelectionController.h"
    40 #import "Sound.h"
    41 #import "TypingCommand.h"
    42 #import "TextIterator.h"
    43 #import "htmlediting.h"
    44 #import "visible_units.h"
    4531
    4632namespace WebCore {
     
    5440void _NSPrependToKillRing(NSString *);
    5541NSString *_NSYankFromKillRing();
    56 NSString *_NSYankPreviousFromKillRing();
    5742void _NSNewKillRingSequence();
    5843void _NSSetKillRingToYankedState();
    59 void _NSResetKillRingOperationFlag();
    6044
    6145}
     
    6448{
    6549    return new ClipboardMac(false, [NSPasteboard generalPasteboard], policy);
     50}
     51
     52NSString* Editor::userVisibleString(NSURL* nsURL)
     53{
     54    if (client())
     55        return client()->userVisibleString(nsURL);
     56    return nil;
    6657}
    6758
     
    7566}
    7667
    77 NSString* Editor::userVisibleString(NSURL* nsURL)
     68void Editor::appendToKillRing(const String& string)
    7869{
    79     if (client())
    80         return client()->userVisibleString(nsURL);
    81     return nil;
     70    initializeKillRingIfNeeded();
     71    _NSAppendToKillRing(string);
    8272}
    8373
    84 void Editor::addToKillRing(Range* range, bool prepend)
     74void Editor::prependToKillRing(const String& string)
    8575{
    8676    initializeKillRingIfNeeded();
    87 
    88     if (m_startNewKillRingSequence)
    89         _NSNewKillRingSequence();
    90 
    91     String text = plainText(range);
    92     text.replace('\\', m_frame->backslashAsCurrencySymbol());
    93     if (prepend)
    94         _NSPrependToKillRing((NSString*)text);
    95     else
    96         _NSAppendToKillRing((NSString*)text);
    97     m_startNewKillRingSequence = false;
     77    _NSPrependToKillRing(string);
    9878}
    9979
    100 void Editor::yank()
     80String Editor::yankFromKillRing()
    10181{
    10282    initializeKillRingIfNeeded();
    103 
    104     if (!canEdit())
    105         return;
    106 
    107     NSString* yankee = _NSYankFromKillRing();
    108     insertTextWithoutSendingTextEvent(yankee, false);
    109     _NSSetKillRingToYankedState();
     83    return _NSYankFromKillRing();
    11084}
    11185
    112 void Editor::yankAndSelect()
     86void Editor::startNewKillRingSequence()
    11387{
    11488    initializeKillRingIfNeeded();
    115 
    116     if (!canEdit())
    117         return;
    118 
    119     NSString* yankee = _NSYankFromKillRing();
    120     insertTextWithoutSendingTextEvent(yankee, true);
    121     _NSSetKillRingToYankedState();
     89    _NSNewKillRingSequence();
    12290}
    12391
    124 void Editor::setMark()
     92void Editor::setKillRingToYankedState()
    12593{
    126     m_frame->setMark(m_frame->selectionController()->selection());
    127 }
    128 
    129 static RefPtr<Range> unionDOMRanges(Range* a, Range* b)
    130 {
    131     ExceptionCode ec = 0;
    132     Range* start = a->compareBoundaryPoints(Range::START_TO_START, b, ec) <= 0 ? a : b;
    133     ASSERT(!ec);
    134     Range* end = a->compareBoundaryPoints(Range::END_TO_END, b, ec) <= 0 ? b : a;
    135     ASSERT(!ec);
    136 
    137     return new Range(a->startContainer(ec)->ownerDocument(), start->startContainer(ec), start->startOffset(ec), end->endContainer(ec), end->endOffset(ec));
    138 }
    139 
    140 void Editor::deleteToMark()
    141 {
    142     if (!canEdit())
    143         return;
    144 
    145     RefPtr<Range> mark = m_frame->mark().toRange();
    146     if (mark) {
    147         SelectionController* selectionController = m_frame->selectionController();
    148         bool selected = selectionController->setSelectedRange(unionDOMRanges(mark.get(), selectedRange().get()).get(), DOWNSTREAM, true);
    149         ASSERT(selected);
    150         if (!selected)
    151             return;
    152     }
    153 
    154     performDelete();
    155     m_frame->setMark(m_frame->selectionController()->selection());
    156 }
    157 
    158 void Editor::selectToMark()
    159 {
    160     RefPtr<Range> mark = m_frame->mark().toRange();
    161     RefPtr<Range> selection = selectedRange();
    162     if (!mark || !selection) {
    163         systemBeep();
    164         return;
    165     }
    166     m_frame->selectionController()->setSelectedRange(unionDOMRanges(mark.get(), selection.get()).get(), DOWNSTREAM, true);
    167 }
    168 
    169 void Editor::swapWithMark()
    170 {
    171     const Selection& mark = m_frame->mark();
    172     Selection selection = m_frame->selectionController()->selection();
    173     if (mark.isNone() || selection.isNone()) {
    174         systemBeep();
    175         return;
    176     }
    177 
    178     m_frame->selectionController()->setSelection(mark);
    179     m_frame->setMark(selection);
     94    initializeKillRingIfNeeded();
     95    _NSSetKillRingToYankedState();
    18096}
    18197
  • trunk/WebCore/loader/FrameLoader.cpp

    r28468 r28626  
    11221122}
    11231123
    1124 static HashSet<String, CaseInsensitiveHash<String> >& localSchemes()
    1125 {
    1126     static HashSet<String, CaseInsensitiveHash<String> > localSchemes;
     1124static HashSet<String, CaseFoldingHash>& localSchemes()
     1125{
     1126    static HashSet<String, CaseFoldingHash> localSchemes;
    11271127
    11281128    if (localSchemes.isEmpty()) {
  • trunk/WebCore/page/Frame.cpp

    r28496 r28626  
    880880}
    881881
    882 static void updateState(CSSMutableStyleDeclaration *desiredStyle, CSSComputedStyleDeclaration *computedStyle, bool& atStart, Frame::TriState& state)
    883 {
    884     DeprecatedValueListConstIterator<CSSProperty> end;
    885     for (DeprecatedValueListConstIterator<CSSProperty> it = desiredStyle->valuesIterator(); it != end; ++it) {
    886         int propertyID = (*it).id();
    887         String desiredProperty = desiredStyle->getPropertyValue(propertyID);
    888         String computedProperty = computedStyle->getPropertyValue(propertyID);
    889         Frame::TriState propertyState = equalIgnoringCase(desiredProperty, computedProperty)
    890             ? Frame::trueTriState : Frame::falseTriState;
    891         if (atStart) {
    892             state = propertyState;
    893             atStart = false;
    894         } else if (state != propertyState) {
    895             state = Frame::mixedTriState;
    896             break;
    897         }
    898     }
    899 }
    900 
    901 Frame::TriState Frame::selectionHasStyle(CSSStyleDeclaration *style) const
    902 {
    903     bool atStart = true;
    904     TriState state = falseTriState;
    905 
    906     RefPtr<CSSMutableStyleDeclaration> mutableStyle = style->makeMutable();
    907 
    908     if (!selectionController()->isRange()) {
    909         Node* nodeToRemove;
    910         RefPtr<CSSComputedStyleDeclaration> selectionStyle = selectionComputedStyle(nodeToRemove);
    911         if (!selectionStyle)
    912             return falseTriState;
    913         updateState(mutableStyle.get(), selectionStyle.get(), atStart, state);
    914         if (nodeToRemove) {
    915             ExceptionCode ec = 0;
    916             nodeToRemove->remove(ec);
    917             ASSERT(ec == 0);
    918         }
    919     } else {
    920         for (Node* node = selectionController()->start().node(); node; node = node->traverseNextNode()) {
    921             RefPtr<CSSComputedStyleDeclaration> computedStyle = new CSSComputedStyleDeclaration(node);
    922             if (computedStyle)
    923                 updateState(mutableStyle.get(), computedStyle.get(), atStart, state);
    924             if (state == mixedTriState)
    925                 break;
    926             if (node == selectionController()->end().node())
    927                 break;
    928         }
    929     }
    930 
    931     return state;
    932 }
    933 
    934882String Frame::selectionStartStylePropertyValue(int stylePropertyID) const
    935883{
  • trunk/WebCore/page/Frame.h

    r28411 r28626  
    274274
    275275    void computeAndSetTypingStyle(CSSStyleDeclaration* , EditAction = EditActionUnspecified);
    276     enum TriState { falseTriState, trueTriState, mixedTriState };
    277     TriState selectionHasStyle(CSSStyleDeclaration*) const;
    278276    String selectionStartStylePropertyValue(int stylePropertyID) const;
    279277    void applyEditingStyleToBodyElement() const;
  • trunk/WebCore/page/mac/WebCoreFrameBridge.h

    r28411 r28626  
    213213- (DOMCSSStyleDeclaration *)typingStyle;
    214214- (void)setTypingStyle:(DOMCSSStyleDeclaration *)style withUndoAction:(WebCore::EditAction)undoAction;
    215 - (NSCellStateValue)selectionHasStyle:(DOMCSSStyleDeclaration *)style;
    216215
    217216- (void)dragSourceMovedTo:(NSPoint)windowLoc;
  • trunk/WebCore/page/mac/WebCoreFrameBridge.mm

    r28411 r28626  
    11621162}
    11631163
    1164 - (NSCellStateValue)selectionHasStyle:(DOMCSSStyleDeclaration *)style
    1165 {
    1166     if (!m_frame)
    1167         return NSOffState;
    1168     switch (m_frame->selectionHasStyle([style _CSSStyleDeclaration])) {
    1169         case Frame::falseTriState:
    1170             return NSOffState;
    1171         case Frame::trueTriState:
    1172             return NSOnState;
    1173         case Frame::mixedTriState:
    1174             return NSMixedState;
    1175     }
    1176     return NSOffState;
    1177 }
    1178 
    11791164- (NSFont *)fontForSelection:(BOOL *)hasMultipleFonts
    11801165{
  • trunk/WebCore/platform/ContextMenu.cpp

    r24529 r28626  
    407407}
    408408
    409 static bool triStateToBool(Frame::TriState state)
    410 {
    411     return state == Frame::trueTriState;
    412 }
    413 
    414409void ContextMenu::checkOrEnableIfNeeded(ContextMenuItem& item) const
    415410{
     
    438433            String direction = item.action() == ContextMenuItemTagLeftToRight ? "ltr" : "rtl";
    439434            style->setProperty(CSS_PROP_DIRECTION, direction, false, ec);
    440             shouldCheck = triStateToBool(frame->selectionHasStyle(style.get()));
     435            shouldCheck = frame->editor()->selectionHasStyle(style.get()) != FalseTriState;
    441436            shouldEnable = true;
    442437            break;
     
    459454            RefPtr<CSSStyleDeclaration> style = frame->document()->createCSSStyleDeclaration();
    460455            style->setProperty(CSS_PROP__WEBKIT_TEXT_DECORATIONS_IN_EFFECT, "underline", false, ec);
    461             shouldCheck = triStateToBool(frame->selectionHasStyle(style.get()));
     456            shouldCheck = frame->editor()->selectionHasStyle(style.get()) != FalseTriState;
    462457            shouldEnable = frame->editor()->canEditRichly();
    463458            break;
     
    477472            RefPtr<CSSStyleDeclaration> style = frame->document()->createCSSStyleDeclaration();
    478473            style->setProperty(CSS_PROP_FONT_STYLE, "italic", false, ec);
    479             shouldCheck = triStateToBool(frame->selectionHasStyle(style.get()));
     474            shouldCheck = frame->editor()->selectionHasStyle(style.get()) != FalseTriState;
    480475            shouldEnable = frame->editor()->canEditRichly();
    481476            break;
     
    485480            RefPtr<CSSStyleDeclaration> style = frame->document()->createCSSStyleDeclaration();
    486481            style->setProperty(CSS_PROP_FONT_WEIGHT, "bold", false, ec);
    487             shouldCheck = triStateToBool(frame->selectionHasStyle(style.get()));
     482            shouldCheck = frame->editor()->selectionHasStyle(style.get()) != FalseTriState;
    488483            shouldEnable = frame->editor()->canEditRichly();
    489484            break;
  • trunk/WebCore/platform/graphics/FontCache.cpp

    r28234 r28626  
    6666{
    6767    unsigned hashCodes[3] = {
    68         CaseInsensitiveHash<String>::hash(fontKey.m_family),
     68        CaseFoldingHash::hash(fontKey.m_family),
    6969        fontKey.m_size,
    7070        static_cast<unsigned>(fontKey.m_bold) << 2 | static_cast<unsigned>(fontKey.m_italic) << 1 | static_cast<unsigned>(fontKey.m_printerFont)
  • trunk/WebCore/platform/network/HTTPHeaderMap.h

    r18874 r28626  
    3333namespace WebCore {
    3434
    35     typedef HashMap<String, String, CaseInsensitiveHash<String> > HTTPHeaderMap;
     35    typedef HashMap<String, String, CaseFoldingHash> HTTPHeaderMap;
    3636
    3737} // namespace WebCore
  • trunk/WebCore/platform/text/PlatformString.h

    r28620 r28626  
    11/*
    2  * This file is part of the DOM implementation for KDE.
    3  *
    42 * (C) 1999 Lars Knoll (knoll@kde.org)
    5  * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc.
     3 * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
    64 *
    75 * This library is free software; you can redistribute it and/or
     
    4644
    4745class CString;
    48    
     46struct StringHash;
     47
    4948/**
    5049 * Currently, strings are explicitly shared (they behave like pointers), meaning
     
    243242namespace WTF {
    244243
    245     // StrHash is the default hash for String
     244    // StringHash is the default hash for String
    246245    template<typename T> struct DefaultHash;
    247     template<typename T> struct StrHash;
    248246    template<> struct DefaultHash<WebCore::String> {
    249         typedef StrHash<WebCore::String> Hash;
     247        typedef WebCore::StringHash Hash;
    250248    };
    251249
  • trunk/WebCore/platform/text/StringHash.h

    r28234 r28626  
    11/*
    2  * Copyright (C) 2006 Apple Computer, Inc.
     2 * Copyright (C) 2006, 2007 Apple Inc. All rights reserved
    33 *
    44 * This library is free software; you can redistribute it and/or
     
    2727#include <wtf/unicode/Unicode.h>
    2828
    29 namespace WTF {
    30 
    31     template<typename T> struct StrHash;
    32 
    33     template<> struct StrHash<WebCore::StringImpl*> {
    34         static unsigned hash(const WebCore::StringImpl* key) { return key->hash(); }
    35         static bool equal(const WebCore::StringImpl* a, const WebCore::StringImpl* b)
     29namespace WebCore {
     30
     31    struct StringHash {
     32        static unsigned hash(const StringImpl* key) { return key->hash(); }
     33        static bool equal(const StringImpl* a, const StringImpl* b)
    3634        {
    3735            if (a == b)
     
    5856            return true;
    5957        }
     58
     59        static unsigned hash(const RefPtr<StringImpl>& key) { return key->hash(); }
     60        static bool equal(const RefPtr<StringImpl>& a, const RefPtr<StringImpl>& b)
     61        {
     62            return equal(a.get(), b.get());
     63        }
     64
     65        static unsigned hash(const String& key) { return key.impl()->hash(); }
     66        static bool equal(const String& a, const String& b)
     67        {
     68            return equal(a.impl(), b.impl());
     69        }
     70
    6071        static const bool safeToCompareToEmptyOrDeleted = false;
    6172    };
    62    
    63     template<> struct StrHash<WebCore::AtomicStringImpl*> : public StrHash<WebCore::StringImpl*> { };
    64 
    65     template<> struct StrHash<RefPtr<WebCore::StringImpl> > {
    66         static unsigned hash(const RefPtr<WebCore::StringImpl>& key) { return key->hash(); }
    67         static bool equal(const RefPtr<WebCore::StringImpl>& a, const RefPtr<WebCore::StringImpl>& b)
    68         {
    69             return StrHash<WebCore::StringImpl*>::equal(a.get(), b.get());
    70         }
    71         static const bool safeToCompareToEmptyOrDeleted = false;
    72     };
    73 
    74     template<> struct StrHash<WebCore::String> {
    75         static unsigned hash(const WebCore::String& key) { return key.impl()->hash(); }
    76         static bool equal(const WebCore::String& a, const WebCore::String& b)
    77         {
    78             return StrHash<WebCore::StringImpl*>::equal(a.impl(), b.impl());
    79         }
    80         static const bool safeToCompareToEmptyOrDeleted = false;
    81     };
    82 
    83     template<typename T> struct CaseInsensitiveHash;
    84 
    85     template<> class CaseInsensitiveHash<WebCore::StringImpl*> {
     73
     74    class CaseFoldingHash {
    8675    private:
    8776        // Golden ratio - arbitrary start value to avoid mapping all 0's to all 0's
     
    9079        // Paul Hsieh's SuperFastHash
    9180        // http://www.azillionmonkeys.com/qed/hash.html
    92         static unsigned hash(const WebCore::StringImpl* str)
     81        static unsigned hash(const StringImpl* str)
    9382        {
    9483            unsigned l = str->length();
     
    178167        }
    179168       
    180         static bool equal(const WebCore::StringImpl* a, const WebCore::StringImpl* b)
     169        static bool equal(const StringImpl* a, const StringImpl* b)
    181170        {
    182171            if (a == b)
     
    190179        }
    191180
     181        static unsigned hash(const RefPtr<StringImpl>& key)
     182        {
     183            return hash(key.get());
     184        }
     185
     186        static bool equal(const RefPtr<StringImpl>& a, const RefPtr<StringImpl>& b)
     187        {
     188            return equal(a.get(), b.get());
     189        }
     190
     191        static unsigned hash(const String& key)
     192        {
     193            return hash(key.impl());
     194        }
     195        static bool equal(const String& a, const String& b)
     196        {
     197            return equal(a.impl(), b.impl());
     198        }
     199
    192200        static const bool safeToCompareToEmptyOrDeleted = false;
    193201    };
    194202
    195     template<> struct CaseInsensitiveHash<WebCore::AtomicStringImpl*> : public CaseInsensitiveHash<WebCore::StringImpl*> { };
    196 
    197     template<> struct CaseInsensitiveHash<RefPtr<WebCore::StringImpl> > {
    198         static unsigned hash(const RefPtr<WebCore::StringImpl>& key)
    199         {
    200             return CaseInsensitiveHash<WebCore::StringImpl*>::hash(key.get());
    201         }
    202 
    203         static bool equal(const RefPtr<WebCore::StringImpl>& a, const RefPtr<WebCore::StringImpl>& b)
    204         {
    205             return CaseInsensitiveHash<WebCore::StringImpl*>::equal(a.get(), b.get());
    206         }
    207 
    208         static const bool safeToCompareToEmptyOrDeleted = false;
    209     };
    210 
    211     template<> struct CaseInsensitiveHash<WebCore::String> {
    212         static unsigned hash(const WebCore::String& key)
    213         {
    214             return CaseInsensitiveHash<WebCore::StringImpl*>::hash(key.impl());
    215         }
    216         static bool equal(const WebCore::String& a, const WebCore::String& b)
    217         {
    218             return CaseInsensitiveHash<WebCore::StringImpl*>::equal(a.impl(), b.impl());
    219         }
    220 
    221         static const bool safeToCompareToEmptyOrDeleted = false;
    222     };
     203}
     204
     205namespace WTF {
    223206
    224207    // store WebCore::String as StringImpl*
     
    244227    // share code between StringImpl*, RefPtr<StringImpl>, and String
    245228
    246     template<> struct HashKeyStorageTraits<StrHash<RefPtr<WebCore::StringImpl> >, HashTraits<RefPtr<WebCore::StringImpl> > > {
    247         typedef StrHash<WebCore::StringImpl*> Hash;
    248         typedef HashTraits<WebCore::StringImpl*> Traits;
    249     };
    250     template<> struct HashKeyStorageTraits<StrHash<WebCore::String>, HashTraits<WebCore::String> > {
    251         typedef StrHash<WebCore::StringImpl*> Hash;
    252         typedef HashTraits<WebCore::StringImpl*> Traits;
    253     };
    254 
    255     template<> struct HashKeyStorageTraits<CaseInsensitiveHash<RefPtr<WebCore::StringImpl> >, HashTraits<RefPtr<WebCore::StringImpl> > > {
    256         typedef CaseInsensitiveHash<WebCore::StringImpl*> Hash;
    257         typedef HashTraits<WebCore::StringImpl*> Traits;
    258     };
    259     template<> struct HashKeyStorageTraits<CaseInsensitiveHash<WebCore::String>, HashTraits<WebCore::String> > {
    260         typedef CaseInsensitiveHash<WebCore::StringImpl*> Hash;
     229    template<> struct HashKeyStorageTraits<WebCore::StringHash, HashTraits<RefPtr<WebCore::StringImpl> > > {
     230        typedef WebCore::StringHash Hash;
     231        typedef HashTraits<WebCore::StringImpl*> Traits;
     232    };
     233    template<> struct HashKeyStorageTraits<WebCore::StringHash, HashTraits<WebCore::String> > {
     234        typedef WebCore::StringHash Hash;
     235        typedef HashTraits<WebCore::StringImpl*> Traits;
     236    };
     237
     238    template<> struct HashKeyStorageTraits<WebCore::CaseFoldingHash, HashTraits<RefPtr<WebCore::StringImpl> > > {
     239        typedef WebCore::CaseFoldingHash Hash;
     240        typedef HashTraits<WebCore::StringImpl*> Traits;
     241    };
     242    template<> struct HashKeyStorageTraits<WebCore::CaseFoldingHash, HashTraits<WebCore::String> > {
     243        typedef WebCore::CaseFoldingHash Hash;
    261244        typedef HashTraits<WebCore::StringImpl*> Traits;
    262245    };
     
    264247}
    265248
    266 using WTF::CaseInsensitiveHash;
    267 
    268249#endif
  • trunk/WebCore/platform/text/StringImpl.cpp

    r28620 r28626  
    10471047bool equal(const StringImpl* a, const StringImpl* b)
    10481048{
    1049     return StrHash<StringImpl*>::equal(a, b);
     1049    return StringHash::equal(a, b);
    10501050}
    10511051
     
    10721072bool equalIgnoringCase(const StringImpl* a, const StringImpl* b)
    10731073{
    1074     return CaseInsensitiveHash<StringImpl*>::equal(a, b);
     1074    return CaseFoldingHash::equal(a, b);
    10751075}
    10761076
  • trunk/WebCore/platform/text/StringImpl.h

    r28620 r28626  
    11/*
    2  * This file is part of the DOM implementation for KDE.
    3  *
    42 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
    5  * Copyright (C) 2005, 2006 Apple Computer, Inc.
     3 * Copyright (C) 2005, 2006, 2007 Apple Inc. All rights reserved.
    64 *
    75 * This library is free software; you can redistribute it and/or
     
    4442class AtomicString;
    4543class DeprecatedString;
    46 struct UCharBufferTranslator;
    4744struct CStringTranslator;
    4845struct Length;
     46struct StringHash;
     47struct UCharBufferTranslator;
    4948
    5049class StringImpl : public RefCounted<StringImpl> {
     
    181180namespace WTF {
    182181
    183     // StrHash is the default hash for StringImpl* and RefPtr<StringImpl>
     182    // WebCore::StringHash is the default hash for StringImpl* and RefPtr<StringImpl>
    184183    template<typename T> struct DefaultHash;
    185     template<typename T> struct StrHash;
    186184    template<> struct DefaultHash<WebCore::StringImpl*> {
    187         typedef StrHash<WebCore::StringImpl*> Hash;
     185        typedef WebCore::StringHash Hash;
    188186    };
    189187    template<> struct DefaultHash<RefPtr<WebCore::StringImpl> > {
    190         typedef StrHash<RefPtr<WebCore::StringImpl> > Hash;
     188        typedef WebCore::StringHash Hash;
    191189    };
    192190
  • trunk/WebCore/rendering/RenderPartObject.cpp

    r27982 r28626  
    151151          serviceType = o->m_serviceType;
    152152     
    153       HashSet<StringImpl*, CaseInsensitiveHash<StringImpl*> > uniqueParamNames;
     153      HashSet<StringImpl*, CaseFoldingHash> uniqueParamNames;
    154154     
    155155      // Scan the PARAM children.
  • trunk/WebCore/rendering/RenderTreeAsText.cpp

    r26843 r28626  
    3434#include "HTMLNames.h"
    3535#include "InlineTextBox.h"
    36 #include "JSEditor.h"
    3736#include "RenderBR.h"
    3837#include "RenderListMarker.h"
  • trunk/WebCore/xml/XMLHttpRequest.cpp

    r28301 r28626  
    9292static bool canSetRequestHeader(const String& name)
    9393{
    94     static HashSet<String, CaseInsensitiveHash<String> > forbiddenHeaders;
     94    static HashSet<String, CaseFoldingHash> forbiddenHeaders;
    9595    static String proxyString("proxy-");
    9696   
  • trunk/WebKit/mac/ChangeLog

    r28620 r28626  
     12007-12-11  Darin Adler  <darin@apple.com>
     2
     3        Reviewed by Geoff.
     4
     5        - change more editing commands to use WebCore::Editor
     6        - change to use the new WebCore::Editor::command() function
     7
     8        * WebView/WebHTMLView.mm: Changed alignCenter, alignJustified, alignLeft,
     9        alignRight, cut, copy, deleteToMark, indent, insertNewlineIgnoringFieldEditor,
     10        insertTabIgnoringFieldEditor, outdent, selectAll, selectToMark, setMark,
     11        subscript, superscript, swapWithMark, underline, unscript, yank, and yankAndSelect
     12        to use the "forward to WebCore" macro instead of having hand-written implementations.
     13        (kit): Added function to change a TriState to an AppKit-style tri-state value.
     14        (-[WebHTMLView coreCommandBySelector:]): Added. No longer converts case of the
     15        first character or copies the selector name, since the Editor commands are not case
     16        sensitive any more. Returns a command object.
     17        (-[WebHTMLView coreCommandByName:]): Added.
     18        (-[WebHTMLView executeCoreCommandBySelector:]): Renamed from callWebCoreCommand:,
     19        and changed to use the new coreCommandBySelector: method.
     20        (-[WebHTMLView executeCoreCommandByName:]): Added.
     21        (-[WebHTMLView validateUserInterfaceItemWithoutDelegate:]): Changed all the
     22        methods that call through to WebCore to also use the state() and isEnabled()
     23        functions on the commands for the menu item state and user interface item enabling.
     24        (-[WebHTMLView _handleStyleKeyEquivalent:]): Use ToggleBold and ToggleItalic by
     25        name rather than having local methods for them; no need for methods with a single
     26        call site.
     27        (-[WebHTMLView insertParagraphSeparator:]): Use executeCoreCommandByName: rather
     28        than the deprecated execCommand().
     29        (-[WebHTMLView doCommandBySelector:]): Changed to use command().execute() rather
     30        than the deprecated execCommand().
     31        * WebView/WebHTMLViewInternal.h: Removed some unneeded method declarations.
     32
    1332007-12-07  Alexey Proskuryakov  <ap@webkit.org>
    234
  • trunk/WebKit/mac/WebView/WebHTMLView.mm

    r28620 r28626  
    362362};
    363363
     364static NSCellStateValue kit(TriState state)
     365{
     366    switch (state) {
     367        case FalseTriState:
     368            return NSOffState;
     369        case TrueTriState:
     370            return NSOnState;
     371        case MixedTriState:
     372            return NSMixedState;
     373    }
     374    ASSERT_NOT_REACHED();
     375    return NSOffState;
     376}
     377
    364378@implementation WebHTMLViewPrivate
    365 
    366379
    367380+ (void)initialize
     
    20482061}
    20492062
    2050 static AtomicString selectorToCommandName(SEL selector)
    2051 {
    2052     // Capitalize the first letter of the selector, since we use capitalized command
    2053     // names in the Editor object (why?). And remove the trailing colon.
    2054     // And change a few command names into ones supported by WebCore::Editor.
    2055 
     2063static String comandNameForSelector(SEL selector)
     2064{
     2065    // Change a few command names into ones supported by WebCore::Editor.
    20562066    if (selector == @selector(insertParagraphSeparator:) || selector == @selector(insertNewlineIgnoringFieldEditor:))
    20572067        return "InsertNewline";
     
    20592069        return "InsertTab";
    20602070
     2071    // Remove the trailing colon.
    20612072    const char* selectorName = sel_getName(selector);
    20622073    size_t selectorNameLength = strlen(selectorName);
    20632074    ASSERT(selectorNameLength >= 2);
    20642075    ASSERT(selectorName[selectorNameLength - 1] == ':');
    2065     Vector<char, 256> commandName(selectorNameLength - 1 + 1);
    2066     commandName[0] = toASCIIUpper(selectorName[0]);
    2067     memcpy(&commandName[1], &selectorName[1], selectorNameLength - 2);
    2068     commandName[selectorNameLength - 1] = 0;
    2069 
    2070     return AtomicString(commandName.data());
    2071 }
    2072 
    2073 - (void)callWebCoreCommand:(SEL)selector
    2074 {
    2075     if ([self callDelegateDoCommandBySelectorIfNeeded:selector])
    2076         return;
    2077 
     2076    return String(selectorName, selectorNameLength - 1);
     2077}
     2078
     2079- (Editor::Command)coreCommandBySelector:(SEL)selector
     2080{
    20782081    Frame* coreFrame = core([self _frame]);
    20792082    if (!coreFrame)
    2080         return;
    2081 
    2082     coreFrame->editor()->execCommand(selectorToCommandName(selector));
     2083        return Editor::Command();
     2084    return coreFrame->editor()->command(comandNameForSelector(selector));
     2085}
     2086
     2087- (Editor::Command)coreCommandByName:(const char*)name
     2088{
     2089    Frame* coreFrame = core([self _frame]);
     2090    if (!coreFrame)
     2091        return Editor::Command();
     2092    return coreFrame->editor()->command(name);
     2093}
     2094
     2095- (void)executeCoreCommandBySelector:(SEL)selector
     2096{
     2097    if ([self callDelegateDoCommandBySelectorIfNeeded:selector])
     2098        return;
     2099    [self coreCommandBySelector:selector].execute();
     2100}
     2101
     2102- (void)executeCoreCommandByName:(const char*)name
     2103{
     2104    [self coreCommandByName:name].execute();
    20832105}
    20842106
     
    20882110// added to this list.
    20892111
    2090 #define WEBCORE_COMMAND(command) - (void)command:(id)sender { [self callWebCoreCommand:_cmd]; }
    2091 
     2112// FIXME: Maybe we should set things up so that all these share a single method implementation function.
     2113// The functions are identical.
     2114
     2115#define WEBCORE_COMMAND(command) - (void)command:(id)sender { [self executeCoreCommandBySelector:_cmd]; }
     2116
     2117WEBCORE_COMMAND(alignCenter)
     2118WEBCORE_COMMAND(alignJustified)
     2119WEBCORE_COMMAND(alignLeft)
     2120WEBCORE_COMMAND(alignRight)
     2121WEBCORE_COMMAND(cut)
     2122WEBCORE_COMMAND(copy)
     2123WEBCORE_COMMAND(deleteToMark)
    20922124WEBCORE_COMMAND(deleteWordBackward)
    20932125WEBCORE_COMMAND(deleteWordForward)
     2126WEBCORE_COMMAND(indent)
    20942127WEBCORE_COMMAND(insertBacktab)
    20952128WEBCORE_COMMAND(insertLineBreak)
    20962129WEBCORE_COMMAND(insertNewline)
     2130WEBCORE_COMMAND(insertNewlineIgnoringFieldEditor)
     2131WEBCORE_COMMAND(insertParagraphSeparator)
    20972132WEBCORE_COMMAND(insertTab)
     2133WEBCORE_COMMAND(insertTabIgnoringFieldEditor)
    20982134WEBCORE_COMMAND(moveBackward)
    20992135WEBCORE_COMMAND(moveBackwardAndModifySelection)
     
    21342170WEBCORE_COMMAND(moveWordRight)
    21352171WEBCORE_COMMAND(moveWordRightAndModifySelection)
     2172WEBCORE_COMMAND(outdent)
     2173WEBCORE_COMMAND(selectAll)
     2174WEBCORE_COMMAND(selectToMark)
     2175WEBCORE_COMMAND(setMark)
     2176WEBCORE_COMMAND(subscript)
     2177WEBCORE_COMMAND(superscript)
     2178WEBCORE_COMMAND(swapWithMark)
    21362179WEBCORE_COMMAND(transpose)
     2180WEBCORE_COMMAND(underline)
     2181WEBCORE_COMMAND(unscript)
     2182WEBCORE_COMMAND(yank)
     2183WEBCORE_COMMAND(yankAndSelect)
    21372184
    21382185#undef WEBCORE_COMMAND
     
    21812228}
    21822229
    2183 - (void)selectAll:(id)sender
    2184 {
    2185     COMMAND_PROLOGUE
    2186 
    2187     [self selectAll];
    2188 }
    2189 
    21902230// jumpToSelection is the old name for what AppKit now calls centerSelectionInVisibleArea. Safari
    21912231// was using the old jumpToSelection selector in its menu. Newer versions of Safari will us the
     
    21992239    if (Frame* coreFrame = core([self _frame]))
    22002240        coreFrame->revealSelection(RenderLayer::gAlignCenterAlways);
     2241}
     2242
     2243- (NSCellStateValue)selectionHasStyle:(CSSStyleDeclaration*)style
     2244{
     2245    Frame* coreFrame = core([self _frame]);
     2246    if (!coreFrame)
     2247        return NSOffState;
     2248    return kit(coreFrame->editor()->selectionHasStyle(style));
    22012249}
    22022250
     
    22202268        }
    22212269    }
    2222    
    2223     if (action == @selector(changeSpelling:)
    2224             || action == @selector(_changeSpellingFromMenu:)
    2225             || action == @selector(checkSpelling:)
    2226             || action == @selector(complete:)
    2227             || action == @selector(deleteBackward:)
    2228             || action == @selector(deleteBackwardByDecomposingPreviousCharacter:)
    2229             || action == @selector(deleteForward:)
    2230             || action == @selector(deleteToBeginningOfLine:)
    2231             || action == @selector(deleteToBeginningOfParagraph:)
    2232             || action == @selector(deleteToEndOfLine:)
    2233             || action == @selector(deleteToEndOfParagraph:)
     2270
     2271    if (action == @selector(alignCenter:)
     2272            || action == @selector(alignJustified:)
     2273            || action == @selector(alignLeft:)
     2274            || action == @selector(alignRight:)
     2275            || action == @selector(cut:)
     2276            || action == @selector(copy:)
    22342277            || action == @selector(deleteToMark:)
    22352278            || action == @selector(deleteWordBackward:)
    22362279            || action == @selector(deleteWordForward:)
     2280            || action == @selector(indent:)
    22372281            || action == @selector(insertBacktab:)
    22382282            || action == @selector(insertLineBreak:)
     
    22562300            || action == @selector(moveToBeginningOfDocument:)
    22572301            || action == @selector(moveToBeginningOfDocumentAndModifySelection:)
    2258             || action == @selector(moveToBeginningOfSentence:)
    2259             || action == @selector(moveToBeginningOfSentenceAndModifySelection:)
    22602302            || action == @selector(moveToBeginningOfLine:)
    22612303            || action == @selector(moveToBeginningOfLineAndModifySelection:)
    22622304            || action == @selector(moveToBeginningOfParagraph:)
    22632305            || action == @selector(moveToBeginningOfParagraphAndModifySelection:)
     2306            || action == @selector(moveToBeginningOfSentence:)
     2307            || action == @selector(moveToBeginningOfSentenceAndModifySelection:)
    22642308            || action == @selector(moveToEndOfDocument:)
    22652309            || action == @selector(moveToEndOfDocumentAndModifySelection:)
    2266             || action == @selector(moveToEndOfSentence:)
    2267             || action == @selector(moveToEndOfSentenceAndModifySelection:)
    22682310            || action == @selector(moveToEndOfLine:)
    22692311            || action == @selector(moveToEndOfLineAndModifySelection:)
    22702312            || action == @selector(moveToEndOfParagraph:)
    22712313            || action == @selector(moveToEndOfParagraphAndModifySelection:)
     2314            || action == @selector(moveToEndOfSentence:)
     2315            || action == @selector(moveToEndOfSentenceAndModifySelection:)
    22722316            || action == @selector(moveUp:)
    22732317            || action == @selector(moveUpAndModifySelection:)
     
    22802324            || action == @selector(moveWordRight:)
    22812325            || action == @selector(moveWordRightAndModifySelection:)
     2326            || action == @selector(outdent:)
     2327            || action == @selector(selectAll:)
     2328            || action == @selector(selectToMark:)
     2329            || action == @selector(setMark:)
     2330            || action == @selector(subscript:)
     2331            || action == @selector(superscript:)
     2332            || action == @selector(swapWithMark:)
     2333            || action == @selector(transpose:)
     2334            || action == @selector(underline:)
     2335            || action == @selector(unscript:)
     2336            || action == @selector(yank:)
     2337            || action == @selector(yankAndSelect:)) {
     2338        Editor::Command command = [self coreCommandBySelector:action];
     2339        NSMenuItem *menuItem = (NSMenuItem *)item;
     2340        if ([menuItem isKindOfClass:[NSMenuItem class]])
     2341            [menuItem setState:kit(command.state())];
     2342        return command.isEnabled();
     2343    }
     2344
     2345    if (action == @selector(changeSpelling:)
     2346            || action == @selector(_changeSpellingFromMenu:)
     2347            || action == @selector(checkSpelling:)
     2348            || action == @selector(complete:)
     2349            || action == @selector(deleteBackward:)
     2350            || action == @selector(deleteBackwardByDecomposingPreviousCharacter:)
     2351            || action == @selector(deleteForward:)
     2352            || action == @selector(deleteToBeginningOfLine:)
     2353            || action == @selector(deleteToBeginningOfParagraph:)
     2354            || action == @selector(deleteToEndOfLine:)
     2355            || action == @selector(deleteToEndOfParagraph:)
    22822356            || action == @selector(pageDown:)
    22832357            || action == @selector(pageDownAndModifySelection:)
    22842358            || action == @selector(pageUp:)
    22852359            || action == @selector(pageUpAndModifySelection:)
    2286             || action == @selector(pasteFont:)
    2287             || action == @selector(transpose:)
    2288             || action == @selector(yank:)
    2289             || action == @selector(yankAndSelect:))
     2360            || action == @selector(pasteFont:))
    22902361        return [self _canEdit];
    22912362   
     
    23072378            NSWritingDirection writingDirection = static_cast<NSWritingDirection>([item tag]);
    23082379            if (writingDirection == NSWritingDirectionNatural) {
    2309                 [menuItem setState:NO];
     2380                [menuItem setState:NSOffState];
    23102381                return NO;
    23112382            }
    2312             DOMCSSStyleDeclaration* style = [self _emptyStyle];
    2313             [style setDirection:writingDirection == NSWritingDirectionLeftToRight ? @"LTR" : @"RTL"];
    2314             [menuItem setState:[[self _bridge] selectionHasStyle:style]];
     2383            RefPtr<CSSStyleDeclaration> style = new CSSMutableStyleDeclaration;
     2384            ExceptionCode ec;
     2385            style->setProperty("direction", writingDirection == NSWritingDirectionLeftToRight ? "LTR" : "RTL", ec);
     2386            [menuItem setState:frame->editor()->selectionHasStyle(style.get())];
    23152387        }
    23162388        return [self _canEdit];
     
    23202392        NSMenuItem *menuItem = (NSMenuItem *)item;
    23212393        if ([menuItem isKindOfClass:[NSMenuItem class]]) {
    2322             DOMCSSStyleDeclaration* rtl = [self _emptyStyle];
    2323             [rtl setDirection:@"RTL"];
     2394            RefPtr<CSSStyleDeclaration> style = new CSSMutableStyleDeclaration;
     2395            ExceptionCode ec;
     2396            style->setProperty("direction", "RTL", ec);
    23242397            // Take control of the title of the menu item, instead of just checking/unchecking it because otherwise
    23252398            // we don't know what the check would mean.
    2326             [menuItem setTitle:[[self _bridge] selectionHasStyle:rtl] ? UI_STRING("Left to Right", "Left to Right context menu item") : UI_STRING("Right to Left", "Right to Left context menu item")];
     2399            [menuItem setTitle:frame->editor()->selectionHasStyle(style.get())
     2400                ? UI_STRING("Left to Right", "Left to Right context menu item")
     2401                : UI_STRING("Right to Left", "Right to Left context menu item")];
    23272402        }
    23282403        return [self _canEdit];
    23292404    }
    23302405   
    2331     if (action == @selector(alignCenter:)
    2332             || action == @selector(alignLeft:)
    2333             || action == @selector(alignJustified:)
    2334             || action == @selector(alignRight:)
    2335             || action == @selector(changeAttributes:)
     2406    if (action == @selector(changeAttributes:)
    23362407            || action == @selector(changeColor:)       
    2337             || action == @selector(changeFont:)
    2338             || action == @selector(indent:)
    2339             || action == @selector(outdent:))
     2408            || action == @selector(changeFont:))
    23402409        return [self _canEditRichly];
    23412410   
     
    23472416    if (action == @selector(centerSelectionInVisibleArea:)
    23482417               || action == @selector(jumpToSelection:)
    2349                || action == @selector(copyFont:)
    2350                || action == @selector(setMark:))
     2418               || action == @selector(copyFont:))
    23512419        return [self _hasSelection] || ([self _isEditable] && [self _hasInsertionPoint]);
    23522420   
    23532421    if (action == @selector(changeDocumentBackgroundColor:))
    23542422        return [[self _webView] isEditable] && [self _canEditRichly];
    2355    
    2356     if (action == @selector(copy:))
    2357         return frame && (frame->editor()->canDHTMLCopy() || frame->editor()->canCopy());
    2358    
    2359     if (action == @selector(cut:))
    2360         return frame && (frame->editor()->canDHTMLCut() || frame->editor()->canCut());
    23612423   
    23622424    if (action == @selector(delete:))
     
    23782440        // FIXME: Not yet implemented.
    23792441        return NO;
    2380    
    2381     if (action == @selector(selectToMark:)
    2382             || action == @selector(swapWithMark:))
    2383         return [self _hasSelectionOrInsertionPoint] && [[self _bridge] markDOMRange] != nil;
    2384    
    2385     if (action == @selector(subscript:)) {
    2386         NSMenuItem *menuItem = (NSMenuItem *)item;
    2387         if ([menuItem isKindOfClass:[NSMenuItem class]]) {
    2388             DOMCSSStyleDeclaration *style = [self _emptyStyle];
    2389             [style setVerticalAlign:@"sub"];
    2390             [menuItem setState:[[self _bridge] selectionHasStyle:style]];
    2391         }
    2392         return [self _canEditRichly];
    2393     }
    2394    
    2395     if (action == @selector(superscript:)) {
    2396         NSMenuItem *menuItem = (NSMenuItem *)item;
    2397         if ([menuItem isKindOfClass:[NSMenuItem class]]) {
    2398             DOMCSSStyleDeclaration *style = [self _emptyStyle];
    2399             [style setVerticalAlign:@"super"];
    2400             [menuItem setState:[[self _bridge] selectionHasStyle:style]];
    2401         }
    2402         return [self _canEditRichly];
    2403     }
    2404    
    2405     if (action == @selector(underline:)) {
    2406         NSMenuItem *menuItem = (NSMenuItem *)item;
    2407         if ([menuItem isKindOfClass:[NSMenuItem class]]) {
    2408             DOMCSSStyleDeclaration *style = [self _emptyStyle];
    2409             [style setProperty:@"-khtml-text-decorations-in-effect" value:@"underline" priority:@""];
    2410             [menuItem setState:[[self _bridge] selectionHasStyle:style]];
    2411         }
    2412         return [self _canEditRichly];
    2413     }
    2414    
    2415     if (action == @selector(unscript:)) {
    2416         NSMenuItem *menuItem = (NSMenuItem *)item;
    2417         if ([menuItem isKindOfClass:[NSMenuItem class]]) {
    2418             DOMCSSStyleDeclaration *style = [self _emptyStyle];
    2419             [style setVerticalAlign:@"baseline"];
    2420             [menuItem setState:[[self _bridge] selectionHasStyle:style]];
    2421         }
    2422         return [self _canEditRichly];
    2423     }
    24242442   
    24252443    if (action == @selector(_lookUpInDictionaryFromMenu:)) {
     
    38993917}
    39003918
    3901 - (void)_toggleBold
    3902 {
    3903     if (Frame* coreFrame = core([self _frame]))
    3904         coreFrame->editor()->execCommand("ToggleBold");
    3905 }
    3906 
    3907 - (void)_toggleItalic
    3908 {
    3909     if (Frame* coreFrame = core([self _frame]))
    3910         coreFrame->editor()->execCommand("ToggleItalic");
    3911 }
    3912 
    39133919- (BOOL)_handleStyleKeyEquivalent:(NSEvent *)event
    39143920{
     
    39253931    NSString *string = [event characters];
    39263932    if ([string caseInsensitiveCompare:@"b"] == NSOrderedSame) {
    3927         [self _toggleBold];
     3933        [self executeCoreCommandByName:"ToggleBold"];
    39283934        return YES;
    39293935    }
    39303936    if ([string caseInsensitiveCompare:@"i"] == NSOrderedSame) {
    3931         [self _toggleItalic];
     3937        [self executeCoreCommandByName:"ToggleItalic"];
    39323938        return YES;
    39333939    }
     
    42614267}
    42624268
    4263 - (void)_alignSelectionUsingCSSValue:(NSString *)CSSAlignmentValue withUndoAction:(EditAction)undoAction
    4264 {
    4265     if (![self _canEditRichly])
    4266         return;
    4267        
    4268     DOMCSSStyleDeclaration *style = [self _emptyStyle];
    4269     [style setTextAlign:CSSAlignmentValue];
    4270     [self _applyStyleToSelection:style withUndoAction:undoAction];
    4271 }
    4272 
    4273 - (void)alignCenter:(id)sender
    4274 {
    4275     COMMAND_PROLOGUE
    4276 
    4277     [self _alignSelectionUsingCSSValue:@"center" withUndoAction:EditActionCenter];
    4278 }
    4279 
    4280 - (void)alignJustified:(id)sender
    4281 {
    4282     COMMAND_PROLOGUE
    4283 
    4284     [self _alignSelectionUsingCSSValue:@"justify" withUndoAction:EditActionJustify];
    4285 }
    4286 
    4287 - (void)alignLeft:(id)sender
    4288 {
    4289     COMMAND_PROLOGUE
    4290 
    4291     [self _alignSelectionUsingCSSValue:@"left" withUndoAction:EditActionAlignLeft];
    4292 }
    4293 
    4294 - (void)alignRight:(id)sender
    4295 {
    4296     COMMAND_PROLOGUE
    4297 
    4298     [self _alignSelectionUsingCSSValue:@"right" withUndoAction:EditActionAlignRight];
    4299 }
    4300 
    4301 - (void)insertParagraphSeparator:(id)sender
    4302 {
    4303     COMMAND_PROLOGUE
    4304 
    4305     if (Frame* coreFrame = core([self _frame]))
    4306         coreFrame->editor()->execCommand("InsertNewline");
    4307 }
    4308 
    43094269- (void)_changeWordCaseWithSelector:(SEL)selector
    43104270{
     
    45334493
    45344494    [NSApp stopSpeaking:sender];
    4535 }
    4536 
    4537 - (void)insertNewlineIgnoringFieldEditor:(id)sender
    4538 {
    4539     COMMAND_PROLOGUE
    4540 
    4541     if (Frame* coreFrame = core([self _frame]))
    4542         coreFrame->editor()->execCommand("InsertNewline");
    4543 }
    4544 
    4545 - (void)insertTabIgnoringFieldEditor:(id)sender
    4546 {
    4547     COMMAND_PROLOGUE
    4548 
    4549     if (Frame* coreFrame = core([self _frame]))
    4550         coreFrame->editor()->execCommand("InsertTab");
    4551 }
    4552 
    4553 - (void)subscript:(id)sender
    4554 {
    4555     COMMAND_PROLOGUE
    4556 
    4557     DOMCSSStyleDeclaration *style = [self _emptyStyle];
    4558     [style setVerticalAlign:@"sub"];
    4559     [self _applyStyleToSelection:style withUndoAction:EditActionSubscript];
    4560 }
    4561 
    4562 - (void)superscript:(id)sender
    4563 {
    4564     COMMAND_PROLOGUE
    4565 
    4566     DOMCSSStyleDeclaration *style = [self _emptyStyle];
    4567     [style setVerticalAlign:@"super"];
    4568     [self _applyStyleToSelection:style withUndoAction:EditActionSuperscript];
    4569 }
    4570 
    4571 - (void)unscript:(id)sender
    4572 {
    4573     COMMAND_PROLOGUE
    4574 
    4575     DOMCSSStyleDeclaration *style = [self _emptyStyle];
    4576     [style setVerticalAlign:@"baseline"];
    4577     [self _applyStyleToSelection:style withUndoAction:EditActionUnscript];
    4578 }
    4579 
    4580 - (void)underline:(id)sender
    4581 {
    4582     COMMAND_PROLOGUE
    4583 
    4584     Frame* coreFrame = core([self _frame]);
    4585     if (!coreFrame)
    4586         return;
    4587     // Despite the name, this method is actually supposed to toggle underline.
    4588     // FIXME: This currently clears overline, line-through, and blink as an unwanted side effect.
    4589     DOMCSSStyleDeclaration *style = [self _emptyStyle];
    4590     [style setProperty:@"-khtml-text-decorations-in-effect" value:@"underline" priority:@""];
    4591     if (coreFrame->editor()->selectionStartHasStyle(core(style)))
    4592         [style setProperty:@"-khtml-text-decorations-in-effect" value:@"none" priority:@""];
    4593     [self _applyStyleToSelection:style withUndoAction:EditActionUnderline];
    4594 }
    4595 
    4596 - (void)yank:(id)sender
    4597 {
    4598     COMMAND_PROLOGUE
    4599 
    4600     if (Frame* coreFrame = core([self _frame]))
    4601         coreFrame->editor()->yank();
    4602 }
    4603 
    4604 - (void)yankAndSelect:(id)sender
    4605 {
    4606     COMMAND_PROLOGUE
    4607 
    4608     if (Frame* coreFrame = core([self _frame]))
    4609         coreFrame->editor()->yankAndSelect();
    4610 }
    4611 
    4612 - (void)setMark:(id)sender
    4613 {
    4614     COMMAND_PROLOGUE
    4615 
    4616     if (Frame* coreFrame = core([self _frame]))
    4617         coreFrame->editor()->setMark();
    4618 }
    4619 
    4620 - (void)deleteToMark:(id)sender
    4621 {
    4622     COMMAND_PROLOGUE
    4623 
    4624     if (Frame* coreFrame = core([self _frame]))
    4625         coreFrame->editor()->deleteToMark();
    4626 }
    4627 
    4628 - (void)selectToMark:(id)sender
    4629 {
    4630     COMMAND_PROLOGUE
    4631 
    4632     if (Frame* coreFrame = core([self _frame]))
    4633         coreFrame->editor()->selectToMark();
    4634 }
    4635 
    4636 - (void)swapWithMark:(id)sender
    4637 {
    4638     COMMAND_PROLOGUE
    4639 
    4640     if (Frame* coreFrame = core([self _frame]))
    4641         coreFrame->editor()->swapWithMark();
    46424495}
    46434496
     
    46844537    [style setDirection:writingDirection == NSWritingDirectionLeftToRight ? @"LTR" : @"RTL"];
    46854538    [self _applyParagraphStyleToSelection:style withUndoAction:EditActionSetWritingDirection];
    4686 }
    4687 
    4688 - (void)indent:(id)sender
    4689 {
    4690     COMMAND_PROLOGUE
    4691 
    4692     if (Frame* coreFrame = core([self _frame]))
    4693         coreFrame->editor()->indent();
    4694 }
    4695 
    4696 - (void)outdent:(id)sender
    4697 {
    4698     COMMAND_PROLOGUE
    4699    
    4700     if (Frame* coreFrame = core([self _frame]))
    4701         coreFrame->editor()->outdent();
    47024539}
    47034540
     
    50154852}
    50164853
    5017 - (void)copy:(id)sender
    5018 {
    5019     COMMAND_PROLOGUE
    5020 
    5021     if (Frame* coreFrame = core([self _frame]))
    5022         coreFrame->editor()->copy();
    5023 }
    5024 
    5025 - (void)cut:(id)sender
    5026 {
    5027     COMMAND_PROLOGUE
    5028 
    5029     if (Frame* coreFrame = core([self _frame]))
    5030         coreFrame->editor()->cut();
    5031 }
    5032 
    50334854- (void)paste:(id)sender
    50344855{
     
    52275048            bool haveTextInsertionCommands = false;
    52285049            for (size_t i = 0; i < size; ++i) {
    5229                 if (Editor::isTextInsertionCommand(selectorToCommandName(NSSelectorFromString(command.commandNames[i]))))
     5050                if ([self coreCommandBySelector:NSSelectorFromString(command.commandNames[i])].isTextInsertion())
    52305051                    haveTextInsertionCommands = true;
    52315052            }
     
    55705391        Frame* coreFrame = core([self _frame]);
    55715392        if (![[webView _editingDelegateForwarder] webView:webView doCommandBySelector:selector] && coreFrame) {
    5572             AtomicString commandName = selectorToCommandName(selector);
    5573             if (Editor::isTextInsertionCommand(commandName))
    5574                 eventWasHandled = coreFrame->editor()->execCommand(commandName, event);
     5393            Editor::Command command = [self coreCommandBySelector:selector];
     5394            if (command.isTextInsertion())
     5395                eventWasHandled = command.execute(event);
    55755396            else {
    55765397                _private->selectorForDoCommandBySelector = selector;
  • trunk/WebKit/mac/WebView/WebHTMLViewInternal.h

    r28371 r28626  
    117117- (id<WebHTMLHighlighter>)_highlighterForType:(NSString*)type;
    118118- (WebFrame *)_frame;
    119 - (void)copy:(id)sender;
    120 - (void)cut:(id)sender;
    121119- (void)paste:(id)sender;
    122 - (void)pasteAsPlainText:(id)sender;
    123120- (void)closeIfNotCurrentView;
    124121- (void)_lookUpInDictionaryFromMenu:(id)sender;
  • trunk/WebKit/win/ChangeLog

    r28620 r28626  
     12007-12-11  Darin Adler  <darin@apple.com>
     2
     3        * WebView.cpp:
     4        (WebView::handleEditingKeyboardEvent): Update for change to Editor API.
     5
    162007-12-07  Alexey Proskuryakov  <ap@webkit.org>
    27
  • trunk/WebKit/win/WebView.cpp

    r28620 r28626  
    13701370        return false;
    13711371
     1372    Editor::Command command = frame->editor()->command(interpretKeyEvent(evt));
     1373
    13721374    if (keyEvent->type() == PlatformKeyboardEvent::RawKeyDown) {
    1373         String command = interpretKeyEvent(evt);
    1374 
    13751375        // WebKit doesn't have enough information about mode to decide how commands that just insert text if executed via Editor should be treated,
    13761376        // so we leave it upon WebCore to either handle them immediately (e.g. Tab that changes focus) or let a keypress event be generated
    13771377        // (e.g. Tab that inserts a Tab character, or Enter).
    1378         if (!command.isEmpty() && !Editor::isTextInsertionCommand(command))
    1379             if (frame->editor()->execCommand(command, evt))
    1380                 return true;
    1381         return false;
    1382     }
    1383 
    1384     String command = interpretKeyEvent(evt);
    1385      if (!command.isEmpty())
    1386         if (frame->editor()->execCommand(command, evt))
    1387             return true;
     1378        return !command.isTextInsertion() && command.execute(evt);
     1379    }
     1380
     1381     if (command.execute(evt))
     1382        return true;
    13881383
    13891384    // Don't insert null or control characters as they can result in unexpected behaviour
Note: See TracChangeset for help on using the changeset viewer.