Chromium Code Reviews| 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()) |