| 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 |