Commit 27521495 authored by xiaochengh's avatar xiaochengh Committed by Commit bot

Perform Spellcheck Requesting before Dispatching Events

|ReplaceSelectionCommand| stores the inserted range after |doApply()|.
This range may be invalidated if |Editor::appliedEditing()| modifies the
DOM, causing spellcheck run on an invalid range.

This CL moves the spellcheck request into |Editor::appliedEditing()|
before dispatching any event, ensuring spellcheck run on a valid range.

BUG=580950
TEST=LayoutTests/editing/pasteboard/paste-webkit-editable-content-changed-crash.html

Review URL: https://codereview.chromium.org/1636883003

Cr-Commit-Position: refs/heads/master@{#371776}
parent 78f61359
<!DOCTYPE html>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<div id="src">
<div>Some text.</div>
<div>Some other text.</div>
</div>
<div contenteditable="true" id="dest"></div>
<div id="log"></div>
<script>
// A repro of crbug.com/580950, which crashes in debug build.
document.body.onload = function() {
var src = document.getElementById('src');
var dest = document.getElementById('dest');
var sel = window.getSelection();
dest.addEventListener('webkitEditableContentChanged', () => dest.innerHTML = 'foo');
test(function() {
sel.setBaseAndExtent(src, 0, src, src.childNodes.length);
document.execCommand('copy');
dest.focus();
document.execCommand('paste');
assert_equals(dest.innerHTML, 'foo');
}, 'A pasting that fires a webkitEditableContentChanged event should not crash.');
}
</script>
...@@ -514,14 +514,6 @@ void Editor::replaceSelectionWithFragment(PassRefPtrWillBeRawPtr<DocumentFragmen ...@@ -514,14 +514,6 @@ void Editor::replaceSelectionWithFragment(PassRefPtrWillBeRawPtr<DocumentFragmen
ASSERT(frame().document()); ASSERT(frame().document());
ReplaceSelectionCommand::create(*frame().document(), fragment, options, EditActionPaste)->apply(); ReplaceSelectionCommand::create(*frame().document(), fragment, options, EditActionPaste)->apply();
revealSelectionAfterEditingOperation(); revealSelectionAfterEditingOperation();
if (frame().selection().isInPasswordField() || !spellChecker().isContinuousSpellCheckingEnabled())
return;
ASSERT(lastEditCommand()->isReplaceSelectionCommand());
const EphemeralRange& insertedRange = toReplaceSelectionCommand(lastEditCommand())->insertedRange();
if (insertedRange.isNull())
return;
spellChecker().chunkAndMarkAllMisspellingsAndBadGrammar(frame().selection().rootEditableElement(), insertedRange);
} }
void Editor::replaceSelectionWithText(const String& text, bool selectReplacement, bool smartReplace) void Editor::replaceSelectionWithText(const String& text, bool selectReplacement, bool smartReplace)
...@@ -675,11 +667,30 @@ static void dispatchEditableContentChangedEvents(PassRefPtrWillBeRawPtr<Element> ...@@ -675,11 +667,30 @@ static void dispatchEditableContentChangedEvents(PassRefPtrWillBeRawPtr<Element>
endRoot->dispatchEvent(Event::create(EventTypeNames::webkitEditableContentChanged)); endRoot->dispatchEvent(Event::create(EventTypeNames::webkitEditableContentChanged));
} }
void Editor::requestSpellcheckingAfterApplyingCommand(CompositeEditCommand* cmd)
{
// Note: Request spell checking for and only for |ReplaceSelectionCommand|s
// created in |Editor::replaceSelectionWithFragment()|.
// TODO(xiaochengh): May also need to do this after dragging crbug.com/298046.
if (cmd->editingAction() != EditActionPaste)
return;
if (frame().selection().isInPasswordField() || !spellChecker().isContinuousSpellCheckingEnabled())
return;
ASSERT(cmd->isReplaceSelectionCommand());
const EphemeralRange& insertedRange = toReplaceSelectionCommand(cmd)->insertedRange();
if (insertedRange.isNull())
return;
spellChecker().chunkAndMarkAllMisspellingsAndBadGrammar(cmd->endingSelection().rootEditableElement(), insertedRange);
}
void Editor::appliedEditing(PassRefPtrWillBeRawPtr<CompositeEditCommand> cmd) void Editor::appliedEditing(PassRefPtrWillBeRawPtr<CompositeEditCommand> cmd)
{ {
EventQueueScope scope; EventQueueScope scope;
frame().document()->updateLayout(); frame().document()->updateLayout();
// Request spell checking after pasting before any further DOM change.
requestSpellcheckingAfterApplyingCommand(cmd.get());
EditCommandComposition* composition = cmd->composition(); EditCommandComposition* composition = cmd->composition();
ASSERT(composition); ASSERT(composition);
dispatchEditableContentChangedEvents(composition->startingRootEditableElement(), composition->endingRootEditableElement()); dispatchEditableContentChangedEvents(composition->startingRootEditableElement(), composition->endingRootEditableElement());
......
...@@ -288,6 +288,7 @@ private: ...@@ -288,6 +288,7 @@ private:
SpellChecker& spellChecker() const; SpellChecker& spellChecker() const;
bool handleEditingKeyboardEvent(KeyboardEvent*); bool handleEditingKeyboardEvent(KeyboardEvent*);
void requestSpellcheckingAfterApplyingCommand(CompositeEditCommand*);
}; };
inline void Editor::setStartNewKillRingSequence(bool flag) inline void Editor::setStartNewKillRingSequence(bool flag)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment