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 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 177 } | 177 } |
| 178 | 178 |
| 179 if (!queryAttribute) | 179 if (!queryAttribute) |
| 180 return AtomicString(); | 180 return AtomicString(); |
| 181 | 181 |
| 182 // TODO(dtapuska): We may wish to restrict this to a yet to be proposed | 182 // TODO(dtapuska): We may wish to restrict this to a yet to be proposed |
| 183 // <contenteditable> or <richtext> element Mozilla discussed at TPAC 2016. | 183 // <contenteditable> or <richtext> element Mozilla discussed at TPAC 2016. |
| 184 return element->fastGetAttribute(HTMLNames::inputmodeAttr).lower(); | 184 return element->fastGetAttribute(HTMLNames::inputmodeAttr).lower(); |
| 185 } | 185 } |
| 186 | 186 |
| 187 bool hasInvalidSurrogatePair(const UChar* text, | |
| 188 const int start, | |
| 189 const int end) { | |
| 190 for (int i = start; i < end; i++) { | |
| 191 if (U_IS_SURROGATE(text[i])) { | |
| 192 const bool isValidSurrogatePair = | |
| 193 U16_IS_LEAD(text[i]) && i + 1 < end && U16_IS_TRAIL(text[i + 1]); | |
| 194 if (!isValidSurrogatePair) | |
| 195 return true; | |
| 196 i++; | |
| 197 } | |
| 198 } | |
| 199 return false; | |
| 200 } | |
| 201 | |
| 202 bool hasInvalidSurrogatePair(const LChar* text, | |
|
Changwan Ryu
2017/01/11 06:44:33
This is somewhat weird. UTF-8 does not have surrog
yabinh
2017/01/24 11:39:56
Done. This function has been removed.
We can simp
| |
| 203 const int start, | |
| 204 const int end) { | |
| 205 for (int i = start; i < end; i++) { | |
| 206 if (!U8_IS_SINGLE(text[i])) { | |
| 207 const bool isValidSurrogatePair = | |
| 208 U8_IS_LEAD(text[i]) && i + 1 < end && U8_IS_TRAIL(text[i + 1]); | |
| 209 if (!isValidSurrogatePair) | |
| 210 return true; | |
| 211 i++; | |
| 212 } | |
| 213 } | |
| 214 return false; | |
| 215 } | |
| 216 | |
| 217 std::pair<int, int> invalidDeletionLength() { | |
| 218 return std::make_pair(-1, -1); | |
| 219 } | |
| 220 | |
| 221 bool isInvalidDeletionLength(const std::pair<int, int>& lengthPair) { | |
| 222 return lengthPair.first == -1 && lengthPair.second == -1; | |
| 223 } | |
| 224 | |
| 225 std::pair<int, int> convertDeletionLengthForDeleteSurroundingTextInCodePoints( | |
| 226 const String& text, | |
| 227 const int beforeLengthInCodePoints, | |
| 228 const int afterLengthInCodePoints, | |
| 229 const int selectionStart, | |
| 230 const int selectionEnd) { | |
| 231 int deletionStart = selectionStart; | |
|
Changwan Ryu
2017/01/11 06:44:33
Are selectionStart / selectionEnd in code points?
yabinh
2017/01/24 11:39:56
No, it's in Java length.
But we don't need convert
| |
| 232 int deletionEnd = selectionEnd; | |
| 233 const int length = static_cast<int>(text.length()); | |
| 234 | |
| 235 if (text.is8Bit()) { | |
| 236 const LChar* LText = text.characters8(); | |
| 237 U8_BACK_N(LText, 0, deletionStart, beforeLengthInCodePoints); | |
| 238 | |
| 239 // Return an invalid value if there are one or more invalid surrogate pairs | |
| 240 // in the requested range | |
| 241 if (hasInvalidSurrogatePair(LText, deletionStart, selectionStart)) | |
| 242 return invalidDeletionLength(); | |
| 243 | |
| 244 U8_FWD_N(LText, deletionEnd, length, afterLengthInCodePoints); | |
| 245 if (hasInvalidSurrogatePair(LText, selectionEnd, deletionEnd)) | |
| 246 return invalidDeletionLength(); | |
| 247 } else { | |
| 248 const UChar* UText = text.characters16(); | |
| 249 | |
| 250 U16_BACK_N(UText, 0, deletionStart, beforeLengthInCodePoints); | |
| 251 if (hasInvalidSurrogatePair(UText, deletionStart, selectionStart)) | |
| 252 return invalidDeletionLength(); | |
|
Changwan Ryu
2017/01/11 06:44:33
I think it should be ok to delete the range even w
yabinh
2017/01/24 11:39:56
This is to follow the specification:
'''
This met
| |
| 253 | |
| 254 U16_FWD_N(UText, deletionEnd, length, afterLengthInCodePoints); | |
| 255 if (hasInvalidSurrogatePair(UText, selectionEnd, deletionEnd)) | |
| 256 return invalidDeletionLength(); | |
| 257 } | |
| 258 | |
| 259 const int beforeLengthInJavaChars = selectionStart - deletionStart; | |
|
Changwan Ryu
2017/01/11 02:00:27
WebKit should not know about JavaChars. Also it do
yabinh
2017/01/24 11:39:56
Done.
| |
| 260 const int afterLengthInJavaChars = deletionEnd - selectionEnd; | |
| 261 return std::make_pair(beforeLengthInJavaChars, afterLengthInJavaChars); | |
| 262 } | |
| 263 | |
| 187 } // anonymous namespace | 264 } // anonymous namespace |
| 188 | 265 |
| 189 InputMethodController* InputMethodController::create(LocalFrame& frame) { | 266 InputMethodController* InputMethodController::create(LocalFrame& frame) { |
| 190 return new InputMethodController(frame); | 267 return new InputMethodController(frame); |
| 191 } | 268 } |
| 192 | 269 |
| 193 InputMethodController::InputMethodController(LocalFrame& frame) | 270 InputMethodController::InputMethodController(LocalFrame& frame) |
| 194 : m_frame(&frame), m_hasComposition(false) {} | 271 : m_frame(&frame), m_hasComposition(false) {} |
| 195 | 272 |
| 196 InputMethodController::~InputMethodController() = default; | 273 InputMethodController::~InputMethodController() = default; |
| (...skipping 645 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 842 const int adjustedEnd = end + static_cast<int>(diff); | 919 const int adjustedEnd = end + static_cast<int>(diff); |
| 843 if (!setSelectionOffsets(PlainTextRange(selectionEnd, adjustedEnd))) | 920 if (!setSelectionOffsets(PlainTextRange(selectionEnd, adjustedEnd))) |
| 844 return; | 921 return; |
| 845 TypingCommand::deleteSelection(document(), | 922 TypingCommand::deleteSelection(document(), |
| 846 EditCommandSource::kMenuOrKeyBinding); | 923 EditCommandSource::kMenuOrKeyBinding); |
| 847 } | 924 } |
| 848 | 925 |
| 849 setSelectionOffsets(PlainTextRange(selectionStart, selectionEnd)); | 926 setSelectionOffsets(PlainTextRange(selectionStart, selectionEnd)); |
| 850 } | 927 } |
| 851 | 928 |
| 929 void InputMethodController::deleteSurroundingTextInCodePoints(int before, | |
| 930 int after) { | |
| 931 DCHECK_GE(before, 0); | |
| 932 DCHECK_GE(after, 0); | |
| 933 if (!editor().canEdit()) | |
| 934 return; | |
| 935 const PlainTextRange selectionOffsets(getSelectionOffsets()); | |
| 936 if (selectionOffsets.isNull()) | |
| 937 return; | |
| 938 Element* const rootEditableElement = | |
| 939 frame().selection().rootEditableElement(); | |
| 940 if (!rootEditableElement) | |
| 941 return; | |
| 942 | |
| 943 const int selectionStart = static_cast<int>(selectionOffsets.start()); | |
| 944 const int selectionEnd = static_cast<int>(selectionOffsets.end()); | |
| 945 const String& text = | |
| 946 plainText(EphemeralRange::rangeOfContents(*rootEditableElement), | |
| 947 TextIteratorEmitsObjectReplacementCharacter); | |
| 948 std::pair<int, int> deletionLengthPair = | |
| 949 convertDeletionLengthForDeleteSurroundingTextInCodePoints( | |
| 950 text, before, after, selectionStart, selectionEnd); | |
| 951 if (isInvalidDeletionLength(deletionLengthPair)) | |
| 952 return; | |
| 953 | |
| 954 return deleteSurroundingText(deletionLengthPair.first, | |
| 955 deletionLengthPair.second); | |
| 956 } | |
| 957 | |
| 852 WebTextInputInfo InputMethodController::textInputInfo() const { | 958 WebTextInputInfo InputMethodController::textInputInfo() const { |
| 853 WebTextInputInfo info; | 959 WebTextInputInfo info; |
| 854 if (!isAvailable()) | 960 if (!isAvailable()) |
| 855 return info; | 961 return info; |
| 856 | 962 |
| 857 if (!frame().selection().isAvailable()) { | 963 if (!frame().selection().isAvailable()) { |
| 858 // plugins/mouse-capture-inside-shadow.html reaches here. | 964 // plugins/mouse-capture-inside-shadow.html reaches here. |
| 859 return info; | 965 return info; |
| 860 } | 966 } |
| 861 Element* element = frame().selection().rootEditableElement(); | 967 Element* element = frame().selection().rootEditableElement(); |
| (...skipping 201 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1063 frame().chromeClient().resetInputMethod(); | 1169 frame().chromeClient().resetInputMethod(); |
| 1064 } | 1170 } |
| 1065 | 1171 |
| 1066 DEFINE_TRACE(InputMethodController) { | 1172 DEFINE_TRACE(InputMethodController) { |
| 1067 visitor->trace(m_frame); | 1173 visitor->trace(m_frame); |
| 1068 visitor->trace(m_compositionRange); | 1174 visitor->trace(m_compositionRange); |
| 1069 SynchronousMutationObserver::trace(visitor); | 1175 SynchronousMutationObserver::trace(visitor); |
| 1070 } | 1176 } |
| 1071 | 1177 |
| 1072 } // namespace blink | 1178 } // namespace blink |
| OLD | NEW |