OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 String& text, | |
197 const int beforeLengthInCodePoints, | |
198 const int selectionStart) { | |
199 DCHECK_GE(beforeLengthInCodePoints, 0); | |
200 DCHECK_GE(selectionStart, 0); | |
201 DCHECK_LE(selectionStart, static_cast<int>(text.length())); | |
202 | |
203 const UChar* uText = text.characters16(); | |
204 BackwardCodePointStateMachine backwardMachine; | |
205 int counter = beforeLengthInCodePoints; | |
206 int deletionStart = selectionStart; | |
207 while (counter > 0 && deletionStart > 0) { | |
208 const TextSegmentationMachineState state = | |
209 backwardMachine.feedPrecedingCodeUnit(uText[deletionStart - 1]); | |
210 // According to Android's InputConnection spec, we should do nothing if | |
211 // |text| has invalid surrogate pair in the deletion range. | |
212 if (state == TextSegmentationMachineState::Invalid) | |
213 return invalidDeletionLength; | |
214 | |
215 if (backwardMachine.atCodePointBoundary()) | |
216 --counter; | |
217 --deletionStart; | |
218 } | |
219 if (!backwardMachine.atCodePointBoundary()) | |
220 return invalidDeletionLength; | |
221 | |
222 const int offset = backwardMachine.getBoundaryOffset(); | |
223 DCHECK_EQ(-offset, selectionStart - deletionStart); | |
224 return -offset; | |
225 } | |
226 | |
227 int calculateAfterDeletionLengthsInCodePoints(const String& text, | |
228 const int afterLengthInCodePoints, | |
229 const int selectionEnd) { | |
230 DCHECK_GE(afterLengthInCodePoints, 0); | |
231 DCHECK_GE(selectionEnd, 0); | |
232 const int length = text.length(); | |
233 DCHECK_LE(selectionEnd, length); | |
234 | |
235 const UChar* uText = text.characters16(); | |
236 ForwardCodePointStateMachine forwardMachine; | |
237 int counter = afterLengthInCodePoints; | |
238 int deletionEnd = selectionEnd; | |
239 while (counter > 0 && deletionEnd < length) { | |
240 const TextSegmentationMachineState state = | |
241 forwardMachine.feedFollowingCodeUnit(uText[deletionEnd]); | |
242 // According to Android's InputConnection spec, we should do nothing if | |
243 // |text| has invalid surrogate pair in the deletion range. | |
244 if (state == TextSegmentationMachineState::Invalid) | |
245 return invalidDeletionLength; | |
246 | |
247 if (forwardMachine.atCodePointBoundary()) | |
248 --counter; | |
249 ++deletionEnd; | |
250 } | |
251 if (!forwardMachine.atCodePointBoundary()) | |
252 return invalidDeletionLength; | |
253 | |
254 const int offset = forwardMachine.getBoundaryOffset(); | |
255 DCHECK_EQ(offset, deletionEnd - selectionEnd); | |
256 return offset; | |
257 } | |
258 | |
188 } // anonymous namespace | 259 } // anonymous namespace |
189 | 260 |
190 InputMethodController* InputMethodController::create(LocalFrame& frame) { | 261 InputMethodController* InputMethodController::create(LocalFrame& frame) { |
191 return new InputMethodController(frame); | 262 return new InputMethodController(frame); |
192 } | 263 } |
193 | 264 |
194 InputMethodController::InputMethodController(LocalFrame& frame) | 265 InputMethodController::InputMethodController(LocalFrame& frame) |
195 : m_frame(&frame), m_hasComposition(false) {} | 266 : m_frame(&frame), m_hasComposition(false) {} |
196 | 267 |
197 InputMethodController::~InputMethodController() = default; | 268 InputMethodController::~InputMethodController() = default; |
(...skipping 662 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
860 const size_t diff = computeDistanceToRightGraphemeBoundary(position); | 931 const size_t diff = computeDistanceToRightGraphemeBoundary(position); |
861 const int adjustedEnd = end + static_cast<int>(diff); | 932 const int adjustedEnd = end + static_cast<int>(diff); |
862 if (!setSelectionOffsets(PlainTextRange(selectionEnd, adjustedEnd))) | 933 if (!setSelectionOffsets(PlainTextRange(selectionEnd, adjustedEnd))) |
863 return; | 934 return; |
864 TypingCommand::deleteSelection(document()); | 935 TypingCommand::deleteSelection(document()); |
865 } | 936 } |
866 | 937 |
867 setSelectionOffsets(PlainTextRange(selectionStart, selectionEnd)); | 938 setSelectionOffsets(PlainTextRange(selectionStart, selectionEnd)); |
868 } | 939 } |
869 | 940 |
941 void InputMethodController::deleteSurroundingTextInCodePoints(int before, | |
942 int after) { | |
943 DCHECK_GE(before, 0); | |
944 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.
| |
945 if (!editor().canEdit()) | |
946 return; | |
947 const PlainTextRange selectionOffsets(getSelectionOffsets()); | |
948 if (selectionOffsets.isNull()) | |
949 return; | |
950 Element* const rootEditableElement = | |
951 frame().selection().rootEditableElement(); | |
952 if (!rootEditableElement) | |
953 return; | |
954 | |
955 const TextIteratorBehavior& behavior = | |
956 TextIteratorBehavior::Builder() | |
957 .setEmitsObjectReplacementCharacter(true) | |
958 .build(); | |
959 const String& text = plainText( | |
960 EphemeralRange::rangeOfContents(*rootEditableElement), behavior); | |
961 | |
962 // 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.
| |
963 // are trivial. | |
964 if (text.is8Bit()) | |
965 return deleteSurroundingText(before, after); | |
966 | |
967 const int selectionStart = static_cast<int>(selectionOffsets.start()); | |
968 const int selectionEnd = static_cast<int>(selectionOffsets.end()); | |
969 | |
970 const int beforeLength = | |
971 calculateBeforeDeletionLengthsInCodePoints(text, before, selectionStart); | |
972 if (isInvalidDeletionLength(beforeLength)) | |
973 return; | |
974 const int afterLength = | |
975 calculateAfterDeletionLengthsInCodePoints(text, after, selectionEnd); | |
976 if (isInvalidDeletionLength(afterLength)) | |
977 return; | |
978 | |
979 return deleteSurroundingText(beforeLength, afterLength); | |
980 } | |
981 | |
870 WebTextInputInfo InputMethodController::textInputInfo() const { | 982 WebTextInputInfo InputMethodController::textInputInfo() const { |
871 WebTextInputInfo info; | 983 WebTextInputInfo info; |
872 if (!isAvailable()) | 984 if (!isAvailable()) |
873 return info; | 985 return info; |
874 | 986 |
875 if (!frame().selection().isAvailable()) { | 987 if (!frame().selection().isAvailable()) { |
876 // plugins/mouse-capture-inside-shadow.html reaches here. | 988 // plugins/mouse-capture-inside-shadow.html reaches here. |
877 return info; | 989 return info; |
878 } | 990 } |
879 Element* element = frame().selection().rootEditableElement(); | 991 Element* element = frame().selection().rootEditableElement(); |
(...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1082 finishComposingText(DoNotKeepSelection); | 1194 finishComposingText(DoNotKeepSelection); |
1083 } | 1195 } |
1084 | 1196 |
1085 DEFINE_TRACE(InputMethodController) { | 1197 DEFINE_TRACE(InputMethodController) { |
1086 visitor->trace(m_frame); | 1198 visitor->trace(m_frame); |
1087 visitor->trace(m_compositionRange); | 1199 visitor->trace(m_compositionRange); |
1088 SynchronousMutationObserver::trace(visitor); | 1200 SynchronousMutationObserver::trace(visitor); |
1089 } | 1201 } |
1090 | 1202 |
1091 } // namespace blink | 1203 } // namespace blink |
OLD | NEW |