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 699 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
897 const size_t diff = computeDistanceToRightGraphemeBoundary(position); | 968 const size_t diff = computeDistanceToRightGraphemeBoundary(position); |
898 const int adjustedEnd = end + static_cast<int>(diff); | 969 const int adjustedEnd = end + static_cast<int>(diff); |
899 if (!setSelectionOffsets(PlainTextRange(selectionEnd, adjustedEnd))) | 970 if (!setSelectionOffsets(PlainTextRange(selectionEnd, adjustedEnd))) |
900 return; | 971 return; |
901 TypingCommand::deleteSelection(document()); | 972 TypingCommand::deleteSelection(document()); |
902 } | 973 } |
903 | 974 |
904 setSelectionOffsets(PlainTextRange(selectionStart, selectionEnd)); | 975 setSelectionOffsets(PlainTextRange(selectionStart, selectionEnd)); |
905 } | 976 } |
906 | 977 |
| 978 void InputMethodController::deleteSurroundingTextInCodePoints(int before, |
| 979 int after) { |
| 980 DCHECK_GE(before, 0); |
| 981 DCHECK_GE(after, 0); |
| 982 if (!editor().canEdit()) |
| 983 return; |
| 984 const PlainTextRange selectionOffsets(getSelectionOffsets()); |
| 985 if (selectionOffsets.isNull()) |
| 986 return; |
| 987 Element* const rootEditableElement = |
| 988 frame().selection().rootEditableElementOrDocumentElement(); |
| 989 if (!rootEditableElement) |
| 990 return; |
| 991 |
| 992 const TextIteratorBehavior& behavior = |
| 993 TextIteratorBehavior::Builder() |
| 994 .setEmitsObjectReplacementCharacter(true) |
| 995 .build(); |
| 996 const String& text = plainText( |
| 997 EphemeralRange::rangeOfContents(*rootEditableElement), behavior); |
| 998 |
| 999 // 8-bit characters are Latin-1 characters, so the deletion lengths are |
| 1000 // trivial. |
| 1001 if (text.is8Bit()) |
| 1002 return deleteSurroundingText(before, after); |
| 1003 |
| 1004 const int selectionStart = static_cast<int>(selectionOffsets.start()); |
| 1005 const int selectionEnd = static_cast<int>(selectionOffsets.end()); |
| 1006 |
| 1007 const int beforeLength = |
| 1008 calculateBeforeDeletionLengthsInCodePoints(text, before, selectionStart); |
| 1009 if (isInvalidDeletionLength(beforeLength)) |
| 1010 return; |
| 1011 const int afterLength = |
| 1012 calculateAfterDeletionLengthsInCodePoints(text, after, selectionEnd); |
| 1013 if (isInvalidDeletionLength(afterLength)) |
| 1014 return; |
| 1015 |
| 1016 return deleteSurroundingText(beforeLength, afterLength); |
| 1017 } |
| 1018 |
907 WebTextInputInfo InputMethodController::textInputInfo() const { | 1019 WebTextInputInfo InputMethodController::textInputInfo() const { |
908 WebTextInputInfo info; | 1020 WebTextInputInfo info; |
909 if (!isAvailable()) | 1021 if (!isAvailable()) |
910 return info; | 1022 return info; |
911 | 1023 |
912 if (!frame().selection().isAvailable()) { | 1024 if (!frame().selection().isAvailable()) { |
913 // plugins/mouse-capture-inside-shadow.html reaches here. | 1025 // plugins/mouse-capture-inside-shadow.html reaches here. |
914 return info; | 1026 return info; |
915 } | 1027 } |
916 Element* element = frame() | 1028 Element* element = frame() |
(...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1125 finishComposingText(KeepSelection); | 1237 finishComposingText(KeepSelection); |
1126 } | 1238 } |
1127 | 1239 |
1128 DEFINE_TRACE(InputMethodController) { | 1240 DEFINE_TRACE(InputMethodController) { |
1129 visitor->trace(m_frame); | 1241 visitor->trace(m_frame); |
1130 visitor->trace(m_compositionRange); | 1242 visitor->trace(m_compositionRange); |
1131 SynchronousMutationObserver::trace(visitor); | 1243 SynchronousMutationObserver::trace(visitor); |
1132 } | 1244 } |
1133 | 1245 |
1134 } // namespace blink | 1246 } // namespace blink |
OLD | NEW |