Commit 060d7a1a authored by darin@apple.com's avatar darin@apple.com

2011-02-15 Jia Pu <jpu@apple.com>

        Reviewed by Darin Adler.

        Autocorrection should respect undo.
        https://bugs.webkit.org/show_bug.cgi?id=52221
        <rdar://problem/8663399>

        Please see WebCore/ChangeLog for detailed description.

        * WebCoreSupport/WebEditorClient.cpp:
        (WebFrameImpl::replaceSelection): Adopted new signature of ReplaceSelectionCommand::create().
2011-02-15  Jia Pu  <jpu@apple.com>

        Reviewed by Darin Adler.

        Autocorrection should respect undo.
        https://bugs.webkit.org/show_bug.cgi?id=52221
        <rdar://problem/8663399>

        Please see WebCore/ChangeLog for detailed description.

        * WebCoreSupport/WebEditorClient.h: Updated for the new function declared in EditorClient.

        * WebCoreSupport/WebEditorClient.mm:
        (WebEditorClient::recordAutocorrectionResponse): Ditto.

        * WebView/WebFrame.mm:
        (-[WebFrame _replaceSelectionWithFragment:selectReplacement:smartReplace:matchStyle:]):
             Adopted new signature of ReplaceSelectionCommand::create().
2011-02-15  Jia Pu  <jpu@apple.com>

        Reviewed by Darin Adler.

        Autocorrection should respect undo.
        https://bugs.webkit.org/show_bug.cgi?id=52221
        <rdar://problem/8663399>

        Manual test: manual-tests/autocorrection/undo-autocorrection.html

        When user undoes an autocorrection, we need to do four things:
        1. Revert the change in text that has been made by correction.
        2. Revert the selection to pre-correction state so that user can immediately continue typing.
        3. Add appropriate markers to reverted text so that it won't be corrected again and/or shown
           as misspelled.
        4. If applicable, notify spell checking service to record this reversion.

        To achieve these, this patch introduces following changes:
        1. Created SpellingCorrectionCommand so that correction can be undone in similar way as any
           other editing command. SpellingCorrectionCommand is a composition of SetSelectionCommand,
           SpellingCorrectionRecordUndoCommand and ReplaceSelectionCommand.
        2. Created SetSelectionCommand so that undo command can restore selection state.
        3. Added member function recordAutocorrectionResponse() to editor client.

        To improve readability, this patch also consolidates various boolean arguments in SelectionController::setSelection()
        and ReplaceSelectionCommand::ReplaceSelectionCommand(). These boolean arguments have been
        replaced by enum variable.

        * WebCore.exp.in: Updated for changes in Editor and ReplaceSelectionCommand.

        * WebCore.xcodeproj/project.pbxproj: Updated for new source files.

        * editing/CompositeEditCommand.cpp:
        (WebCore::CompositeEditCommand::moveParagraphs): Adopted new signature of ReplaceSelectionCommand::create().

        * editing/Editor.cpp:
        (WebCore::Editor::replaceSelectionWithFragment): Ditto.
        (WebCore::Editor::unappliedEditing): Cleaned up trailing whitespace.
        (WebCore::Editor::reappliedEditing): Ditto.
        (WebCore::Editor::selectComposition): Adopted new signature of SelectionController::setSelection().
        (WebCore::Editor::confirmComposition): Ditto.
        (WebCore::Editor::markAllMisspellingsAndBadGrammarInRanges): Rearranged code to reduce the
            level of deeply nested if statement. Adopted SpellingCorrectionCommand.
        (WebCore::Editor::applyCorrectionPanelInfo): Adopted SpellingCorrectionCommand.
        (WebCore::Editor::unappliedSpellCorrection): Function for adding markers to reverted text and
            for notifiying editor client about undone correction.
        (WebCore::Editor::changeSelectionAfterCommand): Adopted new signature of SelectionController::setSelection().
        (WebCore::Editor::respondToChangedSelection): Use SelectionController::SetSelectionOptions
            instead of boolean variables.

        * editing/Editor.h: Added Editor::unappliedSpellCorrection().

        * editing/EditorCommand.cpp:
        (WebCore::executeInsertFragment): Adopted new signature of ReplaceSelectionCommand::create().

        * editing/MoveSelectionCommand.cpp:
        (WebCore::MoveSelectionCommand::doApply): Ditto.

        * editing/ReplaceSelectionCommand.cpp:
        (WebCore::ReplaceSelectionCommand::ReplaceSelectionCommand): Replaced all boolean arguments
            with an enum value.

        * editing/ReplaceSelectionCommand.h:
        (WebCore::ReplaceSelectionCommand::create): Ditto.

        * editing/SelectionController.cpp: Adopted new signature of SelectionController::setSelection().
        (WebCore::SelectionController::moveTo):
        (WebCore::SelectionController::setSelection):
        (WebCore::SelectionController::respondToNodeModification):
        (WebCore::SelectionController::setBase):
        (WebCore::SelectionController::setExtent):
        (WebCore::SelectionController::setSelectedRange):

        * editing/SelectionController.h:
        (WebCore::SelectionController::setSelection): Replaced all boolean arguments with an enum value.

        * editing/SetSelectionCommand.cpp: Added.
        (WebCore::SetSelectionCommand::SetSelectionCommand):
        (WebCore::SetSelectionCommand::doApply):
        (WebCore::SetSelectionCommand::doUnapply):

        * editing/SetSelectionCommand.h: Added.
        (WebCore::SetSelectionCommand::create):

        * editing/mac/SpellingCorrectionCommand.cpp: Added.
        (WebCore::SpellingCorrectionRecordUndoCommand::create):
        (WebCore::SpellingCorrectionRecordUndoCommand::SpellingCorrectionRecordUndoCommand):
        (WebCore::SpellingCorrectionRecordUndoCommand::doApply):
        (WebCore::SpellingCorrectionRecordUndoCommand::doUnapply):
        (WebCore::SpellingCorrectionCommand::SpellingCorrectionCommand):
        (WebCore::SpellingCorrectionCommand::doApply):

        * editing/mac/SpellingCorrectionCommand.h: Added.
        (WebCore::SpellingCorrectionCommand::create):

        * loader/EmptyClients.h: Updated for the new function declared in EditorClient.
        (WebCore::EmptyEditorClient::recordAutocorrectionResponse):

        * manual-tests/autocorrection/undo-autocorrection.html: Added.

        * page/ContextMenuController.cpp:
        (WebCore::ContextMenuController::contextMenuItemSelected): Adopted new signature of ReplaceSelectionCommand::create().

        * page/DragController.cpp:
        (WebCore::DragController::concludeEditDrag): Ditto.

        * page/EditorClient.h: Added EditorClient::recordAutocorrectionResponse().
2011-02-15  Jia Pu  <jpu@apple.com>

        Reviewed by Darin Adler.

        Autocorrection should respect undo.
        https://bugs.webkit.org/show_bug.cgi?id=52221
        <rdar://problem/8663399>

        Please see WebCore/ChangeLog for detailed description.

        * WebProcess/WebCoreSupport/WebEditorClient.h: Updated for the new function declared in EditorClient.

        * WebProcess/WebCoreSupport/mac/WebEditorClientMac.mm:
        (WebKit::WebEditorClient::recordAutocorrectionResponse): Ditto.

        * WebProcess/WebPage/WebPage.cpp:
        (WebKit::WebPage::replaceSelectionWithText): Adopted new signature of ReplaceSelectionCommand::create().


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@78632 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 312046e4
2011-02-15 Jia Pu <jpu@apple.com>
Reviewed by Darin Adler.
Autocorrection should respect undo.
https://bugs.webkit.org/show_bug.cgi?id=52221
<rdar://problem/8663399>
Manual test: manual-tests/autocorrection/undo-autocorrection.html
When user undoes an autocorrection, we need to do four things:
1. Revert the change in text that has been made by correction.
2. Revert the selection to pre-correction state so that user can immediately continue typing.
3. Add appropriate markers to reverted text so that it won't be corrected again and/or shown
as misspelled.
4. If applicable, notify spell checking service to record this reversion.
To achieve these, this patch introduces following changes:
1. Created SpellingCorrectionCommand so that correction can be undone in similar way as any
other editing command. SpellingCorrectionCommand is a composition of SetSelectionCommand,
SpellingCorrectionRecordUndoCommand and ReplaceSelectionCommand.
2. Created SetSelectionCommand so that undo command can restore selection state.
3. Added member function recordAutocorrectionResponse() to editor client.
To improve readability, this patch also consolidates various boolean arguments in SelectionController::setSelection()
and ReplaceSelectionCommand::ReplaceSelectionCommand(). These boolean arguments have been
replaced by enum variable.
* WebCore.exp.in: Updated for changes in Editor and ReplaceSelectionCommand.
* WebCore.xcodeproj/project.pbxproj: Updated for new source files.
* editing/CompositeEditCommand.cpp:
(WebCore::CompositeEditCommand::moveParagraphs): Adopted new signature of ReplaceSelectionCommand::create().
* editing/Editor.cpp:
(WebCore::Editor::replaceSelectionWithFragment): Ditto.
(WebCore::Editor::unappliedEditing): Cleaned up trailing whitespace.
(WebCore::Editor::reappliedEditing): Ditto.
(WebCore::Editor::selectComposition): Adopted new signature of SelectionController::setSelection().
(WebCore::Editor::confirmComposition): Ditto.
(WebCore::Editor::markAllMisspellingsAndBadGrammarInRanges): Rearranged code to reduce the
level of deeply nested if statement. Adopted SpellingCorrectionCommand.
(WebCore::Editor::applyCorrectionPanelInfo): Adopted SpellingCorrectionCommand.
(WebCore::Editor::unappliedSpellCorrection): Function for adding markers to reverted text and
for notifiying editor client about undone correction.
(WebCore::Editor::changeSelectionAfterCommand): Adopted new signature of SelectionController::setSelection().
(WebCore::Editor::respondToChangedSelection): Use SelectionController::SetSelectionOptions
instead of boolean variables.
* editing/Editor.h: Added Editor::unappliedSpellCorrection().
* editing/EditorCommand.cpp:
(WebCore::executeInsertFragment): Adopted new signature of ReplaceSelectionCommand::create().
* editing/MoveSelectionCommand.cpp:
(WebCore::MoveSelectionCommand::doApply): Ditto.
* editing/ReplaceSelectionCommand.cpp:
(WebCore::ReplaceSelectionCommand::ReplaceSelectionCommand): Replaced all boolean arguments
with an enum value.
* editing/ReplaceSelectionCommand.h:
(WebCore::ReplaceSelectionCommand::create): Ditto.
* editing/SelectionController.cpp: Adopted new signature of SelectionController::setSelection().
(WebCore::SelectionController::moveTo):
(WebCore::SelectionController::setSelection):
(WebCore::SelectionController::respondToNodeModification):
(WebCore::SelectionController::setBase):
(WebCore::SelectionController::setExtent):
(WebCore::SelectionController::setSelectedRange):
* editing/SelectionController.h:
(WebCore::SelectionController::setSelection): Replaced all boolean arguments with an enum value.
* editing/SetSelectionCommand.cpp: Added.
(WebCore::SetSelectionCommand::SetSelectionCommand):
(WebCore::SetSelectionCommand::doApply):
(WebCore::SetSelectionCommand::doUnapply):
* editing/SetSelectionCommand.h: Added.
(WebCore::SetSelectionCommand::create):
* editing/mac/SpellingCorrectionCommand.cpp: Added.
(WebCore::SpellingCorrectionRecordUndoCommand::create):
(WebCore::SpellingCorrectionRecordUndoCommand::SpellingCorrectionRecordUndoCommand):
(WebCore::SpellingCorrectionRecordUndoCommand::doApply):
(WebCore::SpellingCorrectionRecordUndoCommand::doUnapply):
(WebCore::SpellingCorrectionCommand::SpellingCorrectionCommand):
(WebCore::SpellingCorrectionCommand::doApply):
* editing/mac/SpellingCorrectionCommand.h: Added.
(WebCore::SpellingCorrectionCommand::create):
* loader/EmptyClients.h: Updated for the new function declared in EditorClient.
(WebCore::EmptyEditorClient::recordAutocorrectionResponse):
* manual-tests/autocorrection/undo-autocorrection.html: Added.
* page/ContextMenuController.cpp:
(WebCore::ContextMenuController::contextMenuItemSelected): Adopted new signature of ReplaceSelectionCommand::create().
* page/DragController.cpp:
(WebCore::DragController::concludeEditDrag): Ditto.
* page/EditorClient.h: Added EditorClient::recordAutocorrectionResponse().
2011-02-15 Beth Dakin <bdakin@apple.com>
Reviewed by Darin Adler.
......@@ -489,7 +489,7 @@ __ZN7WebCore19ResourceRequestBase13setHTTPMethodERKN3WTF6StringE
__ZN7WebCore19ResourceRequestBase19addHTTPHeaderFieldsERKNS_13HTTPHeaderMapE
__ZN7WebCore19ResourceRequestBase6setURLERKNS_4KURLE
__ZN7WebCore19SelectionController10setFocusedEb
__ZN7WebCore19SelectionController12setSelectionERKNS_16VisibleSelectionEbbbNS0_19CursorAlignOnScrollENS_15TextGranularityENS_20DirectionalityPolicyE
__ZN7WebCore19SelectionController12setSelectionERKNS_16VisibleSelectionEjNS0_19CursorAlignOnScrollENS_15TextGranularityENS_20DirectionalityPolicyE
__ZN7WebCore19SelectionController15revealSelectionERKNS_15ScrollAlignmentEb
__ZN7WebCore19SelectionController16setSelectedRangeEPNS_5RangeENS_9EAffinityEb
__ZN7WebCore19SelectionController20setSelectionFromNoneEv
......@@ -535,9 +535,9 @@ __ZN7WebCore22counterValueForElementEPNS_7ElementE
__ZN7WebCore22createFragmentFromTextEPNS_5RangeERKN3WTF6StringE
__ZN7WebCore22externalRepresentationEPNS_5FrameEj
__ZN7WebCore23AuthenticationChallengeC1ERKNS_15ProtectionSpaceERKNS_10CredentialEjRKNS_16ResourceResponseERKNS_13ResourceErrorE
__ZN7WebCore23ReplaceSelectionCommandC1EPNS_8DocumentEN3WTF10PassRefPtrINS_16DocumentFragmentEEEbbbbbNS_10EditActionE
__ZN7WebCore23createFragmentFromNodesEPNS_8DocumentERKN3WTF6VectorIPNS_4NodeELm0EEE
__ZN7WebCore23overrideDefaultLanguageERKN3WTF6StringE
__ZN7WebCore23ReplaceSelectionCommandC1EPNS_8DocumentEN3WTF10PassRefPtrINS_16DocumentFragmentEEEjNS_10EditActionE
__ZN7WebCore24BinaryPropertyListWriter17writePropertyListEv
__ZN7WebCore24DocumentMarkerController13removeMarkersEj
__ZN7WebCore24DocumentMarkerController14markersForNodeEPNS_4NodeE
......
......@@ -4769,6 +4769,10 @@
B885E8D411E06DD2009FFBF4 /* InspectorApplicationCacheAgent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B885E8D211E06DD2009FFBF4 /* InspectorApplicationCacheAgent.cpp */; };
B885E8D511E06DD2009FFBF4 /* InspectorApplicationCacheAgent.h in Headers */ = {isa = PBXBuildFile; fileRef = B885E8D311E06DD2009FFBF4 /* InspectorApplicationCacheAgent.h */; settings = {ATTRIBUTES = (); }; };
B8A6A6D5127B338D008673BA /* CorrectionPanelInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = B8A6A6D4127B338D008673BA /* CorrectionPanelInfo.h */; settings = {ATTRIBUTES = (Private, ); }; };
B8DBDB4B130B0F8A00F5CDB1 /* SetSelectionCommand.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B8DBDB47130B0F8A00F5CDB1 /* SetSelectionCommand.cpp */; };
B8DBDB4C130B0F8A00F5CDB1 /* SetSelectionCommand.h in Headers */ = {isa = PBXBuildFile; fileRef = B8DBDB48130B0F8A00F5CDB1 /* SetSelectionCommand.h */; };
B8DBDB4D130B0F8A00F5CDB1 /* SpellingCorrectionCommand.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B8DBDB49130B0F8A00F5CDB1 /* SpellingCorrectionCommand.cpp */; };
B8DBDB4E130B0F8A00F5CDB1 /* SpellingCorrectionCommand.h in Headers */ = {isa = PBXBuildFile; fileRef = B8DBDB4A130B0F8A00F5CDB1 /* SpellingCorrectionCommand.h */; };
BC00F0040E0A185500FD04E3 /* DOMFile.h in Headers */ = {isa = PBXBuildFile; fileRef = BC00EFFE0E0A185500FD04E3 /* DOMFile.h */; };
BC00F0050E0A185500FD04E3 /* DOMFile.mm in Sources */ = {isa = PBXBuildFile; fileRef = BC00EFFF0E0A185500FD04E3 /* DOMFile.mm */; };
BC00F0060E0A185500FD04E3 /* DOMFileInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = BC00F0000E0A185500FD04E3 /* DOMFileInternal.h */; };
......@@ -11061,6 +11065,10 @@
B885E8D211E06DD2009FFBF4 /* InspectorApplicationCacheAgent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InspectorApplicationCacheAgent.cpp; sourceTree = "<group>"; };
B885E8D311E06DD2009FFBF4 /* InspectorApplicationCacheAgent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InspectorApplicationCacheAgent.h; sourceTree = "<group>"; };
B8A6A6D4127B338D008673BA /* CorrectionPanelInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CorrectionPanelInfo.h; sourceTree = "<group>"; };
B8DBDB47130B0F8A00F5CDB1 /* SetSelectionCommand.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SetSelectionCommand.cpp; sourceTree = "<group>"; };
B8DBDB48130B0F8A00F5CDB1 /* SetSelectionCommand.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SetSelectionCommand.h; sourceTree = "<group>"; };
B8DBDB49130B0F8A00F5CDB1 /* SpellingCorrectionCommand.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SpellingCorrectionCommand.cpp; sourceTree = "<group>"; };
B8DBDB4A130B0F8A00F5CDB1 /* SpellingCorrectionCommand.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SpellingCorrectionCommand.h; sourceTree = "<group>"; };
BC00EFFE0E0A185500FD04E3 /* DOMFile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DOMFile.h; sourceTree = "<group>"; };
BC00EFFF0E0A185500FD04E3 /* DOMFile.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = DOMFile.mm; sourceTree = "<group>"; };
BC00F0000E0A185500FD04E3 /* DOMFileInternal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DOMFileInternal.h; sourceTree = "<group>"; };
......@@ -15324,6 +15332,10 @@
93309DBF099E64910056E581 /* SelectionController.h */,
93309DC0099E64910056E581 /* SetNodeAttributeCommand.cpp */,
93309DC1099E64910056E581 /* SetNodeAttributeCommand.h */,
B8DBDB47130B0F8A00F5CDB1 /* SetSelectionCommand.cpp */,
B8DBDB48130B0F8A00F5CDB1 /* SetSelectionCommand.h */,
B8DBDB49130B0F8A00F5CDB1 /* SpellingCorrectionCommand.cpp */,
B8DBDB4A130B0F8A00F5CDB1 /* SpellingCorrectionCommand.h */,
4B6FA6F30C39E48C00087011 /* SmartReplace.cpp */,
4B6FA6F20C39E48C00087011 /* SmartReplace.h */,
4B6FA6F60C39E4A100087011 /* SmartReplaceCF.cpp */,
......@@ -22420,6 +22432,8 @@
975CA28B130365F800E99AD9 /* Crypto.h in Headers */,
975CA2A21303679D00E99AD9 /* JSCrypto.h in Headers */,
26E98A10130A9FCA008EB7B2 /* TextCodecASCIIFastPath.h in Headers */,
B8DBDB4C130B0F8A00F5CDB1 /* SetSelectionCommand.h in Headers */,
B8DBDB4E130B0F8A00F5CDB1 /* SpellingCorrectionCommand.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
......@@ -25102,6 +25116,8 @@
A1E1154413015C3D0054AC8C /* DistantLightSource.cpp in Sources */,
A1E1154613015C4E0054AC8C /* PointLightSource.cpp in Sources */,
A1E1154813015C5D0054AC8C /* SpotLightSource.cpp in Sources */,
B8DBDB4B130B0F8A00F5CDB1 /* SetSelectionCommand.cpp in Sources */,
B8DBDB4D130B0F8A00F5CDB1 /* SpellingCorrectionCommand.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
......@@ -1006,7 +1006,10 @@ void CompositeEditCommand::moveParagraphs(const VisiblePosition& startOfParagrap
setEndingSelection(destination);
ASSERT(endingSelection().isCaretOrRange());
applyCommandToComposite(ReplaceSelectionCommand::create(document(), fragment, true, false, !preserveStyle, false, true));
ReplaceSelectionCommand::CommandOptions options = ReplaceSelectionCommand::SelectReplacement | ReplaceSelectionCommand::MovingParagraph;
if (!preserveStyle)
options |= ReplaceSelectionCommand::MatchStyle;
applyCommandToComposite(ReplaceSelectionCommand::create(document(), fragment, options));
document()->frame()->editor()->markMisspellingsAndBadGrammar(endingSelection());
......
......@@ -74,6 +74,7 @@
#include "Settings.h"
#include "Sound.h"
#include "SpellChecker.h"
#include "SpellingCorrectionCommand.h"
#include "Text.h"
#include "TextEvent.h"
#include "TextIterator.h"
......@@ -436,8 +437,15 @@ void Editor::replaceSelectionWithFragment(PassRefPtr<DocumentFragment> fragment,
{
if (m_frame->selection()->isNone() || !fragment)
return;
applyCommand(ReplaceSelectionCommand::create(m_frame->document(), fragment, selectReplacement, smartReplace, matchStyle));
ReplaceSelectionCommand::CommandOptions options = ReplaceSelectionCommand::PreventNesting;
if (selectReplacement)
options |= ReplaceSelectionCommand::SelectReplacement;
if (smartReplace)
options |= ReplaceSelectionCommand::SmartReplace;
if (matchStyle)
options |= ReplaceSelectionCommand::MatchStyle;
applyCommand(ReplaceSelectionCommand::create(m_frame->document(), fragment, options, EditActionPaste));
revealSelectionAfterEditingOperation();
Node* nodeToCheck = m_frame->selection()->rootEditableElement();
......@@ -1133,7 +1141,7 @@ void Editor::unappliedEditing(PassRefPtr<EditCommand> cmd)
m_lastEditCommand = 0;
if (client())
client()->registerCommandForRedo(cmd);
respondToChangedContents(newSelection);
respondToChangedContents(newSelection);
}
void Editor::reappliedEditing(PassRefPtr<EditCommand> cmd)
......@@ -1148,7 +1156,7 @@ void Editor::reappliedEditing(PassRefPtr<EditCommand> cmd)
m_lastEditCommand = 0;
if (client())
client()->registerCommandForUndo(cmd);
respondToChangedContents(newSelection);
respondToChangedContents(newSelection);
}
Editor::Editor(Frame* frame)
......@@ -1587,7 +1595,7 @@ void Editor::selectComposition()
// See <http://bugs.webkit.org/show_bug.cgi?id=15781>
VisibleSelection selection;
selection.setWithoutValidation(range->startPosition(), range->endPosition());
m_frame->selection()->setSelection(selection, false, false);
m_frame->selection()->setSelection(selection, 0);
}
void Editor::confirmComposition()
......@@ -1645,7 +1653,7 @@ void Editor::confirmComposition(const String& text, bool preserveSelection)
insertTextForConfirmedComposition(text);
if (preserveSelection) {
m_frame->selection()->setSelection(oldSelection, false, false);
m_frame->selection()->setSelection(oldSelection, 0);
// An open typing command that disagrees about current selection would cause issues with typing later on.
TypingCommand::closeTyping(m_lastEditCommand.get());
}
......@@ -2354,7 +2362,7 @@ void Editor::markAllMisspellingsAndBadGrammarInRanges(TextCheckingOptions textCh
// In this case the result range just has to touch the spelling range, so we can handle replacing non-word text such as punctuation.
ASSERT(resultLength > 0 && resultLocation >= 0);
if (shouldShowCorrectionPanel && resultLocation + resultLength < spellingRangeEndOffset)
if (shouldShowCorrectionPanel && (resultLocation + resultLength < spellingRangeEndOffset || result->type != TextCheckingTypeCorrection))
continue;
int replacementLength = result->replacement.length();
......@@ -2369,10 +2377,10 @@ void Editor::markAllMisspellingsAndBadGrammarInRanges(TextCheckingOptions textCh
// adding links should be done only immediately after they are typed
if (result->type == TextCheckingTypeLink && selectionOffset > resultLocation + resultLength + 1)
doReplacement = false;
continue;
// Don't correct spelling in an already-corrected word.
if (doReplacement && result->type == TextCheckingTypeCorrection) {
if (result->type == TextCheckingTypeCorrection) {
Node* node = rangeToReplace->startContainer();
int startOffset = rangeToReplace->startOffset();
int endOffset = startOffset + replacementLength;
......@@ -2388,58 +2396,74 @@ void Editor::markAllMisspellingsAndBadGrammarInRanges(TextCheckingOptions textCh
break;
}
}
if (doReplacement && !shouldShowCorrectionPanel && selectionToReplace != m_frame->selection()->selection()) {
if (m_frame->selection()->shouldChangeSelection(selectionToReplace)) {
m_frame->selection()->setSelection(selectionToReplace);
selectionChanged = true;
} else {
doReplacement = false;
if (!doReplacement)
continue;
#if SUPPORT_AUTOCORRECTION_PANEL
if (shouldShowCorrectionPanel) {
if (resultLocation + resultLength == spellingRangeEndOffset) {
// We only show the correction panel on the last word.
Vector<FloatQuad> textQuads;
rangeToReplace->getBorderAndTextQuads(textQuads);
Vector<FloatQuad>::const_iterator end = textQuads.end();
FloatRect totalBoundingBox;
for (Vector<FloatQuad>::const_iterator it = textQuads.begin(); it < end; ++it)
totalBoundingBox.unite(it->boundingBox());
m_correctionPanelInfo.rangeToBeReplaced = rangeToReplace;
m_correctionPanelInfo.replacedString = plainText(rangeToReplace.get());
m_correctionPanelInfo.replacementString = result->replacement;
m_correctionPanelInfo.isActive = true;
client()->showCorrectionPanel(m_correctionPanelInfo.panelType, totalBoundingBox, m_correctionPanelInfo.replacedString, result->replacement, Vector<String>(), this);
break;
}
// If this function is called for showing correction panel, we ignore other correction or replacement.
continue;
}
#endif
String replacedString;
if (doReplacement) {
if (result->type == TextCheckingTypeLink) {
restoreSelectionAfterChange = false;
if (canEditRichly())
applyCommand(CreateLinkCommand::create(m_frame->document(), result->replacement));
} else if (canEdit() && shouldInsertText(result->replacement, rangeToReplace.get(), EditorInsertActionTyped)) {
if (result->type == TextCheckingTypeCorrection)
replacedString = plainText(rangeToReplace.get());
#if SUPPORT_AUTOCORRECTION_PANEL
if (shouldShowCorrectionPanel && resultLocation + resultLength == spellingRangeEndOffset && result->type == TextCheckingTypeCorrection) {
// We only show the correction panel on the last word.
Vector<FloatQuad> textQuads;
rangeToReplace->getBorderAndTextQuads(textQuads);
Vector<FloatQuad>::const_iterator end = textQuads.end();
FloatRect totalBoundingBox;
for (Vector<FloatQuad>::const_iterator it = textQuads.begin(); it < end; ++it)
totalBoundingBox.unite(it->boundingBox());
m_correctionPanelInfo.rangeToBeReplaced = rangeToReplace;
m_correctionPanelInfo.replacedString = replacedString;
m_correctionPanelInfo.replacementString = result->replacement;
m_correctionPanelInfo.isActive = true;
client()->showCorrectionPanel(m_correctionPanelInfo.panelType, totalBoundingBox, m_correctionPanelInfo.replacedString, result->replacement, Vector<String>(), this);
doReplacement = false;
}
if (selectionToReplace != m_frame->selection()->selection()) {
if (!m_frame->selection()->shouldChangeSelection(selectionToReplace))
continue;
}
if (result->type == TextCheckingTypeLink) {
m_frame->selection()->setSelection(selectionToReplace);
selectionChanged = true;
restoreSelectionAfterChange = false;
if (canEditRichly())
applyCommand(CreateLinkCommand::create(m_frame->document(), result->replacement));
} else if (canEdit() && shouldInsertText(result->replacement, rangeToReplace.get(), EditorInsertActionTyped)) {
String replacedString;
if (result->type == TextCheckingTypeCorrection)
replacedString = plainText(rangeToReplace.get());
bool useSpellingCorrectionCommand = false;
#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
if (result->type == TextCheckingTypeCorrection)
useSpellingCorrectionCommand = true;
#endif
if (doReplacement) {
replaceSelectionWithText(result->replacement, false, false);
offsetDueToReplacement += replacementLength - resultLength;
if (resultLocation < selectionOffset) {
selectionOffset += replacementLength - resultLength;
if (ambiguousBoundaryOffset >= 0)
ambiguousBoundaryOffset = selectionOffset - 1;
}
if (result->type == TextCheckingTypeCorrection) {
// Add a marker so that corrections can easily be undone and won't be re-corrected.
RefPtr<Range> replacedRange = paragraph.subrange(resultLocation, replacementLength);
replacedRange->startContainer()->document()->markers()->addMarker(replacedRange.get(), DocumentMarker::Replacement, replacedString);
replacedRange->startContainer()->document()->markers()->addMarker(replacedRange.get(), DocumentMarker::CorrectionIndicator, replacedString);
replacedRange->startContainer()->document()->markers()->addMarker(replacedRange.get(), DocumentMarker::SpellCheckingExemption);
}
}
if (useSpellingCorrectionCommand)
applyCommand(SpellingCorrectionCommand::create(rangeToReplace, result->replacement));
else {
m_frame->selection()->setSelection(selectionToReplace);
replaceSelectionWithText(result->replacement, false, false);
}
selectionChanged = true;
offsetDueToReplacement += replacementLength - resultLength;
if (resultLocation < selectionOffset) {
selectionOffset += replacementLength - resultLength;
if (ambiguousBoundaryOffset >= 0)
ambiguousBoundaryOffset = selectionOffset - 1;
}
if (result->type == TextCheckingTypeCorrection) {
// Add a marker so that corrections can easily be undone and won't be re-corrected.
RefPtr<Range> replacedRange = paragraph.subrange(resultLocation, replacementLength);
replacedRange->startContainer()->document()->markers()->addMarker(replacedRange.get(), DocumentMarker::Replacement, replacedString);
replacedRange->startContainer()->document()->markers()->addMarker(replacedRange.get(), DocumentMarker::CorrectionIndicator, replacedString);
replacedRange->startContainer()->document()->markers()->addMarker(replacedRange.get(), DocumentMarker::SpellCheckingExemption);
}
}
}
......@@ -2689,6 +2713,7 @@ void Editor::removeSpellAndCorrectionMarkersFromWordsToBeEdited(bool doNotRemove
void Editor::applyCorrectionPanelInfo(const Vector<DocumentMarker::MarkerType>& markerTypesToAdd)
{
#if SUPPORT_AUTOCORRECTION_PANEL
if (!m_correctionPanelInfo.rangeToBeReplaced)
return;
......@@ -2720,21 +2745,26 @@ void Editor::applyCorrectionPanelInfo(const Vector<DocumentMarker::MarkerType>&
// Clone the range, since the caller of this method may want to keep the original range around.
RefPtr<Range> rangeToBeReplaced = m_correctionPanelInfo.rangeToBeReplaced->cloneRange(ec);
VisibleSelection selectionToReplace(rangeToBeReplaced.get(), DOWNSTREAM);
if (m_frame->selection()->shouldChangeSelection(selectionToReplace)) {
m_frame->selection()->setSelection(selectionToReplace);
replaceSelectionWithText(m_correctionPanelInfo.replacementString, false, false);
setEnd(paragraphRangeContainingCorrection.get(), m_frame->selection()->selection().start());
RefPtr<Range> replacementRange = TextIterator::subrange(paragraphRangeContainingCorrection.get(), correctionStartOffsetInParagraph, m_correctionPanelInfo.replacementString.length());
DocumentMarkerController* markers = replacementRange->startContainer()->document()->markers();
size_t size = markerTypesToAdd.size();
for (size_t i = 0; i < size; ++i) {
if (m_correctionPanelInfo.panelType == CorrectionPanelInfo::PanelTypeReversion)
markers->addMarker(replacementRange.get(), markerTypesToAdd[i]);
else
markers->addMarker(replacementRange.get(), markerTypesToAdd[i], m_correctionPanelInfo.replacedString);
}
applyCommand(SpellingCorrectionCommand::create(rangeToBeReplaced, m_correctionPanelInfo.replacementString));
setEnd(paragraphRangeContainingCorrection.get(), m_frame->selection()->selection().start());
RefPtr<Range> replacementRange = TextIterator::subrange(paragraphRangeContainingCorrection.get(), correctionStartOffsetInParagraph, m_correctionPanelInfo.replacementString.length());
String newText = plainText(replacementRange.get());
// Check to see if replacement succeeded.
if (newText != m_correctionPanelInfo.replacementString)
return;
DocumentMarkerController* markers = replacementRange->startContainer()->document()->markers();
size_t size = markerTypesToAdd.size();
for (size_t i = 0; i < size; ++i) {
if (m_correctionPanelInfo.panelType == CorrectionPanelInfo::PanelTypeReversion)
markers->addMarker(replacementRange.get(), markerTypesToAdd[i]);
else
markers->addMarker(replacementRange.get(), markerTypesToAdd[i], m_correctionPanelInfo.replacedString);
}
#else // SUPPORT_AUTOCORRECTION_PANEL
UNUSED_PARAM(markerTypesToAdd);
#endif // SUPPORT_AUTOCORRECTION_PANEL
}
void Editor::applyAutocorrectionBeforeTypingIfAppropriate()
......@@ -2752,6 +2782,25 @@ void Editor::applyAutocorrectionBeforeTypingIfAppropriate()
dismissCorrectionPanel(m_correctionPanelInfo.rangeToBeReplaced->endPosition() == caretPosition ? ReasonForDismissingCorrectionPanelAccepted : ReasonForDismissingCorrectionPanelIgnored);
}
void Editor::unappliedSpellCorrection(const VisibleSelection& selectionOfCorrected, const String& corrected, const String& correction)
{
#if SUPPORT_AUTOCORRECTION_PANEL
client()->recordAutocorrectionResponse(EditorClient::AutocorrectionReverted, corrected, correction);
m_frame->document()->updateLayout();
m_frame->selection()->setSelection(selectionOfCorrected, SelectionController::CloseTyping | SelectionController::ClearTypingStyle | SelectionController::SpellCorrectionTriggered);
RefPtr<Range> range = Range::create(m_frame->document(), m_frame->selection()->selection().start(), m_frame->selection()->selection().end());
DocumentMarkerController* markers = m_frame->document()->markers();
markers->removeMarkers(range.get(), DocumentMarker::Spelling);
markers->addMarker(range.get(), DocumentMarker::Replacement);
markers->addMarker(range.get(), DocumentMarker::SpellCheckingExemption);
#else // SUPPORT_AUTOCORRECTION_PANEL
UNUSED_PARAM(selectionOfCorrected);
UNUSED_PARAM(corrected);
UNUSED_PARAM(correction);
#endif // SUPPORT_AUTOCORRECTION_PANEL
}
PassRefPtr<Range> Editor::rangeForPoint(const IntPoint& windowPoint)
{
Document* document = m_frame->documentAtPoint(windowPoint);
......@@ -3023,8 +3072,14 @@ void Editor::changeSelectionAfterCommand(const VisibleSelection& newSelection, b
// The old selection can be invalid here and calling shouldChangeSelection can produce some strange calls.
// See <rdar://problem/5729315> Some shouldChangeSelectedDOMRange contain Ranges for selections that are no longer valid
bool selectionDidNotChangeDOMPosition = newSelection == m_frame->selection()->selection();
if (selectionDidNotChangeDOMPosition || m_frame->selection()->shouldChangeSelection(newSelection))
m_frame->selection()->setSelection(newSelection, closeTyping, clearTypingStyle);
if (selectionDidNotChangeDOMPosition || m_frame->selection()->shouldChangeSelection(newSelection)) {
SelectionController::SetSelectionOptions options = 0;
if (closeTyping)
options |= SelectionController::CloseTyping;
if (clearTypingStyle)
options |= SelectionController::ClearTypingStyle;
m_frame->selection()->setSelection(newSelection, options);
}
// Some editing operations change the selection visually without affecting its position within the DOM.
// For example when you press return in the following (the caret is marked by ^):
......@@ -3448,7 +3503,7 @@ void Editor::setMarkedTextMatchesAreHighlighted(bool flag)
m_frame->document()->markers()->repaintMarkers(DocumentMarker::TextMatch);
}
void Editor::respondToChangedSelection(const VisibleSelection& oldSelection, bool closeTyping)
void Editor::respondToChangedSelection(const VisibleSelection& oldSelection, SelectionController::SetSelectionOptions options)
{
#if SUPPORT_AUTOCORRECTION_PANEL
// Make sure there's no pending autocorrection before we call markMisspellingsAndBadGrammar() below.
......@@ -3459,6 +3514,7 @@ void Editor::respondToChangedSelection(const VisibleSelection& oldSelection, boo
}
#endif // SUPPORT_AUTOCORRECTION_PANEL
bool closeTyping = options & SelectionController::CloseTyping;
bool isContinuousSpellCheckingEnabled = this->isContinuousSpellCheckingEnabled();
bool isContinuousGrammarCheckingEnabled = isContinuousSpellCheckingEnabled && isGrammarCheckingEnabled();
if (isContinuousSpellCheckingEnabled) {
......@@ -3472,10 +3528,16 @@ void Editor::respondToChangedSelection(const VisibleSelection& oldSelection, boo
newSelectedSentence = VisibleSelection(startOfSentence(newStart), endOfSentence(newStart));
}
bool shouldCheckSpellingAndGrammar = true;
#if SUPPORT_AUTOCORRECTION_PANEL
// Don't check spelling and grammar if the change of selection is triggered by spelling correction itself.
shouldCheckSpellingAndGrammar = !(options & SelectionController::SpellCorrectionTriggered);
#endif
// When typing we check spelling elsewhere, so don't redo it here.
// If this is a change in selection resulting from a delete operation,
// oldSelection may no longer be in the document.
if (closeTyping && oldSelection.isContentEditable() && oldSelection.start().node() && oldSelection.start().node()->inDocument()) {
if (shouldCheckSpellingAndGrammar && closeTyping && oldSelection.isContentEditable() && oldSelection.start().node() && oldSelection.start().node()->inDocument()) {
VisiblePosition oldStart(oldSelection.visibleStart());
VisibleSelection oldAdjacentWords = VisibleSelection(startOfWord(oldStart, LeftWordIfOnBoundary), endOfWord(oldStart, RightWordIfOnBoundary));
if (oldAdjacentWords != newAdjacentWords) {
......
......@@ -35,6 +35,7 @@
#include "EditorDeleteAction.h"
#include "EditorInsertAction.h"
#include "FindOptions.h"
#include "SelectionController.h"
#include "Timer.h"
#include "VisibleSelection.h"
#include "WritingDirection.h"
......@@ -167,7 +168,8 @@ public:
void appliedEditing(PassRefPtr<EditCommand>);
void unappliedEditing(PassRefPtr<EditCommand>);
void reappliedEditing(PassRefPtr<EditCommand>);
void unappliedSpellCorrection(const VisibleSelection& selectionOfCorrected, const String& corrected, const String& correction);
bool selectionStartHasStyle(CSSStyleDeclaration*) const;
bool clientIsEditable() const;
......@@ -353,7 +355,7 @@ public:
IntRect firstRectForRange(Range*) const;
void respondToChangedSelection(const VisibleSelection& oldSelection, bool closeTyping);
void respondToChangedSelection(const VisibleSelection& oldSelection, SelectionController::SetSelectionOptions);
bool shouldChangeSelection(const VisibleSelection& oldSelection, const VisibleSelection& newSelection, EAffinity, bool stillSelecting) const;
RenderStyle* styleForSelectionStart(Node*& nodeToRemove) const;
......
......@@ -194,8 +194,7 @@ static bool executeApplyParagraphStyle(Frame* frame, EditorCommandSource source,
static bool executeInsertFragment(Frame* frame, PassRefPtr<DocumentFragment> fragment)
{
applyCommand(ReplaceSelectionCommand::create(frame->document(), fragment,
false, false, false, true, false, EditActionUnspecified));
applyCommand(ReplaceSelectionCommand::create(frame->document(), fragment, ReplaceSelectionCommand::PreventNesting, EditActionUnspecified));
return true;
}
......
......@@ -70,7 +70,10 @@ void MoveSelectionCommand::doApply()
// Document was modified out from under us.
return;
}
applyCommandToComposite(ReplaceSelectionCommand::create(document(), m_fragment, true, m_smartInsert));
ReplaceSelectionCommand::CommandOptions options = ReplaceSelectionCommand::SelectReplacement | ReplaceSelectionCommand::PreventNesting;
if (m_smartInsert)
options |= ReplaceSelectionCommand::SmartReplace;
applyCommandToComposite(ReplaceSelectionCommand::create(document(), m_fragment, options));
}
EditAction MoveSelectionCommand::editingAction() const
......
......@@ -340,18 +340,16 @@ void ReplacementFragment::removeInterchangeNodes(Node* container)
}
}
ReplaceSelectionCommand::ReplaceSelectionCommand(Document* document, PassRefPtr<DocumentFragment> fragment,
bool selectReplacement, bool smartReplace, bool matchStyle, bool preventNesting, bool movingParagraph,
EditAction editAction)
: CompositeEditCommand(document),
m_selectReplacement(selectReplacement),
m_smartReplace(smartReplace),
m_matchStyle(matchStyle),
m_documentFragment(fragment),
m_preventNesting(preventNesting),
m_movingParagraph(movingParagraph),
m_editAction(editAction),
m_shouldMergeEnd(false)
ReplaceSelectionCommand::ReplaceSelectionCommand(Document* document, PassRefPtr<DocumentFragment> fragment, CommandOptions options, EditAction editAction)
: CompositeEditCommand(document)
, m_selectReplacement(options & SelectReplacement)
, m_smartReplace(options & SmartReplace)
, m_matchStyle(options & MatchStyle)
, m_documentFragment(fragment)
, m_preventNesting(options & PreventNesting)
, m_movingParagraph(options & MovingParagraph)
, m_editAction(editAction)
, m_shouldMergeEnd(false)
{
}
......
......@@ -36,16 +36,23 @@ class ReplacementFragment;
class ReplaceSelectionCommand : public CompositeEditCommand {
public:
static PassRefPtr<ReplaceSelectionCommand> create(Document* document, PassRefPtr<DocumentFragment> fragment,