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 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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |