Changeset 28626 in webkit
- Timestamp:
- Dec 11, 2007 12:26:56 PM (16 years ago)
- Location:
- trunk
- Files:
-
- 2 deleted
- 32 edited
- 1 copied
Legend:
- Unmodified
- Added
- Removed
-
trunk/WebCore/ChangeLog
r28625 r28626 1 2007-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 1 286 2007-12-11 Darin Adler <darin@apple.com> 2 287 -
trunk/WebCore/WebCore.base.exp
r28620 r28626 330 330 __ZN7WebCore18PlatformMouseEventC1EP7NSEvent 331 331 __ZN7WebCore18SecurityOriginDataC1ERKNS_6StringES3_t 332 __ZN7WebCore19CSSStyleDeclaration11setPropertyERKNS_6StringES3_Ri 332 333 __ZN7WebCore19InspectorController11showConsoleEv 333 334 __ZN7WebCore19InspectorController12attachWindowEv … … 355 356 __ZN7WebCore20ResourceResponseBase24setExpectedContentLengthEx 356 357 __ZN7WebCore21ContextMenuController16clearContextMenuEv 358 __ZN7WebCore21PlatformKeyboardEvent24disambiguateKeyDownEventENS0_4TypeEb 357 359 __ZN7WebCore21PlatformKeyboardEventC1EP7NSEvent 358 __ZN7WebCore21PlatformKeyboardEvent24disambiguateKeyDownEventENS0_4TypeEb359 360 __ZN7WebCore21WindowsLatin1EncodingEv 360 361 __ZN7WebCore21findEventWithKeyStateEPNS_5EventE … … 362 363 __ZN7WebCore21reportThreadViolationEPKc 363 364 __ZN7WebCore24notifyHistoryItemChangedE 365 __ZN7WebCore26CSSMutableStyleDeclarationC1Ev 364 366 __ZN7WebCore26NetscapePlugInStreamLoader6createEPNS_5FrameEP11objc_object 365 367 __ZN7WebCore26usesTestModeFocusRingColorEv … … 415 417 __ZN7WebCore6Editor10applyStyleEPNS_19CSSStyleDeclarationENS_10EditActionE 416 418 __ZN7WebCore6Editor10insertTextERKNS_6StringEPNS_5EventE 417 __ZN7WebCore6Editor11canDHTMLCutEv418 __ZN7WebCore6Editor22isTextInsertionCommandERKNS_12AtomicStringE419 __ZN7WebCore6Editor11execCommandERKNS_12AtomicStringEPNS_5EventE420 __ZN7WebCore6Editor11tryDHTMLCutEv421 __ZN7WebCore6Editor12canDHTMLCopyEv422 __ZN7WebCore6Editor12deleteToMarkEv423 __ZN7WebCore6Editor12selectToMarkEv424 __ZN7WebCore6Editor12swapWithMarkEv425 __ZN7WebCore6Editor12tryDHTMLCopyEv426 419 __ZN7WebCore6Editor13canDHTMLPasteEv 427 420 __ZN7WebCore6Editor13performDeleteEv 428 421 __ZN7WebCore6Editor13rangeForPointERKNS_8IntPointE 429 422 __ZN7WebCore6Editor13tryDHTMLPasteEv 430 __ZN7WebCore6Editor13yankAndSelectEv431 423 __ZN7WebCore6Editor14setCompositionERKNS_6StringERKN3WTF6VectorINS_20CompositionUnderlineELm0EEEjj 432 424 __ZN7WebCore6Editor16pasteAsPlainTextEv … … 453 445 __ZN7WebCore6Editor44confirmCompositionWithoutDisturbingSelectionEv 454 446 __ZN7WebCore6Editor4copyEv 455 __ZN7WebCore6Editor4yankEv456 447 __ZN7WebCore6Editor5pasteEv 457 448 __ZN7WebCore6Editor6indentEv 449 __ZN7WebCore6Editor7CommandC1Ev 450 __ZN7WebCore6Editor7commandERKNS_6StringE 451 __ZN7WebCore6Editor7commandERKNS_6StringENS_19EditorCommandSourceE 458 452 __ZN7WebCore6Editor7copyURLERKNS_4KURLERKNS_6StringE 459 453 __ZN7WebCore6Editor7outdentEv 460 __ZN7WebCore6Editor7setMarkEv461 454 __ZN7WebCore6String6appendERKS0_ 462 455 __ZN7WebCore6StringC1EP8NSString 463 456 __ZN7WebCore6StringC1EPKc 457 __ZN7WebCore6StringC1EPKcj 464 458 __ZN7WebCore6StringC1ERKNS_16DeprecatedStringE 465 459 __ZN7WebCore6Widget7setViewEP6NSView … … 678 672 __ZNK7WebCore5Range9startNodeEv 679 673 __ZNK7WebCore6Editor13canEditRichlyEv 674 __ZNK7WebCore6Editor17selectionHasStyleEPNS_19CSSStyleDeclarationE 680 675 __ZNK7WebCore6Editor17shouldDeleteRangeEPNS_5RangeE 681 676 __ZNK7WebCore6Editor22selectionStartHasStyleEPNS_19CSSStyleDeclarationE 682 677 __ZNK7WebCore6Editor23getCompositionSelectionERjS1_ 683 678 __ZNK7WebCore6Editor6canCutEv 679 __ZNK7WebCore6Editor7Command15isTextInsertionEv 680 __ZNK7WebCore6Editor7Command5stateEPNS_5EventE 681 __ZNK7WebCore6Editor7Command7executeEPNS_5EventE 682 __ZNK7WebCore6Editor7Command7executeERKNS_6StringEPNS_5EventE 683 __ZNK7WebCore6Editor7Command9isEnabledEPNS_5EventE 684 684 __ZNK7WebCore6Editor7canCopyEv 685 685 __ZNK7WebCore6Editor7canEditEv -
trunk/WebCore/WebCore.pro
r28592 r28626 528 528 editing/EditCommand.cpp \ 529 529 editing/Editor.cpp \ 530 editing/EditorCommand.cpp \ 530 531 editing/FormatBlockCommand.cpp \ 531 532 editing/htmlediting.cpp \ … … 539 540 editing/InsertTextCommand.cpp \ 540 541 editing/JoinTextNodesCommand.cpp \ 541 editing/JSEditor.cpp \542 542 editing/markup.cpp \ 543 543 editing/MergeIdenticalElementsCommand.cpp \ -
trunk/WebCore/WebCore.vcproj/WebCore.vcproj
r28592 r28626 6310 6310 </File> 6311 6311 <File 6312 RelativePath="..\editing\EditorCommand.cpp" 6313 > 6314 </File> 6315 <File 6312 6316 RelativePath="..\editing\EditorDeleteAction.h" 6313 6317 > … … 6403 6407 <File 6404 6408 RelativePath="..\editing\JoinTextNodesCommand.h" 6405 >6406 </File>6407 <File6408 RelativePath="..\editing\JSEditor.cpp"6409 >6410 </File>6411 <File6412 RelativePath="..\editing\JSEditor.h"6413 6409 > 6414 6410 </File> -
trunk/WebCore/WebCore.xcodeproj/project.pbxproj
r28592 r28626 1469 1469 93309DF3099E64920056E581 /* JoinTextNodesCommand.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 93309DA4099E64910056E581 /* JoinTextNodesCommand.cpp */; }; 1470 1470 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 */; };1473 1471 93309DF7099E64920056E581 /* markup.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 93309DA8099E64910056E581 /* markup.cpp */; }; 1474 1472 93309DF8099E64920056E581 /* markup.h in Headers */ = {isa = PBXBuildFile; fileRef = 93309DA9099E64910056E581 /* markup.h */; }; … … 1562 1560 93A1EAA00A5634C9006960A0 /* ImageDocumentMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = 93A1EA9F0A5634C9006960A0 /* ImageDocumentMac.mm */; }; 1563 1561 93A1EAA80A563508006960A0 /* ImageDocumentMac.h in Headers */ = {isa = PBXBuildFile; fileRef = 93A1EAA70A563508006960A0 /* ImageDocumentMac.h */; }; 1562 93A38B4B0D0E5808006872C2 /* EditorCommand.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 93A38B4A0D0E5808006872C2 /* EditorCommand.cpp */; }; 1564 1563 93B6A0E60B0BCA5C00F5027A /* ContextMenu.h in Headers */ = {isa = PBXBuildFile; fileRef = 93B6A0E50B0BCA5C00F5027A /* ContextMenu.h */; settings = {ATTRIBUTES = (Private, ); }; }; 1565 1564 93B6A0E80B0BCA6700F5027A /* ContextMenu.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 93B6A0E70B0BCA6700F5027A /* ContextMenu.cpp */; }; … … 5762 5761 93309DA4099E64910056E581 /* JoinTextNodesCommand.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JoinTextNodesCommand.cpp; sourceTree = "<group>"; }; 5763 5762 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>"; };5766 5763 93309DA8099E64910056E581 /* markup.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = markup.cpp; sourceTree = "<group>"; }; 5767 5764 93309DA9099E64910056E581 /* markup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = markup.h; sourceTree = "<group>"; }; … … 5860 5857 93A1EA9F0A5634C9006960A0 /* ImageDocumentMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ImageDocumentMac.mm; sourceTree = "<group>"; }; 5861 5858 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>"; }; 5862 5860 93B6A0E50B0BCA5C00F5027A /* ContextMenu.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = ContextMenu.h; sourceTree = "<group>"; }; 5863 5861 93B6A0E70B0BCA6700F5027A /* ContextMenu.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = ContextMenu.cpp; sourceTree = "<group>"; }; … … 9612 9610 4B3043CA0AE0373B00A82647 /* Editor.cpp */, 9613 9611 4B3043CB0AE0373B00A82647 /* Editor.h */, 9612 93A38B4A0D0E5808006872C2 /* EditorCommand.cpp */, 9614 9613 4BAE95B00B2FA9CE00AED8A0 /* EditorDeleteAction.h */, 9615 9614 93FDAFC90B11307400E2746F /* EditorInsertAction.h */, … … 9636 9635 93309DA4099E64910056E581 /* JoinTextNodesCommand.cpp */, 9637 9636 93309DA5099E64910056E581 /* JoinTextNodesCommand.h */, 9638 93309DA6099E64910056E581 /* JSEditor.cpp */,9639 93309DA7099E64910056E581 /* JSEditor.h */,9640 9637 93309DA8099E64910056E581 /* markup.cpp */, 9641 9638 93309DA9099E64910056E581 /* markup.h */, … … 13326 13323 1A494EDF0A123F4C00FDAFC1 /* JSDocumentFragment.h in Headers */, 13327 13324 65DF31F609D1CC60000BE325 /* JSDocumentType.h in Headers */, 13328 93309DF6099E64920056E581 /* JSEditor.h in Headers */,13329 13325 65DF31FA09D1CC60000BE325 /* JSElement.h in Headers */, 13330 13326 65DF323009D1DDBC000BE325 /* JSEntity.h in Headers */, … … 15027 15023 1A494EDE0A123F4C00FDAFC1 /* JSDocumentFragment.cpp in Sources */, 15028 15024 65DF31F509D1CC60000BE325 /* JSDocumentType.cpp in Sources */, 15029 93309DF5099E64920056E581 /* JSEditor.cpp in Sources */,15030 15025 65DF31F909D1CC60000BE325 /* JSElement.cpp in Sources */, 15031 15026 BC2ED5550C6B9BD300920BFF /* JSElementCustom.cpp in Sources */, … … 15797 15792 93309DF7099E64920056E581 /* markup.cpp in Sources */, 15798 15793 93309E1D099E64920056E581 /* visible_units.cpp in Sources */, 15794 93A38B4B0D0E5808006872C2 /* EditorCommand.cpp in Sources */, 15799 15795 ); 15800 15796 runOnlyForDeploymentPostprocessing = 0; -
trunk/WebCore/WebCoreSources.bkl
r28592 r28626 351 351 editing/EditCommand.cpp 352 352 editing/Editor.cpp 353 editing/EditorCommand.cpp 353 354 editing/FormatBlockCommand.cpp 354 355 editing/HTMLInterchange.cpp … … 360 361 editing/InsertParagraphSeparatorCommand.cpp 361 362 editing/InsertTextCommand.cpp 362 editing/JSEditor.cpp363 363 editing/JoinTextNodesCommand.cpp 364 364 editing/MergeIdenticalElementsCommand.cpp -
trunk/WebCore/dom/DOMImplementation.cpp
r25754 r28626 66 66 #if ENABLE(SVG) 67 67 68 static void addString(HashSet<StringImpl*, Case InsensitiveHash<StringImpl*>>& set, const68 static void addString(HashSet<StringImpl*, CaseFoldingHash>& set, const 69 69 char* string) 70 70 { … … 77 77 { 78 78 static bool initialized = false; 79 static HashSet<StringImpl*, Case InsensitiveHash<StringImpl*>> svgFeatures;79 static HashSet<StringImpl*, CaseFoldingHash> svgFeatures; 80 80 if (!initialized) { 81 81 // TODO: features need to be uncommented when we implement them … … 100 100 { 101 101 static bool initialized = false; 102 static HashSet<StringImpl*, Case InsensitiveHash<StringImpl*>> svgFeatures;102 static HashSet<StringImpl*, CaseFoldingHash> svgFeatures; 103 103 if (!initialized) { 104 104 // TODO: features need to be uncommented when we implement them -
trunk/WebCore/dom/Document.cpp
r28620 r28626 69 69 #include "HitTestRequest.h" 70 70 #include "HitTestResult.h" 71 #include "JSEditor.h"72 71 #include "KeyboardEvent.h" 73 72 #include "Logging.h" … … 339 338 m_overMinimumLayoutThreshold = false; 340 339 341 m_jsEditor = 0;342 343 340 initSecurityOrigin(); 344 341 … … 431 428 } 432 429 m_decoder = 0; 433 434 if (m_jsEditor) {435 delete m_jsEditor;436 m_jsEditor = 0;437 }438 430 439 431 unsigned count = sizeof(m_nameCollectionInfo) / sizeof(m_nameCollectionInfo[0]); … … 2858 2850 // Support for Javascript execCommand, and related methods 2859 2851 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); 2852 static 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 2861 bool Document::execCommand(const String& commandName, bool userInterface, const String& value) 2862 { 2863 return command(this, commandName, userInterface).execute(value); 2864 } 2865 2866 bool Document::queryCommandEnabled(const String& commandName) 2867 { 2868 return command(this, commandName).isEnabled(); 2869 } 2870 2871 bool Document::queryCommandIndeterm(const String& commandName) 2872 { 2873 return command(this, commandName).state() == MixedTriState; 2874 } 2875 2876 bool Document::queryCommandState(const String& commandName) 2877 { 2878 return command(this, commandName).state() != FalseTriState; 2879 } 2880 2881 bool Document::queryCommandSupported(const String& commandName) 2882 { 2883 return command(this, commandName).isSupported(); 2884 } 2885 2886 String Document::queryCommandValue(const String& commandName) 2887 { 2888 return command(this, commandName).value(); 2889 } 2890 2891 static IntRect placeholderRectForMarker() 2892 { 2893 return IntRect(-1, -1, -1, -1); 2900 2894 } 2901 2895 -
trunk/WebCore/dom/Document.h
r28620 r28626 71 71 class HTMLMapElement; 72 72 class IntPoint; 73 class JSEditor;74 73 class MouseEventWithHitTestResults; 75 74 class NameNodeList; … … 869 868 void updateFocusAppearanceTimerFired(Timer<Document>*); 870 869 871 JSEditor* jsEditor();872 JSEditor* m_jsEditor;873 874 870 mutable String m_domain; 875 871 … … 887 883 mutable HashCountedSet<AtomicStringImpl*> m_duplicateIds; 888 884 889 mutable HashMap<StringImpl*, Element*, Case InsensitiveHash<StringImpl*>> m_elementsByAccessKey;885 mutable HashMap<StringImpl*, Element*, CaseFoldingHash> m_elementsByAccessKey; 890 886 891 887 InheritedBool m_designMode; -
trunk/WebCore/editing/Editor.cpp
r28620 r28626 33 33 #include "CSSProperty.h" 34 34 #include "CSSPropertyNames.h" 35 #include "CharacterData.h"36 #include "Clipboard.h"37 35 #include "ClipboardEvent.h" 38 36 #include "DeleteButtonController.h" 39 37 #include "DeleteSelectionCommand.h" 40 38 #include "DocLoader.h" 41 #include "Document.h"42 39 #include "DocumentFragment.h" 43 #include "EditCommand.h"44 #include "Editor.h"45 40 #include "EditorClient.h" 46 #include "Event.h"47 41 #include "EventHandler.h" 48 42 #include "EventNames.h" 49 43 #include "FocusController.h" 50 44 #include "FrameView.h" 51 #include "HTMLElement.h"52 45 #include "HTMLInputElement.h" 53 #include "HTMLNames.h"54 46 #include "HTMLTextAreaElement.h" 55 47 #include "HitTestResult.h" … … 57 49 #include "InsertListCommand.h" 58 50 #include "KeyboardEvent.h" 59 #include "KURL.h"60 51 #include "ModifySelectionListLevel.h" 61 52 #include "Page.h" 62 53 #include "Pasteboard.h" 63 #include "Range.h"64 54 #include "RemoveFormatCommand.h" 65 55 #include "ReplaceSelectionCommand.h" 66 #include "SelectionController.h"67 56 #include "Sound.h" 68 57 #include "Text.h" … … 75 64 namespace WebCore { 76 65 77 class FontData;78 79 66 using namespace std; 80 67 using namespace EventNames; … … 83 70 // When an event handler has moved the selection outside of a text control 84 71 // 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(); 72 Selection Editor::selectionForCommand(Event* event) 73 { 74 Selection selection = m_frame->selectionController()->selection(); 91 75 if (!event) 92 76 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. 93 79 Node* target = event->target()->toNode(); 94 80 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 81 if (target && (!selectionStart || target->shadowAncestorNode() != selectionStart->shadowAncestorNode())) { 99 82 if (target->hasTagName(inputTag) && static_cast<HTMLInputElement*>(target)->isTextField()) … … 115 98 { 116 99 if (EditorClient* c = client()) 117 if (selectionFor Event(m_frame,event).isContentEditable())100 if (selectionForCommand(event).isContentEditable()) 118 101 c->handleKeyboardEvent(event); 119 102 } … … 122 105 { 123 106 if (EditorClient* c = client()) 124 if (selectionFor Event(m_frame,event).isContentEditable())107 if (selectionForCommand(event).isContentEditable()) 125 108 c->handleInputMethodKeydown(event); 126 109 } … … 161 144 } 162 145 163 static Node* imageNodeFromImageDocument(Document* document)146 static HTMLImageElement* imageElementFromImageDocument(Document* document) 164 147 { 165 148 if (!document) 166 149 return 0; 167 168 150 if (!document->isImageDocument()) 169 151 return 0; … … 175 157 Node* node = body->firstChild(); 176 158 if (!node) 177 return 0; 178 159 return 0; 179 160 if (!node->hasTagName(imgTag)) 180 161 return 0; 181 182 return node; 162 return static_cast<HTMLImageElement*>(node); 183 163 } 184 164 185 165 bool Editor::canCopy() const 186 166 { 187 if (image NodeFromImageDocument(m_frame->document()))167 if (imageElementFromImageDocument(m_frame->document())) 188 168 return true; 189 190 169 SelectionController* selectionController = m_frame->selectionController(); 191 170 return selectionController->isRange() && !selectionController->isInPasswordField(); … … 480 459 } 481 460 482 Frame::TriState Editor::selectionUnorderedListState() const461 TriState Editor::selectionUnorderedListState() const 483 462 { 484 463 if (m_frame->selectionController()->isCaret()) { 485 464 Node* selectionNode = m_frame->selectionController()->selection().start().node(); 486 465 if (enclosingNodeWithTag(selectionNode, ulTag)) 487 return Frame::trueTriState;466 return TrueTriState; 488 467 } else if (m_frame->selectionController()->isRange()) { 489 468 Node* startNode = enclosingNodeWithTag(m_frame->selectionController()->selection().start().node(), ulTag); 490 469 Node* endNode = enclosingNodeWithTag(m_frame->selectionController()->selection().end().node(), ulTag); 491 470 if (startNode && endNode && startNode == endNode) 492 return Frame::trueTriState;493 } 494 495 return F rame::falseTriState;496 } 497 498 Frame::TriState Editor::selectionOrderedListState() const471 return TrueTriState; 472 } 473 474 return FalseTriState; 475 } 476 477 TriState Editor::selectionOrderedListState() const 499 478 { 500 479 if (m_frame->selectionController()->isCaret()) { 501 480 Node* selectionNode = m_frame->selectionController()->selection().start().node(); 502 481 if (enclosingNodeWithTag(selectionNode, olTag)) 503 return Frame::trueTriState;482 return TrueTriState; 504 483 } else if (m_frame->selectionController()->isRange()) { 505 484 Node* startNode = enclosingNodeWithTag(m_frame->selectionController()->selection().start().node(), olTag); 506 485 Node* endNode = enclosingNodeWithTag(m_frame->selectionController()->selection().end().node(), olTag); 507 486 if (startNode && endNode && startNode == endNode) 508 return Frame::trueTriState;509 } 510 511 return F rame::falseTriState;487 return TrueTriState; 488 } 489 490 return FalseTriState; 512 491 } 513 492 … … 621 600 // do nothing 622 601 break; 623 case Selection::CARET: {602 case Selection::CARET: 624 603 m_frame->computeAndSetTypingStyle(style, editingAction); 625 604 break; 626 }627 605 case Selection::RANGE: 628 606 if (m_frame->document() && style) … … 677 655 { 678 656 Node* nodeToRemove; 679 RefPtr<CSS StyleDeclaration> selectionStyle = m_frame->selectionComputedStyle(nodeToRemove);657 RefPtr<CSSComputedStyleDeclaration> selectionStyle = m_frame->selectionComputedStyle(nodeToRemove); 680 658 if (!selectionStyle) 681 659 return false; … … 702 680 } 703 681 682 static 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 701 TriState 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 } 704 733 void Editor::indent() 705 734 { … … 796 825 } 797 826 798 // Execute command functions799 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() == OSCROLL858 || renderer->style()->overflowY() == OAUTO859 || 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() == OSCROLL896 || renderer->style()->overflowY() == OAUTO897 || 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 functions1182 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 commands1309 //1310 // =============================================================================1311 1312 827 Editor::Editor(Frame* frame) 1313 828 : m_frame(frame) 1314 829 , m_deleteButtonController(new DeleteButtonController(frame)) 1315 830 , m_ignoreCompositionSelectionChange(false) 831 , m_shouldStartNewKillRingSequence(false) 1316 832 { 1317 833 } … … 1327 843 } 1328 844 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 1360 845 bool Editor::insertText(const String& text, Event* triggeringEvent) 1361 846 { … … 1368 853 return false; 1369 854 1370 Selection selection = selectionFor Event(m_frame,triggeringEvent);855 Selection selection = selectionForCommand(triggeringEvent); 1371 856 if (!selection.isContentEditable()) 1372 857 return false; … … 1379 864 // If the event handler changed the selection, we may want to use a different selection 1380 865 // that is contained in the event target. 1381 selection = selectionFor Event(m_frame,triggeringEvent);866 selection = selectionForCommand(triggeringEvent); 1382 867 if (selection.isContentEditable()) { 1383 868 if (Node* selectionStart = selection.start().node()) { … … 1452 937 1453 938 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()); 1456 941 else 1457 942 Pasteboard::generalPasteboard()->writeSelection(selectedRange().get(), canSmartCopyOrDelete(), m_frame); … … 1605 1090 void Editor::toggleBold() 1606 1091 { 1607 execToggleBold(frame(), 0);1092 command("ToggleBold").execute(); 1608 1093 } 1609 1094 1610 1095 void Editor::toggleUnderline() 1611 1096 { 1097 command("ToggleUnderline").execute(); 1098 } 1099 1100 void Editor::setBaseWritingDirection(const String& direction) 1101 { 1612 1102 ExceptionCode ec = 0; 1613 1103 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; 1626 1105 style->setProperty(CSS_PROP_DIRECTION, direction, false, ec); 1627 1106 applyParagraphStyleToSelection(style.get(), EditActionSetWritingDirection); … … 2416 1895 } 2417 1896 1897 void 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 1913 void Editor::appendToKillRing(const String&) 1914 { 1915 } 1916 1917 void Editor::prependToKillRing(const String&) 1918 { 1919 } 1920 1921 String Editor::yankFromKillRing() 1922 { 1923 } 1924 1925 void Editor::startNewKillRingSequence() 1926 { 1927 } 1928 1929 void Editor::setKillRingToYankedState() 1930 { 1931 } 1932 1933 #endif 1934 2418 1935 } // namespace WebCore -
trunk/WebCore/editing/Editor.h
r28620 r28626 47 47 class DocumentFragment; 48 48 class EditCommand; 49 class EditorInternalCommand; 49 50 class EditorClient; 50 51 class EventTargetNode; … … 68 69 }; 69 70 71 enum TriState { FalseTriState, TrueTriState, MixedTriState }; 72 enum EditorCommandSource { CommandFromMenuOrKeyBinding, CommandFromDOM, CommandFromDOMWithUserInterface }; 73 70 74 class Editor { 71 75 public: … … 118 122 void respondToChangedSelection(const Selection& oldSelection); 119 123 void respondToChangedContents(const Selection& endingSelection); 120 124 125 TriState selectionHasStyle(CSSStyleDeclaration*) const; 121 126 const FontData* fontForSelection(bool&) const; 122 127 123 Frame::TriState selectionUnorderedListState() const;124 Frame::TriState selectionOrderedListState() const;128 TriState selectionUnorderedListState() const; 129 TriState selectionOrderedListState() const; 125 130 PassRefPtr<Node> insertOrderedList(); 126 131 PassRefPtr<Node> insertUnorderedList(); … … 158 163 bool clientIsEditable() const; 159 164 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 164 192 bool insertText(const String&, Event* triggeringEvent); 165 193 bool insertTextWithoutSendingTextEvent(const String&, bool selectInsertedText, Event* triggeringEvent = 0); … … 203 231 void toggleBold(); 204 232 void toggleUnderline(); 205 void setBaseWritingDirection( String);233 void setBaseWritingDirection(const String&); 206 234 207 235 bool smartInsertDeleteEnabled(); … … 227 255 void setStartNewKillRingSequence(bool); 228 256 257 PassRefPtr<Range> rangeForPoint(const IntPoint& windowPoint); 258 259 void clear(); 260 261 Selection selectionForCommand(Event*); 262 229 263 #if PLATFORM(MAC) 230 264 NSString* userVisibleString(NSURL*); 231 232 void yank();233 void yankAndSelect();234 void setMark();235 void deleteToMark();236 void selectToMark();237 void swapWithMark();238 239 265 #endif 240 266 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(); 244 274 245 275 private: … … 254 284 Vector<CompositionUnderline> m_customCompositionUnderlines; 255 285 bool m_ignoreCompositionSelectionChange; 286 bool m_shouldStartNewKillRingSequence; 256 287 257 288 bool canDeleteRange(Range*) const; 258 289 bool canSmartReplaceWithPasteboard(Pasteboard*); 259 290 PassRefPtr<Clipboard> newGeneralClipboard(ClipboardAccessPolicy); 260 PassRefPtr<Range> selectedRange();261 291 void pasteAsPlainTextWithPasteboard(Pasteboard*); 262 292 void pasteWithPasteboard(Pasteboard*, bool allowPlainText); … … 271 301 272 302 void addToKillRing(Range*, bool prepend); 273 274 #if PLATFORM(MAC)275 bool m_startNewKillRingSequence;276 #endif277 303 }; 278 279 #if PLATFORM(MAC)280 304 281 305 inline void Editor::setStartNewKillRingSequence(bool flag) 282 306 { 283 m_s tartNewKillRingSequence = flag;307 m_shouldStartNewKillRingSequence = flag; 284 308 } 285 309 286 #else287 288 inline void Editor::setStartNewKillRingSequence(bool) { }289 inline void Editor::addToKillRing(Range*, bool) { }290 291 #endif292 293 310 } // namespace WebCore 294 311 -
trunk/WebCore/editing/EditorCommand.cpp
r28608 r28626 26 26 27 27 #include "config.h" 28 29 #include "AtomicString.h" 30 #include "CSSPropertyNames.h" 31 #include "CreateLinkCommand.h" 32 #include "DocumentFragment.h" 28 33 #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"46 34 #include "Event.h" 47 35 #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" 56 39 #include "IndentOutdentCommand.h" 57 40 #include "InsertListCommand.h" 58 #include "KeyboardEvent.h"59 #include "KURL.h"60 #include "ModifySelectionListLevel.h"61 41 #include "Page.h" 62 #include "Pasteboard.h"63 #include "Range.h"64 #include "RemoveFormatCommand.h"65 42 #include "ReplaceSelectionCommand.h" 66 #include "Se lectionController.h"43 #include "Settings.h" 67 44 #include "Sound.h" 68 #include "Text.h"69 #include "TextIterator.h"70 45 #include "TypingCommand.h" 46 #include "UnlinkCommand.h" 71 47 #include "htmlediting.h" 72 48 #include "markup.h" 73 #include "visible_units.h"74 49 75 50 namespace WebCore { 76 51 77 class FontData;78 79 using namespace std;80 using namespace EventNames;81 52 using namespace HTMLNames; 82 53 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(); 54 class EditorInternalCommand { 55 public: 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 64 typedef HashMap<String, const EditorInternalCommand*, CaseFoldingHash> CommandMap; 65 66 static const bool notTextInsertion = false; 67 static 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. 72 static Frame* targetFrame(Frame* frame, Event* event) 73 { 91 74 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(); 1155 77 if (!node) 1156 78 return frame; … … 1158 80 } 1159 81 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); 82 static 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 100 static 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 105 static 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 123 static 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 142 static 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 160 static 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 167 static 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 177 static 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 184 static String valueStyle(Frame* frame, int propertyID) 185 { 186 return frame->selectionStartStylePropertyValue(propertyID); 187 } 188 189 static 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 199 static 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 212 static bool executeBackColor(Frame* frame, Event*, EditorCommandSource source, const String& value) 213 { 214 return executeApplyStyle(frame, source, EditActionSetBackgroundColor, CSS_PROP_BACKGROUND_COLOR, value); 215 } 216 217 static bool executeBackwardDelete(Frame* frame, Event*, EditorCommandSource, const String&) 218 { 219 frame->editor()->deleteWithDirection(SelectionController::BACKWARD, CharacterGranularity, false, true); 220 return true; 221 } 222 223 static bool executeCopy(Frame* frame, Event*, EditorCommandSource, const String&) 224 { 225 frame->editor()->copy(); 226 return true; 227 } 228 229 static 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 238 static bool executeCut(Frame* frame, Event*, EditorCommandSource, const String&) 239 { 240 frame->editor()->cut(); 241 return true; 242 } 243 244 static 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 261 static 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 276 static bool executeDeleteWordBackward(Frame* frame, Event*, EditorCommandSource, const String&) 277 { 278 frame->editor()->deleteWithDirection(SelectionController::BACKWARD, WordGranularity, true, false); 279 return true; 280 } 281 282 static bool executeDeleteWordForward(Frame* frame, Event*, EditorCommandSource, const String&) 283 { 284 frame->editor()->deleteWithDirection(SelectionController::FORWARD, WordGranularity, true, false); 285 return true; 286 } 287 288 static bool executeFindString(Frame* frame, Event*, EditorCommandSource, const String& value) 289 { 290 return frame->findString(value, true, false, true, false); 291 } 292 293 static bool executeFontName(Frame* frame, Event*, EditorCommandSource source, const String& value) 294 { 295 return executeApplyStyle(frame, source, EditActionSetFont, CSS_PROP_FONT_FAMILY, value); 296 } 297 298 static 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 306 static 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 311 static bool executeForeColor(Frame* frame, Event*, EditorCommandSource source, const String& value) 312 { 313 return executeApplyStyle(frame, source, EditActionSetColor, CSS_PROP_COLOR, value); 314 } 315 316 static 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 327 static 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 344 static bool executeIndent(Frame* frame, Event*, EditorCommandSource, const String&) 345 { 346 applyCommand(new IndentOutdentCommand(frame->document(), IndentOutdentCommand::Indent)); 347 return true; 348 } 349 350 static bool executeInsertBacktab(Frame* frame, Event* event, EditorCommandSource, const String&) 351 { 352 return targetFrame(frame, event)->eventHandler()->handleTextInputEvent("\t", event, false, true); 353 } 354 355 static 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 363 static bool executeInsertHTML(Frame* frame, Event*, EditorCommandSource, const String& value) 364 { 365 return executeInsertFragment(frame, createFragmentFromMarkup(frame->document(), value, "")); 366 } 367 368 static 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 376 static 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 392 static 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 398 static bool executeInsertNewlineInQuotedContent(Frame* frame, Event*, EditorCommandSource, const String&) 399 { 400 TypingCommand::insertParagraphSeparatorInQuotedContent(frame->document()); 401 return true; 402 } 403 404 static bool executeInsertOrderedList(Frame* frame, Event*, EditorCommandSource, const String& value) 405 { 406 applyCommand(new InsertListCommand(frame->document(), InsertListCommand::OrderedList, value)); 407 return true; 408 } 409 410 static bool executeInsertParagraph(Frame* frame, Event*, EditorCommandSource, const String&) 411 { 412 TypingCommand::insertParagraphSeparator(frame->document()); 413 return true; 414 } 415 416 static bool executeInsertTab(Frame* frame, Event* event, EditorCommandSource, const String&) 417 { 418 return targetFrame(frame, event)->eventHandler()->handleTextInputEvent("\t", event, false, false); 419 } 420 421 static bool executeInsertText(Frame* frame, Event*, EditorCommandSource, const String& value) 422 { 423 TypingCommand::insertText(frame->document(), value); 424 return true; 425 } 426 427 static bool executeInsertUnorderedList(Frame* frame, Event*, EditorCommandSource, const String& value) 428 { 429 applyCommand(new InsertListCommand(frame->document(), InsertListCommand::UnorderedList, value)); 430 return true; 431 } 432 433 static bool executeJustifyCenter(Frame* frame, Event*, EditorCommandSource source, const String&) 434 { 435 return executeApplyParagraphStyle(frame, source, EditActionCenter, CSS_PROP_TEXT_ALIGN, "center"); 436 } 437 438 static bool executeJustifyFull(Frame* frame, Event*, EditorCommandSource source, const String&) 439 { 440 return executeApplyParagraphStyle(frame, source, EditActionJustify, CSS_PROP_TEXT_ALIGN, "justify"); 441 } 442 443 static bool executeJustifyLeft(Frame* frame, Event*, EditorCommandSource source, const String&) 444 { 445 return executeApplyParagraphStyle(frame, source, EditActionAlignLeft, CSS_PROP_TEXT_ALIGN, "left"); 446 } 447 448 static bool executeJustifyRight(Frame* frame, Event*, EditorCommandSource source, const String&) 449 { 450 return executeApplyParagraphStyle(frame, source, EditActionAlignRight, CSS_PROP_TEXT_ALIGN, "right"); 451 } 452 453 static bool executeMoveBackward(Frame* frame, Event*, EditorCommandSource, const String&) 454 { 455 frame->selectionController()->modify(SelectionController::MOVE, SelectionController::BACKWARD, CharacterGranularity, true); 456 return true; 457 } 458 459 static bool executeMoveBackwardAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&) 460 { 461 frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::BACKWARD, CharacterGranularity, true); 462 return true; 463 } 464 465 static bool executeMoveDown(Frame* frame, Event*, EditorCommandSource, const String&) 466 { 467 frame->selectionController()->modify(SelectionController::MOVE, SelectionController::FORWARD, LineGranularity, true); 468 return true; 469 } 470 471 static bool executeMoveDownAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&) 472 { 473 frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::FORWARD, LineGranularity, true); 474 return true; 475 } 476 477 static 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 490 static bool executeMoveForward(Frame* frame, Event*, EditorCommandSource, const String&) 491 { 492 frame->selectionController()->modify(SelectionController::MOVE, SelectionController::FORWARD, CharacterGranularity, true); 493 return true; 494 } 495 496 static bool executeMoveForwardAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&) 497 { 498 frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::FORWARD, CharacterGranularity, true); 499 return true; 500 } 501 502 static bool executeMoveLeft(Frame* frame, Event*, EditorCommandSource, const String&) 503 { 504 frame->selectionController()->modify(SelectionController::MOVE, SelectionController::LEFT, CharacterGranularity, true); 505 return true; 506 } 507 508 static bool executeMoveLeftAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&) 509 { 510 frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::LEFT, CharacterGranularity, true); 511 return true; 512 } 513 514 static bool executeMoveRight(Frame* frame, Event*, EditorCommandSource, const String&) 515 { 516 frame->selectionController()->modify(SelectionController::MOVE, SelectionController::RIGHT, CharacterGranularity, true); 517 return true; 518 } 519 520 static bool executeMoveRightAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&) 521 { 522 frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::RIGHT, CharacterGranularity, true); 523 return true; 524 } 525 526 static bool executeMoveToBeginningOfDocument(Frame* frame, Event*, EditorCommandSource, const String&) 527 { 528 frame->selectionController()->modify(SelectionController::MOVE, SelectionController::BACKWARD, DocumentBoundary, true); 529 return true; 530 } 531 532 static bool executeMoveToBeginningOfDocumentAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&) 533 { 534 frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::BACKWARD, DocumentBoundary, true); 535 return true; 536 } 537 538 static bool executeMoveToBeginningOfLine(Frame* frame, Event*, EditorCommandSource, const String&) 539 { 540 frame->selectionController()->modify(SelectionController::MOVE, SelectionController::BACKWARD, LineBoundary, true); 541 return true; 542 } 543 544 static bool executeMoveToBeginningOfLineAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&) 545 { 546 frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::BACKWARD, LineBoundary, true); 547 return true; 548 } 549 550 static bool executeMoveToBeginningOfParagraph(Frame* frame, Event*, EditorCommandSource, const String&) 551 { 552 frame->selectionController()->modify(SelectionController::MOVE, SelectionController::BACKWARD, ParagraphBoundary, true); 553 return true; 554 } 555 556 static bool executeMoveToBeginningOfParagraphAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&) 557 { 558 frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::BACKWARD, ParagraphBoundary, true); 559 return true; 560 } 561 562 static bool executeMoveToBeginningOfSentence(Frame* frame, Event*, EditorCommandSource, const String&) 563 { 564 frame->selectionController()->modify(SelectionController::MOVE, SelectionController::BACKWARD, SentenceBoundary, true); 565 return true; 566 } 567 568 static bool executeMoveToBeginningOfSentenceAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&) 569 { 570 frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::BACKWARD, SentenceBoundary, true); 571 return true; 572 } 573 574 static bool executeMoveToEndOfDocument(Frame* frame, Event*, EditorCommandSource, const String&) 575 { 576 frame->selectionController()->modify(SelectionController::MOVE, SelectionController::FORWARD, DocumentBoundary, true); 577 return true; 578 } 579 580 static bool executeMoveToEndOfDocumentAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&) 581 { 582 frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::FORWARD, DocumentBoundary, true); 583 return true; 584 } 585 586 static bool executeMoveToEndOfSentence(Frame* frame, Event*, EditorCommandSource, const String&) 587 { 588 frame->selectionController()->modify(SelectionController::MOVE, SelectionController::FORWARD, SentenceBoundary, true); 589 return true; 590 } 591 592 static bool executeMoveToEndOfSentenceAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&) 593 { 594 frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::FORWARD, SentenceBoundary, true); 595 return true; 596 } 597 598 static bool executeMoveToEndOfLine(Frame* frame, Event*, EditorCommandSource, const String&) 599 { 600 frame->selectionController()->modify(SelectionController::MOVE, SelectionController::FORWARD, LineBoundary, true); 601 return true; 602 } 603 604 static bool executeMoveToEndOfLineAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&) 605 { 606 frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::FORWARD, LineBoundary, true); 607 return true; 608 } 609 610 static bool executeMoveToEndOfParagraph(Frame* frame, Event*, EditorCommandSource, const String&) 611 { 612 frame->selectionController()->modify(SelectionController::MOVE, SelectionController::FORWARD, ParagraphBoundary, true); 613 return true; 614 } 615 616 static bool executeMoveToEndOfParagraphAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&) 617 { 618 frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::FORWARD, ParagraphBoundary, true); 619 return true; 620 } 621 622 static bool executeMoveParagraphBackwardAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&) 623 { 624 frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::BACKWARD, ParagraphGranularity, true); 625 return true; 626 } 627 628 static bool executeMoveParagraphForwardAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&) 629 { 630 frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::FORWARD, ParagraphGranularity, true); 631 return true; 632 } 633 634 static bool executeMoveUp(Frame* frame, Event*, EditorCommandSource, const String&) 635 { 636 frame->selectionController()->modify(SelectionController::MOVE, SelectionController::BACKWARD, LineGranularity, true); 637 return true; 638 } 639 640 static bool executeMoveUpAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&) 641 { 642 frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::BACKWARD, LineGranularity, true); 643 return true; 644 } 645 646 static 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 659 static bool executeMoveWordBackward(Frame* frame, Event*, EditorCommandSource, const String&) 660 { 661 frame->selectionController()->modify(SelectionController::MOVE, SelectionController::BACKWARD, WordGranularity, true); 662 return true; 663 } 664 665 static bool executeMoveWordBackwardAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&) 666 { 667 frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::BACKWARD, WordGranularity, true); 668 return true; 669 } 670 671 static bool executeMoveWordForward(Frame* frame, Event*, EditorCommandSource, const String&) 672 { 673 frame->selectionController()->modify(SelectionController::MOVE, SelectionController::FORWARD, WordGranularity, true); 674 return true; 675 } 676 677 static bool executeMoveWordForwardAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&) 678 { 679 frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::FORWARD, WordGranularity, true); 680 return true; 681 } 682 683 static bool executeMoveWordLeft(Frame* frame, Event*, EditorCommandSource, const String&) 684 { 685 frame->selectionController()->modify(SelectionController::MOVE, SelectionController::LEFT, WordGranularity, true); 686 return true; 687 } 688 689 static bool executeMoveWordLeftAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&) 690 { 691 frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::LEFT, WordGranularity, true); 692 return true; 693 } 694 695 static bool executeMoveWordRight(Frame* frame, Event*, EditorCommandSource, const String&) 696 { 697 frame->selectionController()->modify(SelectionController::MOVE, SelectionController::RIGHT, WordGranularity, true); 698 return true; 699 } 700 701 static bool executeMoveWordRightAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&) 702 { 703 frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::RIGHT, WordGranularity, true); 704 return true; 705 } 706 707 static bool executeOutdent(Frame* frame, Event*, EditorCommandSource, const String&) 708 { 709 applyCommand(new IndentOutdentCommand(frame->document(), IndentOutdentCommand::Outdent)); 710 return true; 711 } 712 713 static bool executePaste(Frame* frame, Event*, EditorCommandSource, const String&) 714 { 715 frame->editor()->paste(); 716 return true; 717 } 718 719 static bool executePasteAndMatchStyle(Frame* frame, Event*, EditorCommandSource, const String&) 720 { 721 frame->editor()->pasteAsPlainText(); 722 return true; 723 } 724 725 static 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 734 static bool executeRedo(Frame* frame, Event*, EditorCommandSource, const String&) 735 { 736 frame->editor()->redo(); 737 return true; 738 } 739 740 static bool executeRemoveFormat(Frame* frame, Event*, EditorCommandSource, const String&) 741 { 742 frame->editor()->removeFormattingAndStyle(); 743 return true; 744 } 745 746 static bool executeSelectAll(Frame* frame, Event*, EditorCommandSource, const String&) 747 { 748 frame->selectionController()->selectAll(); 749 return true; 750 } 751 752 static 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 764 static bool executeSetMark(Frame* frame, Event*, EditorCommandSource, const String&) 765 { 766 frame->setMark(frame->selectionController()->selection()); 767 return true; 768 } 769 770 static 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 775 static bool executeSubscript(Frame* frame, Event*, EditorCommandSource source, const String&) 776 { 777 return executeApplyStyle(frame, source, EditActionSubscript, CSS_PROP_VERTICAL_ALIGN, "sub"); 778 } 779 780 static bool executeSuperscript(Frame* frame, Event*, EditorCommandSource source, const String&) 781 { 782 return executeApplyStyle(frame, source, EditActionSuperscript, CSS_PROP_VERTICAL_ALIGN, "super"); 783 } 784 785 static 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 799 static bool executeToggleBold(Frame* frame, Event*, EditorCommandSource source, const String&) 800 { 801 return executeToggleStyle(frame, source, EditActionChangeAttributes, CSS_PROP_FONT_WEIGHT, "normal", "bold"); 802 } 803 804 static bool executeToggleItalic(Frame* frame, Event*, EditorCommandSource source, const String&) 805 { 806 return executeToggleStyle(frame, source, EditActionChangeAttributes, CSS_PROP_FONT_STYLE, "normal", "italic"); 807 } 808 809 static bool executeTranspose(Frame* frame, Event*, EditorCommandSource, const String&) 810 { 811 frame->editor()->transpose(); 812 return true; 813 } 814 815 static 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 821 static bool executeUndo(Frame* frame, Event*, EditorCommandSource, const String&) 822 { 823 frame->editor()->undo(); 824 return true; 825 } 826 827 static bool executeUnlink(Frame* frame, Event*, EditorCommandSource, const String&) 828 { 829 applyCommand(new UnlinkCommand(frame->document())); 830 return true; 831 } 832 833 static bool executeUnscript(Frame* frame, Event*, EditorCommandSource source, const String&) 834 { 835 return executeApplyStyle(frame, source, EditActionUnscript, CSS_PROP_VERTICAL_ALIGN, "baseline"); 836 } 837 838 static bool executeUnselect(Frame* frame, Event*, EditorCommandSource, const String&) 839 { 840 frame->selectionController()->clear(); 841 return true; 842 } 843 844 static 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 851 static 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 860 static bool supported(Frame*, EditorCommandSource) 861 { 862 return true; 863 } 864 865 static 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; 1179 878 } 1180 879 … … 1186 885 } 1187 886 1188 static bool canPaste(Frame* frame, Event*) 887 static bool enabledAnySelection(Frame* frame, Event*) 888 { 889 return frame->selectionController()->isCaretOrRange(); 890 } 891 892 static bool enabledAnySelectionAndMark(Frame* frame, Event*) 893 { 894 return frame->selectionController()->isCaretOrRange() && frame->mark().isCaretOrRange(); 895 } 896 897 static bool enableCaretInEditableText(Frame* frame, Event* event) 898 { 899 const Selection& selection = frame->editor()->selectionForCommand(event); 900 return selection.isCaret() && selection.isContentEditable(); 901 } 902 903 static bool enabledCopy(Frame* frame, Event* source) 904 { 905 return frame->editor()->canDHTMLCopy() || frame->editor()->canCopy(); 906 } 907 908 static bool enabledCut(Frame* frame, Event* source) 909 { 910 return frame->editor()->canDHTMLCut() || frame->editor()->canCut(); 911 } 912 913 static bool enabledInEditableText(Frame* frame, Event* event) 914 { 915 return frame->editor()->selectionForCommand(event).isContentEditable(); 916 } 917 918 static bool enabledInRichlyEditableText(Frame* frame, Event*) 919 { 920 return frame->selectionController()->isCaretOrRange() && frame->selectionController()->isContentRichlyEditable(); 921 } 922 923 static bool enabledPaste(Frame* frame, Event*) 1189 924 { 1190 925 return frame->editor()->canPaste(); 1191 926 } 1192 927 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*) 928 static bool enabledRangeInEditableText(Frame* frame, Event*) 1201 929 { 1202 930 return frame->selectionController()->isRange() && frame->selectionController()->isContentEditable(); 1203 931 } 1204 932 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*) 933 static bool enabledRangeInRichlyEditableText(Frame* frame, Event*) 934 { 935 return frame->selectionController()->isRange() && frame->selectionController()->isContentRichlyEditable(); 936 } 937 938 static bool enabledRedo(Frame* frame, Event*) 1216 939 { 1217 940 return frame->editor()->canRedo(); 1218 941 } 1219 942 1220 static bool canUndo(Frame* frame, Event*)943 static bool enabledUndo(Frame* frame, Event*) 1221 944 { 1222 945 return frame->editor()->canUndo(); 1223 946 } 1224 947 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 950 static TriState stateNone(Frame*, Event*) 951 { 952 return FalseTriState; 953 } 954 955 static TriState stateBold(Frame* frame, Event*) 956 { 957 return stateStyle(frame, CSS_PROP_FONT_WEIGHT, "bold"); 958 } 959 960 static TriState stateItalic(Frame* frame, Event*) 961 { 962 return stateStyle(frame, CSS_PROP_FONT_STYLE, "italic"); 963 } 964 965 static TriState stateOrderedList(Frame* frame, Event*) 966 { 967 return frame->editor()->selectionOrderedListState(); 968 } 969 970 static TriState stateStrikethrough(Frame* frame, Event*) 971 { 972 return stateStyle(frame, CSS_PROP_TEXT_DECORATION, "line-through"); 973 } 974 975 static TriState stateSubscript(Frame* frame, Event*) 976 { 977 return stateStyle(frame, CSS_PROP_VERTICAL_ALIGN, "sub"); 978 } 979 980 static TriState stateSuperscript(Frame* frame, Event*) 981 { 982 return stateStyle(frame, CSS_PROP_VERTICAL_ALIGN, "super"); 983 } 984 985 static TriState stateUnderline(Frame* frame, Event*) 986 { 987 return stateStyle(frame, CSS_PROP_TEXT_DECORATION, "underline"); 988 } 989 990 static TriState stateUnorderedList(Frame* frame, Event*) 991 { 992 return frame->editor()->selectionUnorderedListState(); 993 } 994 995 // Value functions 996 997 static String valueNull(Frame*, Event*) 998 { 999 return String(); 1000 } 1001 1002 String valueBackColor(Frame* frame, Event*) 1003 { 1004 return valueStyle(frame, CSS_PROP_BACKGROUND_COLOR); 1005 } 1006 1007 String valueFontName(Frame* frame, Event*) 1008 { 1009 return valueStyle(frame, CSS_PROP_FONT_FAMILY); 1010 } 1011 1012 String valueFontSize(Frame* frame, Event*) 1013 { 1014 return valueStyle(frame, CSS_PROP_FONT_SIZE); 1015 } 1016 1017 String valueFontSizeDelta(Frame* frame, Event*) 1018 { 1019 return valueStyle(frame, CSS_PROP__WEBKIT_FONT_SIZE_DELTA); 1020 } 1021 1022 String valueForeColor(Frame* frame, Event*) 1023 { 1024 return valueStyle(frame, CSS_PROP_COLOR); 1025 } 1026 1027 // Map of functions 1028 1029 static const CommandMap& createCommandMap() 1030 { 1031 struct CommandEntry { const char* name; EditorInternalCommand command; }; 1235 1032 1236 1033 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 } }, 1295 1139 }; 1296 1140 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; 1298 1189 1299 1190 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 } 1302 1195 1303 1196 return commandMap; 1304 1197 } 1305 1198 1306 // ============================================================================= 1307 // 1308 // public editing commands 1309 // 1310 // ============================================================================= 1311 1312 Editor::Editor(Frame* frame) 1199 Editor::Command Editor::command(const String& commandName) 1200 { 1201 return command(commandName, CommandFromMenuOrKeyBinding); 1202 } 1203 1204 Editor::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 1211 Editor::Command::Command() 1212 : m_command(0) 1213 , m_source() 1214 { 1215 } 1216 1217 Editor::Command::Command(PassRefPtr<Frame> frame, const EditorInternalCommand* command, EditorCommandSource source) 1313 1218 : 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 1226 bool 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 1234 bool Editor::Command::execute(Event* triggeringEvent) const 1235 { 1236 return execute(String(), triggeringEvent); 1237 } 1238 1239 bool Editor::Command::isSupported() const 1240 { 1241 return m_command && m_command->isSupported(m_frame.get(), m_source); 1242 } 1243 1244 bool 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 1251 TriState 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 1258 String 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 1265 bool Editor::Command::isTextInsertion() const 1266 { 1267 return m_command && m_command->isTextInsertion; 1268 } 1269 1270 bool Editor::execCommand(const AtomicString& commandName, Event* triggeringEvent) 1271 { 1272 return command(commandName).execute(triggeringEvent); 2408 1273 } 2409 1274 -
trunk/WebCore/editing/mac/EditorMac.mm
r27873 r28626 27 27 #import "Editor.h" 28 28 29 #import "ClipboardAccessPolicy.h"30 #import "Clipboard.h"31 29 #import "ClipboardMac.h" 32 #import "Document.h"33 30 #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"45 31 46 32 namespace WebCore { … … 54 40 void _NSPrependToKillRing(NSString *); 55 41 NSString *_NSYankFromKillRing(); 56 NSString *_NSYankPreviousFromKillRing();57 42 void _NSNewKillRingSequence(); 58 43 void _NSSetKillRingToYankedState(); 59 void _NSResetKillRingOperationFlag();60 44 61 45 } … … 64 48 { 65 49 return new ClipboardMac(false, [NSPasteboard generalPasteboard], policy); 50 } 51 52 NSString* Editor::userVisibleString(NSURL* nsURL) 53 { 54 if (client()) 55 return client()->userVisibleString(nsURL); 56 return nil; 66 57 } 67 58 … … 75 66 } 76 67 77 NSString* Editor::userVisibleString(NSURL* nsURL)68 void Editor::appendToKillRing(const String& string) 78 69 { 79 if (client()) 80 return client()->userVisibleString(nsURL); 81 return nil; 70 initializeKillRingIfNeeded(); 71 _NSAppendToKillRing(string); 82 72 } 83 73 84 void Editor:: addToKillRing(Range* range, bool prepend)74 void Editor::prependToKillRing(const String& string) 85 75 { 86 76 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); 98 78 } 99 79 100 void Editor::yank()80 String Editor::yankFromKillRing() 101 81 { 102 82 initializeKillRingIfNeeded(); 103 104 if (!canEdit()) 105 return; 106 107 NSString* yankee = _NSYankFromKillRing(); 108 insertTextWithoutSendingTextEvent(yankee, false); 109 _NSSetKillRingToYankedState(); 83 return _NSYankFromKillRing(); 110 84 } 111 85 112 void Editor:: yankAndSelect()86 void Editor::startNewKillRingSequence() 113 87 { 114 88 initializeKillRingIfNeeded(); 115 116 if (!canEdit()) 117 return; 118 119 NSString* yankee = _NSYankFromKillRing(); 120 insertTextWithoutSendingTextEvent(yankee, true); 121 _NSSetKillRingToYankedState(); 89 _NSNewKillRingSequence(); 122 90 } 123 91 124 void Editor::set Mark()92 void Editor::setKillRingToYankedState() 125 93 { 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(); 180 96 } 181 97 -
trunk/WebCore/loader/FrameLoader.cpp
r28468 r28626 1122 1122 } 1123 1123 1124 static HashSet<String, Case InsensitiveHash<String>>& localSchemes()1125 { 1126 static HashSet<String, Case InsensitiveHash<String>> localSchemes;1124 static HashSet<String, CaseFoldingHash>& localSchemes() 1125 { 1126 static HashSet<String, CaseFoldingHash> localSchemes; 1127 1127 1128 1128 if (localSchemes.isEmpty()) { -
trunk/WebCore/page/Frame.cpp
r28496 r28626 880 880 } 881 881 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) const902 {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 934 882 String Frame::selectionStartStylePropertyValue(int stylePropertyID) const 935 883 { -
trunk/WebCore/page/Frame.h
r28411 r28626 274 274 275 275 void computeAndSetTypingStyle(CSSStyleDeclaration* , EditAction = EditActionUnspecified); 276 enum TriState { falseTriState, trueTriState, mixedTriState };277 TriState selectionHasStyle(CSSStyleDeclaration*) const;278 276 String selectionStartStylePropertyValue(int stylePropertyID) const; 279 277 void applyEditingStyleToBodyElement() const; -
trunk/WebCore/page/mac/WebCoreFrameBridge.h
r28411 r28626 213 213 - (DOMCSSStyleDeclaration *)typingStyle; 214 214 - (void)setTypingStyle:(DOMCSSStyleDeclaration *)style withUndoAction:(WebCore::EditAction)undoAction; 215 - (NSCellStateValue)selectionHasStyle:(DOMCSSStyleDeclaration *)style;216 215 217 216 - (void)dragSourceMovedTo:(NSPoint)windowLoc; -
trunk/WebCore/page/mac/WebCoreFrameBridge.mm
r28411 r28626 1162 1162 } 1163 1163 1164 - (NSCellStateValue)selectionHasStyle:(DOMCSSStyleDeclaration *)style1165 {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 1179 1164 - (NSFont *)fontForSelection:(BOOL *)hasMultipleFonts 1180 1165 { -
trunk/WebCore/platform/ContextMenu.cpp
r24529 r28626 407 407 } 408 408 409 static bool triStateToBool(Frame::TriState state)410 {411 return state == Frame::trueTriState;412 }413 414 409 void ContextMenu::checkOrEnableIfNeeded(ContextMenuItem& item) const 415 410 { … … 438 433 String direction = item.action() == ContextMenuItemTagLeftToRight ? "ltr" : "rtl"; 439 434 style->setProperty(CSS_PROP_DIRECTION, direction, false, ec); 440 shouldCheck = triStateToBool(frame->selectionHasStyle(style.get()));435 shouldCheck = frame->editor()->selectionHasStyle(style.get()) != FalseTriState; 441 436 shouldEnable = true; 442 437 break; … … 459 454 RefPtr<CSSStyleDeclaration> style = frame->document()->createCSSStyleDeclaration(); 460 455 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; 462 457 shouldEnable = frame->editor()->canEditRichly(); 463 458 break; … … 477 472 RefPtr<CSSStyleDeclaration> style = frame->document()->createCSSStyleDeclaration(); 478 473 style->setProperty(CSS_PROP_FONT_STYLE, "italic", false, ec); 479 shouldCheck = triStateToBool(frame->selectionHasStyle(style.get()));474 shouldCheck = frame->editor()->selectionHasStyle(style.get()) != FalseTriState; 480 475 shouldEnable = frame->editor()->canEditRichly(); 481 476 break; … … 485 480 RefPtr<CSSStyleDeclaration> style = frame->document()->createCSSStyleDeclaration(); 486 481 style->setProperty(CSS_PROP_FONT_WEIGHT, "bold", false, ec); 487 shouldCheck = triStateToBool(frame->selectionHasStyle(style.get()));482 shouldCheck = frame->editor()->selectionHasStyle(style.get()) != FalseTriState; 488 483 shouldEnable = frame->editor()->canEditRichly(); 489 484 break; -
trunk/WebCore/platform/graphics/FontCache.cpp
r28234 r28626 66 66 { 67 67 unsigned hashCodes[3] = { 68 Case InsensitiveHash<String>::hash(fontKey.m_family),68 CaseFoldingHash::hash(fontKey.m_family), 69 69 fontKey.m_size, 70 70 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 33 33 namespace WebCore { 34 34 35 typedef HashMap<String, String, Case InsensitiveHash<String>> HTTPHeaderMap;35 typedef HashMap<String, String, CaseFoldingHash> HTTPHeaderMap; 36 36 37 37 } // namespace WebCore -
trunk/WebCore/platform/text/PlatformString.h
r28620 r28626 1 1 /* 2 * This file is part of the DOM implementation for KDE.3 *4 2 * (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. 6 4 * 7 5 * This library is free software; you can redistribute it and/or … … 46 44 47 45 class CString; 48 46 struct StringHash; 47 49 48 /** 50 49 * Currently, strings are explicitly shared (they behave like pointers), meaning … … 243 242 namespace WTF { 244 243 245 // Str Hash is the default hash for String244 // StringHash is the default hash for String 246 245 template<typename T> struct DefaultHash; 247 template<typename T> struct StrHash;248 246 template<> struct DefaultHash<WebCore::String> { 249 typedef StrHash<WebCore::String>Hash;247 typedef WebCore::StringHash Hash; 250 248 }; 251 249 -
trunk/WebCore/platform/text/StringHash.h
r28234 r28626 1 1 /* 2 * Copyright (C) 2006 Apple Computer, Inc.2 * Copyright (C) 2006, 2007 Apple Inc. All rights reserved 3 3 * 4 4 * This library is free software; you can redistribute it and/or … … 27 27 #include <wtf/unicode/Unicode.h> 28 28 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) 29 namespace 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) 36 34 { 37 35 if (a == b) … … 58 56 return true; 59 57 } 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 60 71 static const bool safeToCompareToEmptyOrDeleted = false; 61 72 }; 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 { 86 75 private: 87 76 // Golden ratio - arbitrary start value to avoid mapping all 0's to all 0's … … 90 79 // Paul Hsieh's SuperFastHash 91 80 // http://www.azillionmonkeys.com/qed/hash.html 92 static unsigned hash(const WebCore::StringImpl* str)81 static unsigned hash(const StringImpl* str) 93 82 { 94 83 unsigned l = str->length(); … … 178 167 } 179 168 180 static bool equal(const WebCore::StringImpl* a, const WebCore::StringImpl* b)169 static bool equal(const StringImpl* a, const StringImpl* b) 181 170 { 182 171 if (a == b) … … 190 179 } 191 180 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 192 200 static const bool safeToCompareToEmptyOrDeleted = false; 193 201 }; 194 202 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 205 namespace WTF { 223 206 224 207 // store WebCore::String as StringImpl* … … 244 227 // share code between StringImpl*, RefPtr<StringImpl>, and String 245 228 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; 261 244 typedef HashTraits<WebCore::StringImpl*> Traits; 262 245 }; … … 264 247 } 265 248 266 using WTF::CaseInsensitiveHash;267 268 249 #endif -
trunk/WebCore/platform/text/StringImpl.cpp
r28620 r28626 1047 1047 bool equal(const StringImpl* a, const StringImpl* b) 1048 1048 { 1049 return Str Hash<StringImpl*>::equal(a, b);1049 return StringHash::equal(a, b); 1050 1050 } 1051 1051 … … 1072 1072 bool equalIgnoringCase(const StringImpl* a, const StringImpl* b) 1073 1073 { 1074 return Case InsensitiveHash<StringImpl*>::equal(a, b);1074 return CaseFoldingHash::equal(a, b); 1075 1075 } 1076 1076 -
trunk/WebCore/platform/text/StringImpl.h
r28620 r28626 1 1 /* 2 * This file is part of the DOM implementation for KDE.3 *4 2 * 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. 6 4 * 7 5 * This library is free software; you can redistribute it and/or … … 44 42 class AtomicString; 45 43 class DeprecatedString; 46 struct UCharBufferTranslator;47 44 struct CStringTranslator; 48 45 struct Length; 46 struct StringHash; 47 struct UCharBufferTranslator; 49 48 50 49 class StringImpl : public RefCounted<StringImpl> { … … 181 180 namespace WTF { 182 181 183 // StrHash is the default hash for StringImpl* and RefPtr<StringImpl>182 // WebCore::StringHash is the default hash for StringImpl* and RefPtr<StringImpl> 184 183 template<typename T> struct DefaultHash; 185 template<typename T> struct StrHash;186 184 template<> struct DefaultHash<WebCore::StringImpl*> { 187 typedef StrHash<WebCore::StringImpl*>Hash;185 typedef WebCore::StringHash Hash; 188 186 }; 189 187 template<> struct DefaultHash<RefPtr<WebCore::StringImpl> > { 190 typedef StrHash<RefPtr<WebCore::StringImpl> >Hash;188 typedef WebCore::StringHash Hash; 191 189 }; 192 190 -
trunk/WebCore/rendering/RenderPartObject.cpp
r27982 r28626 151 151 serviceType = o->m_serviceType; 152 152 153 HashSet<StringImpl*, Case InsensitiveHash<StringImpl*>> uniqueParamNames;153 HashSet<StringImpl*, CaseFoldingHash> uniqueParamNames; 154 154 155 155 // Scan the PARAM children. -
trunk/WebCore/rendering/RenderTreeAsText.cpp
r26843 r28626 34 34 #include "HTMLNames.h" 35 35 #include "InlineTextBox.h" 36 #include "JSEditor.h"37 36 #include "RenderBR.h" 38 37 #include "RenderListMarker.h" -
trunk/WebCore/xml/XMLHttpRequest.cpp
r28301 r28626 92 92 static bool canSetRequestHeader(const String& name) 93 93 { 94 static HashSet<String, Case InsensitiveHash<String>> forbiddenHeaders;94 static HashSet<String, CaseFoldingHash> forbiddenHeaders; 95 95 static String proxyString("proxy-"); 96 96 -
trunk/WebKit/mac/ChangeLog
r28620 r28626 1 2007-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 1 33 2007-12-07 Alexey Proskuryakov <ap@webkit.org> 2 34 -
trunk/WebKit/mac/WebView/WebHTMLView.mm
r28620 r28626 362 362 }; 363 363 364 static 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 364 378 @implementation WebHTMLViewPrivate 365 366 379 367 380 + (void)initialize … … 2048 2061 } 2049 2062 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 2063 static String comandNameForSelector(SEL selector) 2064 { 2065 // Change a few command names into ones supported by WebCore::Editor. 2056 2066 if (selector == @selector(insertParagraphSeparator:) || selector == @selector(insertNewlineIgnoringFieldEditor:)) 2057 2067 return "InsertNewline"; … … 2059 2069 return "InsertTab"; 2060 2070 2071 // Remove the trailing colon. 2061 2072 const char* selectorName = sel_getName(selector); 2062 2073 size_t selectorNameLength = strlen(selectorName); 2063 2074 ASSERT(selectorNameLength >= 2); 2064 2075 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 { 2078 2081 Frame* coreFrame = core([self _frame]); 2079 2082 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(); 2083 2105 } 2084 2106 … … 2088 2110 // added to this list. 2089 2111 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 2117 WEBCORE_COMMAND(alignCenter) 2118 WEBCORE_COMMAND(alignJustified) 2119 WEBCORE_COMMAND(alignLeft) 2120 WEBCORE_COMMAND(alignRight) 2121 WEBCORE_COMMAND(cut) 2122 WEBCORE_COMMAND(copy) 2123 WEBCORE_COMMAND(deleteToMark) 2092 2124 WEBCORE_COMMAND(deleteWordBackward) 2093 2125 WEBCORE_COMMAND(deleteWordForward) 2126 WEBCORE_COMMAND(indent) 2094 2127 WEBCORE_COMMAND(insertBacktab) 2095 2128 WEBCORE_COMMAND(insertLineBreak) 2096 2129 WEBCORE_COMMAND(insertNewline) 2130 WEBCORE_COMMAND(insertNewlineIgnoringFieldEditor) 2131 WEBCORE_COMMAND(insertParagraphSeparator) 2097 2132 WEBCORE_COMMAND(insertTab) 2133 WEBCORE_COMMAND(insertTabIgnoringFieldEditor) 2098 2134 WEBCORE_COMMAND(moveBackward) 2099 2135 WEBCORE_COMMAND(moveBackwardAndModifySelection) … … 2134 2170 WEBCORE_COMMAND(moveWordRight) 2135 2171 WEBCORE_COMMAND(moveWordRightAndModifySelection) 2172 WEBCORE_COMMAND(outdent) 2173 WEBCORE_COMMAND(selectAll) 2174 WEBCORE_COMMAND(selectToMark) 2175 WEBCORE_COMMAND(setMark) 2176 WEBCORE_COMMAND(subscript) 2177 WEBCORE_COMMAND(superscript) 2178 WEBCORE_COMMAND(swapWithMark) 2136 2179 WEBCORE_COMMAND(transpose) 2180 WEBCORE_COMMAND(underline) 2181 WEBCORE_COMMAND(unscript) 2182 WEBCORE_COMMAND(yank) 2183 WEBCORE_COMMAND(yankAndSelect) 2137 2184 2138 2185 #undef WEBCORE_COMMAND … … 2181 2228 } 2182 2229 2183 - (void)selectAll:(id)sender2184 {2185 COMMAND_PROLOGUE2186 2187 [self selectAll];2188 }2189 2190 2230 // jumpToSelection is the old name for what AppKit now calls centerSelectionInVisibleArea. Safari 2191 2231 // was using the old jumpToSelection selector in its menu. Newer versions of Safari will us the … … 2199 2239 if (Frame* coreFrame = core([self _frame])) 2200 2240 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)); 2201 2249 } 2202 2250 … … 2220 2268 } 2221 2269 } 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:) 2234 2277 || action == @selector(deleteToMark:) 2235 2278 || action == @selector(deleteWordBackward:) 2236 2279 || action == @selector(deleteWordForward:) 2280 || action == @selector(indent:) 2237 2281 || action == @selector(insertBacktab:) 2238 2282 || action == @selector(insertLineBreak:) … … 2256 2300 || action == @selector(moveToBeginningOfDocument:) 2257 2301 || action == @selector(moveToBeginningOfDocumentAndModifySelection:) 2258 || action == @selector(moveToBeginningOfSentence:)2259 || action == @selector(moveToBeginningOfSentenceAndModifySelection:)2260 2302 || action == @selector(moveToBeginningOfLine:) 2261 2303 || action == @selector(moveToBeginningOfLineAndModifySelection:) 2262 2304 || action == @selector(moveToBeginningOfParagraph:) 2263 2305 || action == @selector(moveToBeginningOfParagraphAndModifySelection:) 2306 || action == @selector(moveToBeginningOfSentence:) 2307 || action == @selector(moveToBeginningOfSentenceAndModifySelection:) 2264 2308 || action == @selector(moveToEndOfDocument:) 2265 2309 || action == @selector(moveToEndOfDocumentAndModifySelection:) 2266 || action == @selector(moveToEndOfSentence:)2267 || action == @selector(moveToEndOfSentenceAndModifySelection:)2268 2310 || action == @selector(moveToEndOfLine:) 2269 2311 || action == @selector(moveToEndOfLineAndModifySelection:) 2270 2312 || action == @selector(moveToEndOfParagraph:) 2271 2313 || action == @selector(moveToEndOfParagraphAndModifySelection:) 2314 || action == @selector(moveToEndOfSentence:) 2315 || action == @selector(moveToEndOfSentenceAndModifySelection:) 2272 2316 || action == @selector(moveUp:) 2273 2317 || action == @selector(moveUpAndModifySelection:) … … 2280 2324 || action == @selector(moveWordRight:) 2281 2325 || 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:) 2282 2356 || action == @selector(pageDown:) 2283 2357 || action == @selector(pageDownAndModifySelection:) 2284 2358 || action == @selector(pageUp:) 2285 2359 || action == @selector(pageUpAndModifySelection:) 2286 || action == @selector(pasteFont:) 2287 || action == @selector(transpose:) 2288 || action == @selector(yank:) 2289 || action == @selector(yankAndSelect:)) 2360 || action == @selector(pasteFont:)) 2290 2361 return [self _canEdit]; 2291 2362 … … 2307 2378 NSWritingDirection writingDirection = static_cast<NSWritingDirection>([item tag]); 2308 2379 if (writingDirection == NSWritingDirectionNatural) { 2309 [menuItem setState:N O];2380 [menuItem setState:NSOffState]; 2310 2381 return NO; 2311 2382 } 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())]; 2315 2387 } 2316 2388 return [self _canEdit]; … … 2320 2392 NSMenuItem *menuItem = (NSMenuItem *)item; 2321 2393 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); 2324 2397 // Take control of the title of the menu item, instead of just checking/unchecking it because otherwise 2325 2398 // 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")]; 2327 2402 } 2328 2403 return [self _canEdit]; 2329 2404 } 2330 2405 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:) 2336 2407 || action == @selector(changeColor:) 2337 || action == @selector(changeFont:) 2338 || action == @selector(indent:) 2339 || action == @selector(outdent:)) 2408 || action == @selector(changeFont:)) 2340 2409 return [self _canEditRichly]; 2341 2410 … … 2347 2416 if (action == @selector(centerSelectionInVisibleArea:) 2348 2417 || action == @selector(jumpToSelection:) 2349 || action == @selector(copyFont:) 2350 || action == @selector(setMark:)) 2418 || action == @selector(copyFont:)) 2351 2419 return [self _hasSelection] || ([self _isEditable] && [self _hasInsertionPoint]); 2352 2420 2353 2421 if (action == @selector(changeDocumentBackgroundColor:)) 2354 2422 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());2361 2423 2362 2424 if (action == @selector(delete:)) … … 2378 2440 // FIXME: Not yet implemented. 2379 2441 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 }2424 2442 2425 2443 if (action == @selector(_lookUpInDictionaryFromMenu:)) { … … 3899 3917 } 3900 3918 3901 - (void)_toggleBold3902 {3903 if (Frame* coreFrame = core([self _frame]))3904 coreFrame->editor()->execCommand("ToggleBold");3905 }3906 3907 - (void)_toggleItalic3908 {3909 if (Frame* coreFrame = core([self _frame]))3910 coreFrame->editor()->execCommand("ToggleItalic");3911 }3912 3913 3919 - (BOOL)_handleStyleKeyEquivalent:(NSEvent *)event 3914 3920 { … … 3925 3931 NSString *string = [event characters]; 3926 3932 if ([string caseInsensitiveCompare:@"b"] == NSOrderedSame) { 3927 [self _toggleBold];3933 [self executeCoreCommandByName:"ToggleBold"]; 3928 3934 return YES; 3929 3935 } 3930 3936 if ([string caseInsensitiveCompare:@"i"] == NSOrderedSame) { 3931 [self _toggleItalic];3937 [self executeCoreCommandByName:"ToggleItalic"]; 3932 3938 return YES; 3933 3939 } … … 4261 4267 } 4262 4268 4263 - (void)_alignSelectionUsingCSSValue:(NSString *)CSSAlignmentValue withUndoAction:(EditAction)undoAction4264 {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)sender4274 {4275 COMMAND_PROLOGUE4276 4277 [self _alignSelectionUsingCSSValue:@"center" withUndoAction:EditActionCenter];4278 }4279 4280 - (void)alignJustified:(id)sender4281 {4282 COMMAND_PROLOGUE4283 4284 [self _alignSelectionUsingCSSValue:@"justify" withUndoAction:EditActionJustify];4285 }4286 4287 - (void)alignLeft:(id)sender4288 {4289 COMMAND_PROLOGUE4290 4291 [self _alignSelectionUsingCSSValue:@"left" withUndoAction:EditActionAlignLeft];4292 }4293 4294 - (void)alignRight:(id)sender4295 {4296 COMMAND_PROLOGUE4297 4298 [self _alignSelectionUsingCSSValue:@"right" withUndoAction:EditActionAlignRight];4299 }4300 4301 - (void)insertParagraphSeparator:(id)sender4302 {4303 COMMAND_PROLOGUE4304 4305 if (Frame* coreFrame = core([self _frame]))4306 coreFrame->editor()->execCommand("InsertNewline");4307 }4308 4309 4269 - (void)_changeWordCaseWithSelector:(SEL)selector 4310 4270 { … … 4533 4493 4534 4494 [NSApp stopSpeaking:sender]; 4535 }4536 4537 - (void)insertNewlineIgnoringFieldEditor:(id)sender4538 {4539 COMMAND_PROLOGUE4540 4541 if (Frame* coreFrame = core([self _frame]))4542 coreFrame->editor()->execCommand("InsertNewline");4543 }4544 4545 - (void)insertTabIgnoringFieldEditor:(id)sender4546 {4547 COMMAND_PROLOGUE4548 4549 if (Frame* coreFrame = core([self _frame]))4550 coreFrame->editor()->execCommand("InsertTab");4551 }4552 4553 - (void)subscript:(id)sender4554 {4555 COMMAND_PROLOGUE4556 4557 DOMCSSStyleDeclaration *style = [self _emptyStyle];4558 [style setVerticalAlign:@"sub"];4559 [self _applyStyleToSelection:style withUndoAction:EditActionSubscript];4560 }4561 4562 - (void)superscript:(id)sender4563 {4564 COMMAND_PROLOGUE4565 4566 DOMCSSStyleDeclaration *style = [self _emptyStyle];4567 [style setVerticalAlign:@"super"];4568 [self _applyStyleToSelection:style withUndoAction:EditActionSuperscript];4569 }4570 4571 - (void)unscript:(id)sender4572 {4573 COMMAND_PROLOGUE4574 4575 DOMCSSStyleDeclaration *style = [self _emptyStyle];4576 [style setVerticalAlign:@"baseline"];4577 [self _applyStyleToSelection:style withUndoAction:EditActionUnscript];4578 }4579 4580 - (void)underline:(id)sender4581 {4582 COMMAND_PROLOGUE4583 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)sender4597 {4598 COMMAND_PROLOGUE4599 4600 if (Frame* coreFrame = core([self _frame]))4601 coreFrame->editor()->yank();4602 }4603 4604 - (void)yankAndSelect:(id)sender4605 {4606 COMMAND_PROLOGUE4607 4608 if (Frame* coreFrame = core([self _frame]))4609 coreFrame->editor()->yankAndSelect();4610 }4611 4612 - (void)setMark:(id)sender4613 {4614 COMMAND_PROLOGUE4615 4616 if (Frame* coreFrame = core([self _frame]))4617 coreFrame->editor()->setMark();4618 }4619 4620 - (void)deleteToMark:(id)sender4621 {4622 COMMAND_PROLOGUE4623 4624 if (Frame* coreFrame = core([self _frame]))4625 coreFrame->editor()->deleteToMark();4626 }4627 4628 - (void)selectToMark:(id)sender4629 {4630 COMMAND_PROLOGUE4631 4632 if (Frame* coreFrame = core([self _frame]))4633 coreFrame->editor()->selectToMark();4634 }4635 4636 - (void)swapWithMark:(id)sender4637 {4638 COMMAND_PROLOGUE4639 4640 if (Frame* coreFrame = core([self _frame]))4641 coreFrame->editor()->swapWithMark();4642 4495 } 4643 4496 … … 4684 4537 [style setDirection:writingDirection == NSWritingDirectionLeftToRight ? @"LTR" : @"RTL"]; 4685 4538 [self _applyParagraphStyleToSelection:style withUndoAction:EditActionSetWritingDirection]; 4686 }4687 4688 - (void)indent:(id)sender4689 {4690 COMMAND_PROLOGUE4691 4692 if (Frame* coreFrame = core([self _frame]))4693 coreFrame->editor()->indent();4694 }4695 4696 - (void)outdent:(id)sender4697 {4698 COMMAND_PROLOGUE4699 4700 if (Frame* coreFrame = core([self _frame]))4701 coreFrame->editor()->outdent();4702 4539 } 4703 4540 … … 5015 4852 } 5016 4853 5017 - (void)copy:(id)sender5018 {5019 COMMAND_PROLOGUE5020 5021 if (Frame* coreFrame = core([self _frame]))5022 coreFrame->editor()->copy();5023 }5024 5025 - (void)cut:(id)sender5026 {5027 COMMAND_PROLOGUE5028 5029 if (Frame* coreFrame = core([self _frame]))5030 coreFrame->editor()->cut();5031 }5032 5033 4854 - (void)paste:(id)sender 5034 4855 { … … 5227 5048 bool haveTextInsertionCommands = false; 5228 5049 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()) 5230 5051 haveTextInsertionCommands = true; 5231 5052 } … … 5570 5391 Frame* coreFrame = core([self _frame]); 5571 5392 if (![[webView _editingDelegateForwarder] webView:webView doCommandBySelector:selector] && coreFrame) { 5572 AtomicString commandName = selectorToCommandName(selector);5573 if ( Editor::isTextInsertionCommand(commandName))5574 eventWasHandled = co reFrame->editor()->execCommand(commandName,event);5393 Editor::Command command = [self coreCommandBySelector:selector]; 5394 if (command.isTextInsertion()) 5395 eventWasHandled = command.execute(event); 5575 5396 else { 5576 5397 _private->selectorForDoCommandBySelector = selector; -
trunk/WebKit/mac/WebView/WebHTMLViewInternal.h
r28371 r28626 117 117 - (id<WebHTMLHighlighter>)_highlighterForType:(NSString*)type; 118 118 - (WebFrame *)_frame; 119 - (void)copy:(id)sender;120 - (void)cut:(id)sender;121 119 - (void)paste:(id)sender; 122 - (void)pasteAsPlainText:(id)sender;123 120 - (void)closeIfNotCurrentView; 124 121 - (void)_lookUpInDictionaryFromMenu:(id)sender; -
trunk/WebKit/win/ChangeLog
r28620 r28626 1 2007-12-11 Darin Adler <darin@apple.com> 2 3 * WebView.cpp: 4 (WebView::handleEditingKeyboardEvent): Update for change to Editor API. 5 1 6 2007-12-07 Alexey Proskuryakov <ap@webkit.org> 2 7 -
trunk/WebKit/win/WebView.cpp
r28620 r28626 1370 1370 return false; 1371 1371 1372 Editor::Command command = frame->editor()->command(interpretKeyEvent(evt)); 1373 1372 1374 if (keyEvent->type() == PlatformKeyboardEvent::RawKeyDown) { 1373 String command = interpretKeyEvent(evt);1374 1375 1375 // WebKit doesn't have enough information about mode to decide how commands that just insert text if executed via Editor should be treated, 1376 1376 // so we leave it upon WebCore to either handle them immediately (e.g. Tab that changes focus) or let a keypress event be generated 1377 1377 // (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; 1388 1383 1389 1384 // Don't insert null or control characters as they can result in unexpected behaviour
Note: See TracChangeset
for help on using the changeset viewer.