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 |