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

Side by Side Diff: third_party/WebKit/Source/core/editing/InputMethodController.cpp

Issue 2617443002: Implement ThreadedInputConnection.deleteSurroundingTextInCodePoints() (Closed)
Patch Set: Fixed 2 tests 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 unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2006, 2007, 2008, 2011 Apple Inc. All rights reserved. 2 * Copyright (C) 2006, 2007, 2008, 2011 Apple Inc. All rights reserved.
3 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) 3 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
4 * 4 *
5 * Redistribution and use in source and binary forms, with or without 5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions 6 * modification, are permitted provided that the following conditions
7 * are met: 7 * are met:
8 * 1. Redistributions of source code must retain the above copyright 8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer. 9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright 10 * 2. Redistributions in binary form must reproduce the above copyright
(...skipping 17 matching lines...) Expand all
28 28
29 #include "core/InputModeNames.h" 29 #include "core/InputModeNames.h"
30 #include "core/InputTypeNames.h" 30 #include "core/InputTypeNames.h"
31 #include "core/dom/Document.h" 31 #include "core/dom/Document.h"
32 #include "core/dom/Element.h" 32 #include "core/dom/Element.h"
33 #include "core/dom/Text.h" 33 #include "core/dom/Text.h"
34 #include "core/editing/EditingUtilities.h" 34 #include "core/editing/EditingUtilities.h"
35 #include "core/editing/Editor.h" 35 #include "core/editing/Editor.h"
36 #include "core/editing/commands/TypingCommand.h" 36 #include "core/editing/commands/TypingCommand.h"
37 #include "core/editing/markers/DocumentMarkerController.h" 37 #include "core/editing/markers/DocumentMarkerController.h"
38 #include "core/editing/state_machines/BackwardCodePointStateMachine.h"
39 #include "core/editing/state_machines/ForwardCodePointStateMachine.h"
38 #include "core/events/CompositionEvent.h" 40 #include "core/events/CompositionEvent.h"
39 #include "core/frame/LocalFrame.h" 41 #include "core/frame/LocalFrame.h"
40 #include "core/html/HTMLInputElement.h" 42 #include "core/html/HTMLInputElement.h"
41 #include "core/html/HTMLTextAreaElement.h" 43 #include "core/html/HTMLTextAreaElement.h"
42 #include "core/input/EventHandler.h" 44 #include "core/input/EventHandler.h"
43 #include "core/layout/LayoutObject.h" 45 #include "core/layout/LayoutObject.h"
44 #include "core/layout/LayoutTheme.h" 46 #include "core/layout/LayoutTheme.h"
45 #include "core/page/ChromeClient.h" 47 #include "core/page/ChromeClient.h"
46 48
47 namespace blink { 49 namespace blink {
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after
178 } 180 }
179 181
180 if (!queryAttribute) 182 if (!queryAttribute)
181 return AtomicString(); 183 return AtomicString();
182 184
183 // TODO(dtapuska): We may wish to restrict this to a yet to be proposed 185 // TODO(dtapuska): We may wish to restrict this to a yet to be proposed
184 // <contenteditable> or <richtext> element Mozilla discussed at TPAC 2016. 186 // <contenteditable> or <richtext> element Mozilla discussed at TPAC 2016.
185 return element->fastGetAttribute(HTMLNames::inputmodeAttr).lower(); 187 return element->fastGetAttribute(HTMLNames::inputmodeAttr).lower();
186 } 188 }
187 189
190 constexpr int invalidDeletionLength = -1;
191 constexpr bool isInvalidDeletionLength(const int length) {
192 return length == invalidDeletionLength;
193 }
194
195 int calculateBeforeDeletionLengthsInCodePoints(
196 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.
197 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.
198 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.
199 BackwardCodePointStateMachine backwardMachine;
200 int counter = beforeLengthInCodePoints;
201 int deletionStart = selectionStart;
202 while (counter > 0 && deletionStart > 0) {
203 const TextSegmentationMachineState state =
204 backwardMachine.feedPrecedingCodeUnit(uText[deletionStart - 1]);
205 // According to Android's InputConnection spec, we should do nothing if
206 // |text| has invalid surrogate pair in the deletion range.
207 if (state == TextSegmentationMachineState::Invalid)
208 return invalidDeletionLength;
209
210 if (backwardMachine.atCodePointBoundary())
211 --counter;
212 --deletionStart;
213 }
214 if (!backwardMachine.atCodePointBoundary())
215 return invalidDeletionLength;
216
217 const int offset = backwardMachine.getBoundaryOffset();
218 DCHECK_EQ(-offset, selectionStart - deletionStart);
219 return -offset;
220 }
221
222 int calculateAfterDeletionLengthsInCodePoints(const UChar* uText,
223 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.
224 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.
225 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.
226 ForwardCodePointStateMachine forwardMachine;
227 int counter = afterLengthInCodePoints;
228 int deletionEnd = selectionEnd;
229 while (counter > 0 && deletionEnd < length) {
230 const TextSegmentationMachineState state =
231 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.
232 // According to Android's InputConnection spec, we should do nothing if
233 // |text| has invalid surrogate pair in the deletion range.
234 if (state == TextSegmentationMachineState::Invalid)
235 return invalidDeletionLength;
236
237 if (forwardMachine.atCodePointBoundary())
238 --counter;
239 ++deletionEnd;
240 }
241 if (!forwardMachine.atCodePointBoundary())
242 return invalidDeletionLength;
243
244 const int offset = forwardMachine.getBoundaryOffset();
245 DCHECK_EQ(offset, deletionEnd - selectionEnd);
246 return offset;
247 }
248
188 } // anonymous namespace 249 } // anonymous namespace
189 250
190 InputMethodController* InputMethodController::create(LocalFrame& frame) { 251 InputMethodController* InputMethodController::create(LocalFrame& frame) {
191 return new InputMethodController(frame); 252 return new InputMethodController(frame);
192 } 253 }
193 254
194 InputMethodController::InputMethodController(LocalFrame& frame) 255 InputMethodController::InputMethodController(LocalFrame& frame)
195 : m_frame(&frame), m_hasComposition(false) {} 256 : m_frame(&frame), m_hasComposition(false) {}
196 257
197 InputMethodController::~InputMethodController() = default; 258 InputMethodController::~InputMethodController() = default;
(...skipping 662 matching lines...) Expand 10 before | Expand all | Expand 10 after
860 const size_t diff = computeDistanceToRightGraphemeBoundary(position); 921 const size_t diff = computeDistanceToRightGraphemeBoundary(position);
861 const int adjustedEnd = end + static_cast<int>(diff); 922 const int adjustedEnd = end + static_cast<int>(diff);
862 if (!setSelectionOffsets(PlainTextRange(selectionEnd, adjustedEnd))) 923 if (!setSelectionOffsets(PlainTextRange(selectionEnd, adjustedEnd)))
863 return; 924 return;
864 TypingCommand::deleteSelection(document()); 925 TypingCommand::deleteSelection(document());
865 } 926 }
866 927
867 setSelectionOffsets(PlainTextRange(selectionStart, selectionEnd)); 928 setSelectionOffsets(PlainTextRange(selectionStart, selectionEnd));
868 } 929 }
869 930
931 void InputMethodController::deleteSurroundingTextInCodePoints(int before,
932 int after) {
933 DCHECK_GE(before, 0);
934 DCHECK_GE(after, 0);
935 if (!editor().canEdit())
936 return;
937 const PlainTextRange selectionOffsets(getSelectionOffsets());
938 if (selectionOffsets.isNull())
939 return;
940 Element* const rootEditableElement =
941 frame().selection().rootEditableElement();
942 if (!rootEditableElement)
943 return;
944
945 const TextIteratorBehavior& behavior =
946 TextIteratorBehavior::Builder()
947 .setEmitsObjectReplacementCharacter(true)
948 .build();
949 const String& text = plainText(
950 EphemeralRange::rangeOfContents(*rootEditableElement), behavior);
951
952 // UTF-8 is only used to encode Latin-1 characters, so the deletion lengths
953 // are trivial.
954 if (text.is8Bit())
955 return deleteSurroundingText(before, after);
956
957 const int selectionStart = static_cast<int>(selectionOffsets.start());
958 const int selectionEnd = static_cast<int>(selectionOffsets.end());
959
960 const UChar* uText = text.characters16();
961 const int beforeLength =
962 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
963 if (isInvalidDeletionLength(beforeLength))
964 return;
965 const int afterLength = calculateAfterDeletionLengthsInCodePoints(
966 uText, after, selectionEnd, text.length());
967 if (isInvalidDeletionLength(afterLength))
968 return;
969
970 return deleteSurroundingText(beforeLength, afterLength);
971 }
972
870 WebTextInputInfo InputMethodController::textInputInfo() const { 973 WebTextInputInfo InputMethodController::textInputInfo() const {
871 WebTextInputInfo info; 974 WebTextInputInfo info;
872 if (!isAvailable()) 975 if (!isAvailable())
873 return info; 976 return info;
874 977
875 if (!frame().selection().isAvailable()) { 978 if (!frame().selection().isAvailable()) {
876 // plugins/mouse-capture-inside-shadow.html reaches here. 979 // plugins/mouse-capture-inside-shadow.html reaches here.
877 return info; 980 return info;
878 } 981 }
879 Element* element = frame().selection().rootEditableElement(); 982 Element* element = frame().selection().rootEditableElement();
(...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after
1082 finishComposingText(DoNotKeepSelection); 1185 finishComposingText(DoNotKeepSelection);
1083 } 1186 }
1084 1187
1085 DEFINE_TRACE(InputMethodController) { 1188 DEFINE_TRACE(InputMethodController) {
1086 visitor->trace(m_frame); 1189 visitor->trace(m_frame);
1087 visitor->trace(m_compositionRange); 1190 visitor->trace(m_compositionRange);
1088 SynchronousMutationObserver::trace(visitor); 1191 SynchronousMutationObserver::trace(visitor);
1089 } 1192 }
1090 1193
1091 } // namespace blink 1194 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698