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

Unified Diff: third_party/WebKit/Source/core/editing/InputMethodController.cpp

Issue 2617443002: Implement ThreadedInputConnection.deleteSurroundingTextInCodePoints() (Closed)
Patch Set: Add some DCHECK Created 3 years, 10 months 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/InputMethodController.cpp
diff --git a/third_party/WebKit/Source/core/editing/InputMethodController.cpp b/third_party/WebKit/Source/core/editing/InputMethodController.cpp
index e84573affa53ce61f588a2c5d20400ef4ee9b500..8cf8822df275a96f22d5469bd64794b79e63cc5b 100644
--- a/third_party/WebKit/Source/core/editing/InputMethodController.cpp
+++ b/third_party/WebKit/Source/core/editing/InputMethodController.cpp
@@ -35,6 +35,8 @@
#include "core/editing/Editor.h"
#include "core/editing/commands/TypingCommand.h"
#include "core/editing/markers/DocumentMarkerController.h"
+#include "core/editing/state_machines/BackwardCodePointStateMachine.h"
+#include "core/editing/state_machines/ForwardCodePointStateMachine.h"
#include "core/events/CompositionEvent.h"
#include "core/frame/LocalFrame.h"
#include "core/html/HTMLInputElement.h"
@@ -185,6 +187,75 @@ AtomicString getInputModeAttribute(Element* element) {
return element->fastGetAttribute(HTMLNames::inputmodeAttr).lower();
}
+constexpr int invalidDeletionLength = -1;
+constexpr bool isInvalidDeletionLength(const int length) {
+ return length == invalidDeletionLength;
+}
+
+int calculateBeforeDeletionLengthsInCodePoints(
+ const String& text,
+ const int beforeLengthInCodePoints,
+ const int selectionStart) {
+ DCHECK_GE(beforeLengthInCodePoints, 0);
+ DCHECK_GE(selectionStart, 0);
+ DCHECK_LE(selectionStart, static_cast<int>(text.length()));
+
+ const UChar* uText = text.characters16();
+ BackwardCodePointStateMachine backwardMachine;
+ int counter = beforeLengthInCodePoints;
+ int deletionStart = selectionStart;
+ while (counter > 0 && deletionStart > 0) {
+ const TextSegmentationMachineState state =
+ backwardMachine.feedPrecedingCodeUnit(uText[deletionStart - 1]);
+ // According to Android's InputConnection spec, we should do nothing if
+ // |text| has invalid surrogate pair in the deletion range.
+ if (state == TextSegmentationMachineState::Invalid)
+ return invalidDeletionLength;
+
+ if (backwardMachine.atCodePointBoundary())
+ --counter;
+ --deletionStart;
+ }
+ if (!backwardMachine.atCodePointBoundary())
+ return invalidDeletionLength;
+
+ const int offset = backwardMachine.getBoundaryOffset();
+ DCHECK_EQ(-offset, selectionStart - deletionStart);
+ return -offset;
+}
+
+int calculateAfterDeletionLengthsInCodePoints(const String& text,
+ const int afterLengthInCodePoints,
+ const int selectionEnd) {
+ DCHECK_GE(afterLengthInCodePoints, 0);
+ DCHECK_GE(selectionEnd, 0);
+ const int length = text.length();
+ DCHECK_LE(selectionEnd, length);
+
+ const UChar* uText = text.characters16();
+ ForwardCodePointStateMachine forwardMachine;
+ int counter = afterLengthInCodePoints;
+ int deletionEnd = selectionEnd;
+ while (counter > 0 && deletionEnd < length) {
+ const TextSegmentationMachineState state =
+ forwardMachine.feedFollowingCodeUnit(uText[deletionEnd]);
+ // According to Android's InputConnection spec, we should do nothing if
+ // |text| has invalid surrogate pair in the deletion range.
+ if (state == TextSegmentationMachineState::Invalid)
+ return invalidDeletionLength;
+
+ if (forwardMachine.atCodePointBoundary())
+ --counter;
+ ++deletionEnd;
+ }
+ if (!forwardMachine.atCodePointBoundary())
+ return invalidDeletionLength;
+
+ const int offset = forwardMachine.getBoundaryOffset();
+ DCHECK_EQ(offset, deletionEnd - selectionEnd);
+ return offset;
+}
+
} // anonymous namespace
InputMethodController* InputMethodController::create(LocalFrame& frame) {
@@ -867,6 +938,47 @@ void InputMethodController::deleteSurroundingText(int before, int after) {
setSelectionOffsets(PlainTextRange(selectionStart, selectionEnd));
}
+void InputMethodController::deleteSurroundingTextInCodePoints(int before,
+ int after) {
+ DCHECK_GE(before, 0);
+ DCHECK_GE(after, 0);
dcheng 2017/02/25 07:37:04 After int -> size_t -> int in the browser side, it
yabinh 2017/02/27 02:04:33 Done. Replaced size_t with int.
+ if (!editor().canEdit())
+ return;
+ const PlainTextRange selectionOffsets(getSelectionOffsets());
+ if (selectionOffsets.isNull())
+ return;
+ Element* const rootEditableElement =
+ frame().selection().rootEditableElement();
+ if (!rootEditableElement)
+ return;
+
+ const TextIteratorBehavior& behavior =
+ TextIteratorBehavior::Builder()
+ .setEmitsObjectReplacementCharacter(true)
+ .build();
+ const String& text = plainText(
+ EphemeralRange::rangeOfContents(*rootEditableElement), behavior);
+
+ // UTF-8 is only used to encode Latin-1 characters, so the deletion lengths
dcheng 2017/02/25 07:37:03 8-bit characters, not UTF-8
yabinh 2017/02/27 02:04:33 Done.
+ // are trivial.
+ if (text.is8Bit())
+ return deleteSurroundingText(before, after);
+
+ const int selectionStart = static_cast<int>(selectionOffsets.start());
+ const int selectionEnd = static_cast<int>(selectionOffsets.end());
+
+ const int beforeLength =
+ calculateBeforeDeletionLengthsInCodePoints(text, before, selectionStart);
+ if (isInvalidDeletionLength(beforeLength))
+ return;
+ const int afterLength =
+ calculateAfterDeletionLengthsInCodePoints(text, after, selectionEnd);
+ if (isInvalidDeletionLength(afterLength))
+ return;
+
+ return deleteSurroundingText(beforeLength, afterLength);
+}
+
WebTextInputInfo InputMethodController::textInputInfo() const {
WebTextInputInfo info;
if (!isAvailable())

Powered by Google App Engine
This is Rietveld 408576698