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..7b1e7f917c1d4b4669e8680954ff0e53368a364b 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,65 @@ 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 UChar* uText, |
yosin_UTC9
2017/02/20 05:53:59
Do we know length of |uText|?
We should make sure
yabinh
2017/02/20 07:46:45
Done.
|
+ const int beforeLengthInCodePoints, |
yosin_UTC9
2017/02/20 05:53:59
Let's add DCHECK_GE(beforeLengthInCodePoints, 0)
yabinh
2017/02/20 07:46:45
Done.
|
+ const int selectionStart) { |
yosin_UTC9
2017/02/20 05:53:59
Let's add DCHECK_GE(selectionStart, 0)
yabinh
2017/02/20 07:46:45
Done.
|
+ 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 UChar* uText, |
+ const int afterLengthInCodePoints, |
yosin_UTC9
2017/02/20 05:53:59
Let's add DCHECK_GE( afterLengthInCodePoints, 0)
yabinh
2017/02/20 07:46:45
Done.
|
+ const int selectionEnd, |
yosin_UTC9
2017/02/20 05:53:59
Let's add DCHECK_GE(selectionEnd, 0)
yabinh
2017/02/20 07:46:45
Done.
|
+ const int length) { |
yosin_UTC9
2017/02/20 05:53:59
Let's add DCHECK_GE(length, 0) or DCHECK_GE(length
yabinh
2017/02/20 07:46:45
Done.
|
+ ForwardCodePointStateMachine forwardMachine; |
+ int counter = afterLengthInCodePoints; |
+ int deletionEnd = selectionEnd; |
+ while (counter > 0 && deletionEnd < length) { |
+ const TextSegmentationMachineState state = |
+ forwardMachine.feedFollowingCodeUnit(uText[deletionEnd]); |
yosin_UTC9
2017/02/20 05:53:59
Do we know length of |uText|?
We should make sure
yabinh
2017/02/20 07:46:45
Done.
|
+ // 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 +928,48 @@ 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); |
+ 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 |
+ // 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 UChar* uText = text.characters16(); |
+ const int beforeLength = |
+ calculateBeforeDeletionLengthsInCodePoints(uText, before, selectionStart); |
yosin_UTC9
2017/02/20 05:53:59
It seems it is better to pass |text| for bounds ch
yabinh
2017/02/20 06:28:23
The length of |uText| == the length of |text|.
For
|
+ if (isInvalidDeletionLength(beforeLength)) |
+ return; |
+ const int afterLength = calculateAfterDeletionLengthsInCodePoints( |
+ uText, after, selectionEnd, text.length()); |
+ if (isInvalidDeletionLength(afterLength)) |
+ return; |
+ |
+ return deleteSurroundingText(beforeLength, afterLength); |
+} |
+ |
WebTextInputInfo InputMethodController::textInputInfo() const { |
WebTextInputInfo info; |
if (!isAvailable()) |