Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(204)

Unified Diff: third_party/WebKit/Source/core/editing/commands/TypingCommand.cpp

Issue 2530843003: Introduce InsertIncrementalTextCommand to respect existing style for composition (Closed)
Patch Set: Address xiaochengh@'s review Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: third_party/WebKit/Source/core/editing/commands/TypingCommand.cpp
diff --git a/third_party/WebKit/Source/core/editing/commands/TypingCommand.cpp b/third_party/WebKit/Source/core/editing/commands/TypingCommand.cpp
index 68aee201cbbe8b3e2226b5d4b3e667d7bc59ff60..89d68d2f22af91432529b53d4ce0e8e19ab4bfea 100644
--- a/third_party/WebKit/Source/core/editing/commands/TypingCommand.cpp
+++ b/third_party/WebKit/Source/core/editing/commands/TypingCommand.cpp
@@ -31,21 +31,99 @@
#include "core/dom/ElementTraversal.h"
#include "core/editing/EditingUtilities.h"
#include "core/editing/Editor.h"
+#include "core/editing/PlainTextRange.h"
#include "core/editing/SelectionModifier.h"
#include "core/editing/VisiblePosition.h"
#include "core/editing/VisibleUnits.h"
#include "core/editing/commands/BreakBlockquoteCommand.h"
+#include "core/editing/commands/InsertIncrementalTextCommand.h"
#include "core/editing/commands/InsertLineBreakCommand.h"
#include "core/editing/commands/InsertParagraphSeparatorCommand.h"
#include "core/editing/commands/InsertTextCommand.h"
#include "core/editing/spellcheck/SpellChecker.h"
#include "core/events/BeforeTextInsertedEvent.h"
+#include "core/events/TextEvent.h"
#include "core/frame/LocalFrame.h"
#include "core/html/HTMLBRElement.h"
#include "core/layout/LayoutObject.h"
namespace blink {
+namespace {
+
+String dispatchBeforeTextInsertedEvent(const String& text,
+ const VisibleSelection& selection) {
+ String newText = text;
+ if (Node* startNode = selection.start().computeContainerNode()) {
+ if (rootEditableElement(*startNode)) {
+ // Send BeforeTextInsertedEvent. The event handler will update text if
+ // necessary.
+ BeforeTextInsertedEvent* evt = BeforeTextInsertedEvent::create(text);
+ rootEditableElement(*startNode)->dispatchEvent(evt);
+ newText = evt->text();
+ }
+ }
+ return newText;
+}
+
+DispatchEventResult dispatchTextInputEvent(LocalFrame* frame,
+ const String& text) {
+ if (Element* target = frame->document()->focusedElement()) {
+ // Send TextInputEvent. Unlike BeforeTextInsertedEvent, there is no need to
+ // update text for TextInputEvent as it doesn't have the API to modify text.
+ TextEvent* event = TextEvent::create(frame->domWindow(), text,
+ TextEventInputIncrementalInsertion);
+ event->setUnderlyingEvent(nullptr);
+ return target->dispatchEvent(event);
+ }
+ return DispatchEventResult::CanceledBeforeDispatch;
+}
+
+PlainTextRange getSelectionOffsets(LocalFrame* frame) {
+ EphemeralRange range = firstEphemeralRangeOf(frame->selection().selection());
+ if (range.isNull())
+ return PlainTextRange();
+ ContainerNode* editable =
+ frame->selection().rootEditableElementOrTreeScopeRootNode();
+ DCHECK(editable);
+ return PlainTextRange::create(*editable, range);
+}
+
+VisibleSelection createSelection(const size_t start,
+ const size_t end,
+ const bool isDirectional,
+ Element* element) {
+ const EphemeralRange& startRange =
+ PlainTextRange(0, static_cast<int>(start)).createRange(*element);
+ DCHECK(startRange.isNotNull());
+ const Position& startPosition = startRange.endPosition();
+
+ const EphemeralRange& endRange =
+ PlainTextRange(0, static_cast<int>(end)).createRange(*element);
+ DCHECK(endRange.isNotNull());
+ const Position& endPosition = endRange.endPosition();
+
+ const VisibleSelection& selection =
+ createVisibleSelection(SelectionInDOMTree::Builder()
+ .setBaseAndExtent(startPosition, endPosition)
+ .setIsDirectional(isDirectional)
+ .build());
+ return selection;
+}
+
+bool canAppendNewLineFeedToSelection(const VisibleSelection& selection) {
+ Element* element = selection.rootEditableElement();
+ if (!element)
+ return false;
+
+ BeforeTextInsertedEvent* event =
+ BeforeTextInsertedEvent::create(String("\n"));
+ element->dispatchEvent(event);
+ return event->text().length();
+}
+
+} // anonymous namespace
+
using namespace HTMLNames;
TypingCommand::TypingCommand(Document& document,
@@ -143,7 +221,7 @@ void TypingCommand::forwardDeleteKeyPressed(Document& document,
}
String TypingCommand::textDataForInputEvent() const {
- if (m_commands.isEmpty())
+ if (m_commands.isEmpty() || isIncrementalInsertion())
return m_textToInsert;
return m_commands.back()->textDataForInputEvent();
}
@@ -160,30 +238,11 @@ void TypingCommand::updateSelectionIfDifferentFromCurrentSelection(
typingCommand->setEndingVisibleSelection(currentSelection);
}
-static String dispatchBeforeTextInsertedEvent(
- const String& text,
- const VisibleSelection& selectionForInsertion,
- bool insertionIsForUpdatingComposition) {
- if (insertionIsForUpdatingComposition)
- return text;
-
- String newText = text;
- if (Node* startNode = selectionForInsertion.start().computeContainerNode()) {
- if (rootEditableElement(*startNode)) {
- // Send BeforeTextInsertedEvent. The event handler will update text if
- // necessary.
- BeforeTextInsertedEvent* evt = BeforeTextInsertedEvent::create(text);
- rootEditableElement(*startNode)->dispatchEvent(evt);
- newText = evt->text();
- }
- }
- return newText;
-}
-
void TypingCommand::insertText(Document& document,
const String& text,
Options options,
- TextCompositionType composition) {
+ TextCompositionType composition,
+ const bool isIncrementalInsertion) {
LocalFrame* frame = document.frame();
DCHECK(frame);
@@ -192,7 +251,28 @@ void TypingCommand::insertText(Document& document,
isSpaceOrNewline(text[0]));
insertText(document, text, frame->selection().selection(), options,
- composition);
+ composition, isIncrementalInsertion);
+}
+
+void TypingCommand::adjustSelectionAfterIncrementalInsertion(
+ TypingCommand* command,
+ LocalFrame* frame,
+ const size_t start,
+ const size_t end) {
+ // TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets
+ // needs to be audited. see http://crbug.com/590369 for more details.
+ frame->document()->updateStyleAndLayoutIgnorePendingStylesheets();
+
+ Element* element = frame->selection().selection().rootEditableElement();
+ DCHECK(element);
+
+ const VisibleSelection& selection = createSelection(
+ start, end, command->endingSelection().isDirectional(), element);
+
+ if (selection != frame->selection().selection()) {
+ command->setEndingVisibleSelection(selection);
+ frame->selection().setSelection(selection);
+ }
}
// FIXME: We shouldn't need to take selectionForInsertion. It should be
@@ -201,14 +281,32 @@ void TypingCommand::insertText(Document& document,
const String& text,
const VisibleSelection& selectionForInsertion,
Options options,
- TextCompositionType compositionType) {
+ TextCompositionType compositionType,
+ const bool isIncrementalInsertion) {
LocalFrame* frame = document.frame();
DCHECK(frame);
VisibleSelection currentSelection = frame->selection().selection();
- String newText = dispatchBeforeTextInsertedEvent(
- text, selectionForInsertion, compositionType == TextCompositionUpdate);
+ String newText = text;
+ if (compositionType != TextCompositionUpdate)
+ newText = dispatchBeforeTextInsertedEvent(text, selectionForInsertion);
+
+ if (compositionType == TextCompositionConfirm) {
+ if (dispatchTextInputEvent(frame, newText) !=
+ DispatchEventResult::NotCanceled)
+ return;
+ }
+
+ // Do nothing if no need to delete and insert.
+ if (selectionForInsertion.isCaret() && newText.isEmpty())
+ return;
+
+ // TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets
+ // needs to be audited. see http://crbug.com/590369 for more details.
+ document.updateStyleAndLayoutIgnorePendingStylesheets();
+
+ const PlainTextRange selectionOffsets = getSelectionOffsets(frame);
// Set the starting and ending selection appropriately if we are using a
// selection that is different from the current selection. In the future, we
@@ -227,9 +325,21 @@ void TypingCommand::insertText(Document& document,
lastTypingCommand->setShouldPreventSpellChecking(options &
PreventSpellChecking);
EditingState editingState;
+ lastTypingCommand->m_isIncrementalInsertion = isIncrementalInsertion;
lastTypingCommand->insertText(newText, options & SelectInsertedText,
&editingState);
- // Nothing to do even if the command was aborted.
+
+ if (editingState.isAborted())
+ return;
+
+ if (isIncrementalInsertion) {
+ const size_t newEnd = selectionOffsets.start() + newText.length();
+ const size_t newStart = (compositionType == TextCompositionUpdate)
+ ? selectionOffsets.start()
+ : newEnd;
+ adjustSelectionAfterIncrementalInsertion(lastTypingCommand, frame,
+ newStart, newEnd);
+ }
return;
}
@@ -240,10 +350,24 @@ void TypingCommand::insertText(Document& document,
command->setStartingSelection(selectionForInsertion);
command->setEndingVisibleSelection(selectionForInsertion);
}
- command->apply();
+ command->m_isIncrementalInsertion = isIncrementalInsertion;
+ const bool aborted = !(command->apply());
+
if (changeSelection) {
command->setEndingVisibleSelection(currentSelection);
frame->selection().setSelection(currentSelection);
+ return;
+ }
+
+ if (aborted)
+ return;
+
+ if (isIncrementalInsertion) {
+ const size_t newEnd = selectionOffsets.start() + newText.length();
+ const size_t newStart = (compositionType == TextCompositionUpdate)
+ ? selectionOffsets.start()
+ : newEnd;
+ adjustSelectionAfterIncrementalInsertion(command, frame, newStart, newEnd);
}
}
@@ -419,35 +543,37 @@ void TypingCommand::insertText(const String& text,
return;
}
- if (text.length() > offset)
+ if (text.length() > offset) {
insertTextRunWithoutNewlines(text.substring(offset, text.length() - offset),
selectInsertedText, editingState);
+ }
}
void TypingCommand::insertTextRunWithoutNewlines(const String& text,
bool selectInsertedText,
EditingState* editingState) {
- InsertTextCommand* command = InsertTextCommand::create(
- document(), text, selectInsertedText,
- m_compositionType == TextCompositionNone
- ? InsertTextCommand::RebalanceLeadingAndTrailingWhitespaces
- : InsertTextCommand::RebalanceAllWhitespaces);
+ CompositeEditCommand* command;
+ if (isIncrementalInsertion()) {
+ command = InsertIncrementalTextCommand::create(
+ document(), text, selectInsertedText,
+ m_compositionType == TextCompositionNone
+ ? InsertIncrementalTextCommand::
+ RebalanceLeadingAndTrailingWhitespaces
+ : InsertIncrementalTextCommand::RebalanceAllWhitespaces);
+ } else {
+ command = InsertTextCommand::create(
+ document(), text, selectInsertedText,
+ m_compositionType == TextCompositionNone
+ ? InsertTextCommand::RebalanceLeadingAndTrailingWhitespaces
+ : InsertTextCommand::RebalanceAllWhitespaces);
+ }
applyCommandToComposite(command, endingSelection(), editingState);
if (editingState->isAborted())
return;
- typingAddedToOpenCommand(InsertText);
-}
-
-static bool canAppendNewLineFeedToSelection(const VisibleSelection& selection) {
- Element* element = selection.rootEditableElement();
- if (!element)
- return false;
- BeforeTextInsertedEvent* event =
- BeforeTextInsertedEvent::create(String("\n"));
- element->dispatchEvent(event);
- return event->text().length();
+ m_textToInsert = text;
+ typingAddedToOpenCommand(InsertText);
}
void TypingCommand::insertLineBreak(EditingState* editingState) {
« no previous file with comments | « third_party/WebKit/Source/core/editing/commands/TypingCommand.h ('k') | third_party/WebKit/Source/core/events/TextEvent.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698