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 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 193 } | 193 } |
| 194 | 194 |
| 195 if (!queryAttribute) | 195 if (!queryAttribute) |
| 196 return AtomicString(); | 196 return AtomicString(); |
| 197 | 197 |
| 198 // TODO(dtapuska): We may wish to restrict this to a yet to be proposed | 198 // TODO(dtapuska): We may wish to restrict this to a yet to be proposed |
| 199 // <contenteditable> or <richtext> element Mozilla discussed at TPAC 2016. | 199 // <contenteditable> or <richtext> element Mozilla discussed at TPAC 2016. |
| 200 return element->fastGetAttribute(HTMLNames::inputmodeAttr).lower(); | 200 return element->fastGetAttribute(HTMLNames::inputmodeAttr).lower(); |
| 201 } | 201 } |
| 202 | 202 |
| 203 bool hasInvalidSurrogatePair(const UChar* text, | |
| 204 const int start, | |
| 205 const int end) { | |
|
yosin_UTC9
2017/02/09 07:19:27
Let's have following DCHECK's
DCHECK_GE(start, 0)
yabinh
2017/02/09 10:37:03
Done.
| |
| 206 for (int i = start; i < end; i++) { | |
|
yosin_UTC9
2017/02/09 07:19:27
nit: s/i++/++i/
[1] allows to use both pre and pos
yabinh
2017/02/09 10:37:03
Done.
| |
| 207 if (U_IS_SURROGATE(text[i])) { | |
| 208 const bool isValidSurrogatePair = | |
| 209 U16_IS_LEAD(text[i]) && i + 1 < end && U16_IS_TRAIL(text[i + 1]); | |
|
yosin_UTC9
2017/02/09 07:19:27
Let's loop over |end - 1| to avoid checking |i| he
yabinh
2017/02/09 10:37:03
We shouldn't do that because it will fail when tex
| |
| 210 if (!isValidSurrogatePair) | |
| 211 return true; | |
| 212 i++; | |
|
yosin_UTC9
2017/02/09 07:19:27
nit: s/i++/++i/
[1] allows to use both pre and pos
yabinh
2017/02/09 10:37:03
Done.
| |
| 213 } | |
| 214 } | |
| 215 return false; | |
| 216 } | |
| 217 | |
| 218 std::pair<int, int> invalidDeletionLength() { | |
|
yosin_UTC9
2017/02/09 07:19:27
Try to mark |constexpr|.
yabinh
2017/02/09 10:37:03
Do you mean simply adding a mark, like this:
cons
yosin_UTC9
2017/02/10 04:54:11
I mean
constexpr std::pair<int, int> invalidDelet
yabinh
2017/02/10 05:46:07
Sorry, I was referring to the above lines. It can
| |
| 219 return std::make_pair(-1, -1); | |
| 220 } | |
| 221 | |
| 222 bool isInvalidDeletionLength(const std::pair<int, int>& lengthPair) { | |
| 223 return lengthPair.first == -1 && lengthPair.second == -1; | |
| 224 } | |
| 225 | |
| 226 std::pair<int, int> calculateDeletionLengthsInCodePoints( | |
| 227 const String& text, | |
| 228 const int beforeLengthInCodePoints, | |
| 229 const int afterLengthInCodePoints, | |
| 230 const int selectionStart, | |
| 231 const int selectionEnd) { | |
| 232 int deletionStart = selectionStart; | |
| 233 int deletionEnd = selectionEnd; | |
| 234 const int length = static_cast<int>(text.length()); | |
| 235 | |
| 236 if (text.is8Bit()) { | |
| 237 const LChar* LText = text.characters8(); | |
|
yosin_UTC9
2017/02/09 07:19:27
s/LText/character8s/
yabinh
2017/02/09 10:37:03
Done.
| |
| 238 U8_BACK_N(LText, 0, deletionStart, beforeLengthInCodePoints); | |
|
yosin_UTC9
2017/02/09 07:19:27
I think LChar, Latin-1 Character/ doesn't have sur
yabinh
2017/02/09 10:37:03
Yes. That's why we don't need to check whether it
yosin_UTC9
2017/02/10 04:54:11
U8_XXX_N() is for UTF-8, but LChar contains Latin-
yabinh
2017/02/10 07:27:26
You are right.
Actually utf8 is converted in WebSt
| |
| 239 U8_FWD_N(LText, deletionEnd, length, afterLengthInCodePoints); | |
| 240 } else { | |
| 241 const UChar* UText = text.characters16(); | |
|
yosin_UTC9
2017/02/09 07:19:27
s/LText/character16s/
yabinh
2017/02/09 10:37:03
Done.
| |
| 242 U16_BACK_N(UText, 0, deletionStart, beforeLengthInCodePoints); | |
|
yosin_UTC9
2017/02/09 07:19:27
nona@, do we have utility function to walk around
Seigo Nonaka
2017/02/09 07:29:21
We only have base/i18n/char_iterator.h, but it can
| |
| 243 // Required by Android's InputConnection spec. | |
| 244 if (hasInvalidSurrogatePair(UText, deletionStart, selectionStart)) | |
| 245 return invalidDeletionLength(); | |
| 246 | |
| 247 U16_FWD_N(UText, deletionEnd, length, afterLengthInCodePoints); | |
| 248 // Required by Android's InputConnection spec. | |
| 249 if (hasInvalidSurrogatePair(UText, selectionEnd, deletionEnd)) | |
| 250 return invalidDeletionLength(); | |
| 251 } | |
| 252 | |
| 253 const int beforeLength = selectionStart - deletionStart; | |
| 254 const int afterLength = deletionEnd - selectionEnd; | |
| 255 DCHECK_GE(beforeLength, 0); | |
| 256 DCHECK_GE(afterLength, 0); | |
| 257 return std::make_pair(beforeLength, afterLength); | |
| 258 } | |
| 259 | |
| 203 } // anonymous namespace | 260 } // anonymous namespace |
| 204 | 261 |
| 205 InputMethodController* InputMethodController::create(LocalFrame& frame) { | 262 InputMethodController* InputMethodController::create(LocalFrame& frame) { |
| 206 return new InputMethodController(frame); | 263 return new InputMethodController(frame); |
| 207 } | 264 } |
| 208 | 265 |
| 209 InputMethodController::InputMethodController(LocalFrame& frame) | 266 InputMethodController::InputMethodController(LocalFrame& frame) |
| 210 : m_frame(&frame), m_hasComposition(false) {} | 267 : m_frame(&frame), m_hasComposition(false) {} |
| 211 | 268 |
| 212 InputMethodController::~InputMethodController() = default; | 269 InputMethodController::~InputMethodController() = default; |
| (...skipping 671 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 884 const size_t diff = computeDistanceToRightGraphemeBoundary(position); | 941 const size_t diff = computeDistanceToRightGraphemeBoundary(position); |
| 885 const int adjustedEnd = end + static_cast<int>(diff); | 942 const int adjustedEnd = end + static_cast<int>(diff); |
| 886 if (!setSelectionOffsets(PlainTextRange(selectionEnd, adjustedEnd))) | 943 if (!setSelectionOffsets(PlainTextRange(selectionEnd, adjustedEnd))) |
| 887 return; | 944 return; |
| 888 TypingCommand::deleteSelection(document()); | 945 TypingCommand::deleteSelection(document()); |
| 889 } | 946 } |
| 890 | 947 |
| 891 setSelectionOffsets(PlainTextRange(selectionStart, selectionEnd)); | 948 setSelectionOffsets(PlainTextRange(selectionStart, selectionEnd)); |
| 892 } | 949 } |
| 893 | 950 |
| 951 void InputMethodController::deleteSurroundingTextInCodePoints(int before, | |
| 952 int after) { | |
| 953 DCHECK_GE(before, 0); | |
| 954 DCHECK_GE(after, 0); | |
| 955 if (!editor().canEdit()) | |
| 956 return; | |
| 957 const PlainTextRange selectionOffsets(getSelectionOffsets()); | |
| 958 if (selectionOffsets.isNull()) | |
| 959 return; | |
| 960 Element* const rootEditableElement = | |
| 961 frame().selection().rootEditableElement(); | |
| 962 if (!rootEditableElement) | |
| 963 return; | |
| 964 | |
| 965 const int selectionStart = static_cast<int>(selectionOffsets.start()); | |
| 966 const int selectionEnd = static_cast<int>(selectionOffsets.end()); | |
| 967 const TextIteratorBehavior& behavior = | |
| 968 TextIteratorBehavior::Builder() | |
| 969 .setEmitsObjectReplacementCharacter(true) | |
| 970 .build(); | |
| 971 const String& text = plainText( | |
| 972 EphemeralRange::rangeOfContents(*rootEditableElement), behavior); | |
| 973 std::pair<int, int> deletionLengthPair = calculateDeletionLengthsInCodePoints( | |
| 974 text, before, after, selectionStart, selectionEnd); | |
| 975 if (isInvalidDeletionLength(deletionLengthPair)) | |
| 976 return; | |
| 977 | |
| 978 return deleteSurroundingText(deletionLengthPair.first, | |
| 979 deletionLengthPair.second); | |
| 980 } | |
| 981 | |
| 894 WebTextInputInfo InputMethodController::textInputInfo() const { | 982 WebTextInputInfo InputMethodController::textInputInfo() const { |
| 895 WebTextInputInfo info; | 983 WebTextInputInfo info; |
| 896 if (!isAvailable()) | 984 if (!isAvailable()) |
| 897 return info; | 985 return info; |
| 898 | 986 |
| 899 if (!frame().selection().isAvailable()) { | 987 if (!frame().selection().isAvailable()) { |
| 900 // plugins/mouse-capture-inside-shadow.html reaches here. | 988 // plugins/mouse-capture-inside-shadow.html reaches here. |
| 901 return info; | 989 return info; |
| 902 } | 990 } |
| 903 Element* element = frame().selection().rootEditableElement(); | 991 Element* element = frame().selection().rootEditableElement(); |
| (...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1108 frame().chromeClient().resetInputMethod(); | 1196 frame().chromeClient().resetInputMethod(); |
| 1109 } | 1197 } |
| 1110 | 1198 |
| 1111 DEFINE_TRACE(InputMethodController) { | 1199 DEFINE_TRACE(InputMethodController) { |
| 1112 visitor->trace(m_frame); | 1200 visitor->trace(m_frame); |
| 1113 visitor->trace(m_compositionRange); | 1201 visitor->trace(m_compositionRange); |
| 1114 SynchronousMutationObserver::trace(visitor); | 1202 SynchronousMutationObserver::trace(visitor); |
| 1115 } | 1203 } |
| 1116 | 1204 |
| 1117 } // namespace blink | 1205 } // namespace blink |
| OLD | NEW |