Chromium Code Reviews| 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 |