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 |
| 11 * notice, this list of conditions and the following disclaimer in the | 11 * notice, this list of conditions and the following disclaimer in the |
| 12 * documentation and/or other materials provided with the distribution. | 12 * documentation and/or other materials provided with the distribution. |
| 13 * | 13 * |
| 14 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY | 14 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY |
| 15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| 17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR | 17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR |
| 18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | 18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| 19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | 19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| 20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | 20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| 21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY | 21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
| 22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 25 */ | 25 */ |
| 26 | 26 |
| 27 #include "core/editing/InputMethodController.h" | 27 #include "core/editing/InputMethodController.h" |
| 28 | 28 |
| 29 #include "core/InputTypeNames.h" | |
| 29 #include "core/dom/Document.h" | 30 #include "core/dom/Document.h" |
| 30 #include "core/dom/Element.h" | 31 #include "core/dom/Element.h" |
| 31 #include "core/dom/Text.h" | 32 #include "core/dom/Text.h" |
| 32 #include "core/editing/EditingUtilities.h" | 33 #include "core/editing/EditingUtilities.h" |
| 33 #include "core/editing/Editor.h" | 34 #include "core/editing/Editor.h" |
| 34 #include "core/editing/commands/TypingCommand.h" | 35 #include "core/editing/commands/TypingCommand.h" |
| 35 #include "core/editing/markers/DocumentMarkerController.h" | 36 #include "core/editing/markers/DocumentMarkerController.h" |
| 36 #include "core/events/CompositionEvent.h" | 37 #include "core/events/CompositionEvent.h" |
| 37 #include "core/frame/LocalFrame.h" | 38 #include "core/frame/LocalFrame.h" |
| 39 #include "core/html/HTMLInputElement.h" | |
| 38 #include "core/html/HTMLTextAreaElement.h" | 40 #include "core/html/HTMLTextAreaElement.h" |
| 39 #include "core/input/EventHandler.h" | 41 #include "core/input/EventHandler.h" |
| 40 #include "core/layout/LayoutObject.h" | 42 #include "core/layout/LayoutObject.h" |
| 41 #include "core/layout/LayoutTheme.h" | 43 #include "core/layout/LayoutTheme.h" |
| 42 #include "core/page/ChromeClient.h" | 44 #include "core/page/ChromeClient.h" |
| 43 | 45 |
| 44 namespace blink { | 46 namespace blink { |
| 45 | 47 |
| 46 namespace { | 48 namespace { |
| 47 | 49 |
| (...skipping 876 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 924 const size_t diff = computeDistanceToRightGraphemeBoundary(position); | 926 const size_t diff = computeDistanceToRightGraphemeBoundary(position); |
| 925 const int adjustedEnd = end + static_cast<int>(diff); | 927 const int adjustedEnd = end + static_cast<int>(diff); |
| 926 if (!setSelectionOffsets(PlainTextRange(selectionEnd, adjustedEnd))) | 928 if (!setSelectionOffsets(PlainTextRange(selectionEnd, adjustedEnd))) |
| 927 return; | 929 return; |
| 928 TypingCommand::deleteSelection(*frame().document()); | 930 TypingCommand::deleteSelection(*frame().document()); |
| 929 } | 931 } |
| 930 | 932 |
| 931 setSelectionOffsets(PlainTextRange(selectionStart, selectionEnd)); | 933 setSelectionOffsets(PlainTextRange(selectionStart, selectionEnd)); |
| 932 } | 934 } |
| 933 | 935 |
| 936 WebTextInputInfo InputMethodController::textInputInfo() const { | |
| 937 WebTextInputInfo info; | |
| 938 if (!frame().document()) | |
| 939 return info; | |
| 940 | |
| 941 if (!frame().selection().isAvailable()) { | |
| 942 // plugins/mouse-capture-inside-shadow.html reaches here. | |
| 943 return info; | |
| 944 } | |
| 945 Element* element = frame().selection().rootEditableElement(); | |
| 946 if (!element) | |
| 947 return info; | |
| 948 | |
| 949 info.inputMode = inputModeOfFocusedElement(); | |
| 950 info.type = textInputType(); | |
| 951 info.flags = textInputFlags(); | |
| 952 if (info.type == WebTextInputTypeNone) | |
| 953 return info; | |
| 954 | |
| 955 if (!frame().editor().canEdit()) | |
| 956 return info; | |
| 957 | |
| 958 // TODO(dglazkov): The use of updateStyleAndLayoutIgnorePendingStylesheets | |
| 959 // needs to be audited. see http://crbug.com/590369 for more details. | |
| 960 frame().document()->updateStyleAndLayoutIgnorePendingStylesheets(); | |
| 961 | |
| 962 DocumentLifecycle::DisallowTransitionScope disallowTransition( | |
| 963 frame().document()->lifecycle()); | |
| 964 | |
| 965 // Emits an object replacement character for each replaced element so that | |
| 966 // it is exposed to IME and thus could be deleted by IME on android. | |
| 967 info.value = plainText(EphemeralRange::rangeOfContents(*element), | |
| 968 TextIteratorEmitsObjectReplacementCharacter); | |
| 969 | |
| 970 if (info.value.isEmpty()) | |
| 971 return info; | |
| 972 | |
| 973 EphemeralRange firstRange = | |
| 974 firstEphemeralRangeOf(frame().selection().selection()); | |
| 975 if (firstRange.isNotNull()) { | |
| 976 PlainTextRange plainTextRange(PlainTextRange::create(*element, firstRange)); | |
| 977 if (plainTextRange.isNotNull()) { | |
| 978 info.selectionStart = plainTextRange.start(); | |
| 979 info.selectionEnd = plainTextRange.end(); | |
| 980 } | |
| 981 } | |
| 982 | |
| 983 EphemeralRange range = compositionEphemeralRange(); | |
| 984 if (range.isNotNull()) { | |
| 985 PlainTextRange plainTextRange(PlainTextRange::create(*element, range)); | |
| 986 if (plainTextRange.isNotNull()) { | |
| 987 info.compositionStart = plainTextRange.start(); | |
| 988 info.compositionEnd = plainTextRange.end(); | |
| 989 } | |
| 990 } | |
| 991 | |
| 992 return info; | |
| 993 } | |
| 994 | |
| 995 int InputMethodController::textInputFlags() const { | |
| 996 Element* element = frame().document()->focusedElement(); | |
| 997 if (!element) | |
| 998 return WebTextInputFlagNone; | |
| 999 | |
| 1000 DEFINE_STATIC_LOCAL(AtomicString, autocompleteString, ("autocomplete")); | |
| 1001 DEFINE_STATIC_LOCAL(AtomicString, autocorrectString, ("autocorrect")); | |
| 1002 int flags = 0; | |
| 1003 | |
| 1004 const AtomicString& autocomplete = element->getAttribute(autocompleteString); | |
|
esprehn
2016/10/14 16:49:35
This should already be defined as HTMLNames::autoc
dtapuska
2016/10/14 17:21:28
Done.
| |
| 1005 if (autocomplete == "on") | |
| 1006 flags |= WebTextInputFlagAutocompleteOn; | |
| 1007 else if (autocomplete == "off") | |
| 1008 flags |= WebTextInputFlagAutocompleteOff; | |
| 1009 | |
| 1010 const AtomicString& autocorrect = element->getAttribute(autocorrectString); | |
|
esprehn
2016/10/14 16:49:36
Ditto
dtapuska
2016/10/14 17:21:28
Done.
| |
| 1011 if (autocorrect == "on") | |
| 1012 flags |= WebTextInputFlagAutocorrectOn; | |
| 1013 else if (autocorrect == "off") | |
| 1014 flags |= WebTextInputFlagAutocorrectOff; | |
| 1015 | |
| 1016 SpellcheckAttributeState spellcheck = element->spellcheckAttributeState(); | |
| 1017 if (spellcheck == SpellcheckAttributeTrue) | |
| 1018 flags |= WebTextInputFlagSpellcheckOn; | |
| 1019 else if (spellcheck == SpellcheckAttributeFalse) | |
| 1020 flags |= WebTextInputFlagSpellcheckOff; | |
| 1021 | |
| 1022 if (isHTMLTextFormControlElement(element)) { | |
| 1023 HTMLTextFormControlElement* formElement = | |
| 1024 static_cast<HTMLTextFormControlElement*>(element); | |
| 1025 if (formElement->supportsAutocapitalize()) { | |
| 1026 DEFINE_STATIC_LOCAL(const AtomicString, none, ("none")); | |
| 1027 DEFINE_STATIC_LOCAL(const AtomicString, characters, ("characters")); | |
| 1028 DEFINE_STATIC_LOCAL(const AtomicString, words, ("words")); | |
| 1029 DEFINE_STATIC_LOCAL(const AtomicString, sentences, ("sentences")); | |
| 1030 | |
| 1031 const AtomicString& autocapitalize = formElement->autocapitalize(); | |
| 1032 if (autocapitalize == none) | |
| 1033 flags |= WebTextInputFlagAutocapitalizeNone; | |
| 1034 else if (autocapitalize == characters) | |
| 1035 flags |= WebTextInputFlagAutocapitalizeCharacters; | |
| 1036 else if (autocapitalize == words) | |
| 1037 flags |= WebTextInputFlagAutocapitalizeWords; | |
| 1038 else if (autocapitalize == sentences) | |
| 1039 flags |= WebTextInputFlagAutocapitalizeSentences; | |
| 1040 else | |
| 1041 NOTREACHED(); | |
| 1042 } | |
| 1043 } | |
| 1044 | |
| 1045 return flags; | |
| 1046 } | |
| 1047 | |
| 1048 WebString InputMethodController::inputModeOfFocusedElement() const { | |
| 1049 if (!RuntimeEnabledFeatures::inputModeAttributeEnabled()) | |
| 1050 return WebString(); | |
| 1051 | |
| 1052 Element* element = frame().document()->focusedElement(); | |
| 1053 if (!element) | |
| 1054 return WebString(); | |
| 1055 | |
| 1056 if (isHTMLInputElement(*element)) { | |
| 1057 const HTMLInputElement& input = toHTMLInputElement(*element); | |
| 1058 if (input.supportsInputModeAttribute()) | |
| 1059 return input.fastGetAttribute(HTMLNames::inputmodeAttr).lower(); | |
| 1060 return WebString(); | |
| 1061 } | |
| 1062 if (isHTMLTextAreaElement(*element)) { | |
| 1063 const HTMLTextAreaElement& textarea = toHTMLTextAreaElement(*element); | |
| 1064 return textarea.fastGetAttribute(HTMLNames::inputmodeAttr).lower(); | |
| 1065 } | |
| 1066 | |
| 1067 return WebString(); | |
| 1068 } | |
| 1069 | |
| 1070 WebTextInputType InputMethodController::textInputType() const { | |
| 1071 if (!frame().selection().isAvailable()) { | |
| 1072 // "mouse-capture-inside-shadow.html" reaches here. | |
| 1073 return WebTextInputTypeNone; | |
| 1074 } | |
| 1075 | |
| 1076 // It's important to preserve the equivalence of textInputInfo().type and | |
| 1077 // textInputType(), so perform the same rootEditableElement() existence check | |
| 1078 // here for consistency. | |
| 1079 if (!frame().selection().selection().rootEditableElement()) | |
| 1080 return WebTextInputTypeNone; | |
| 1081 | |
| 1082 Document* document = frame().document(); | |
| 1083 if (!document) | |
| 1084 return WebTextInputTypeNone; | |
| 1085 | |
| 1086 Element* element = document->focusedElement(); | |
| 1087 if (!element) | |
| 1088 return WebTextInputTypeNone; | |
| 1089 | |
| 1090 if (isHTMLInputElement(*element)) { | |
| 1091 HTMLInputElement& input = toHTMLInputElement(*element); | |
| 1092 const AtomicString& type = input.type(); | |
| 1093 | |
| 1094 if (input.isDisabledOrReadOnly()) | |
| 1095 return WebTextInputTypeNone; | |
| 1096 | |
| 1097 if (type == InputTypeNames::password) | |
| 1098 return WebTextInputTypePassword; | |
| 1099 if (type == InputTypeNames::search) | |
| 1100 return WebTextInputTypeSearch; | |
| 1101 if (type == InputTypeNames::email) | |
| 1102 return WebTextInputTypeEmail; | |
| 1103 if (type == InputTypeNames::number) | |
| 1104 return WebTextInputTypeNumber; | |
| 1105 if (type == InputTypeNames::tel) | |
| 1106 return WebTextInputTypeTelephone; | |
| 1107 if (type == InputTypeNames::url) | |
| 1108 return WebTextInputTypeURL; | |
| 1109 if (type == InputTypeNames::text) | |
| 1110 return WebTextInputTypeText; | |
| 1111 | |
| 1112 return WebTextInputTypeNone; | |
| 1113 } | |
| 1114 | |
| 1115 if (isHTMLTextAreaElement(*element)) { | |
| 1116 if (toHTMLTextAreaElement(*element).isDisabledOrReadOnly()) | |
| 1117 return WebTextInputTypeNone; | |
| 1118 return WebTextInputTypeTextArea; | |
| 1119 } | |
| 1120 | |
| 1121 if (element->isHTMLElement()) { | |
| 1122 if (toHTMLElement(element)->isDateTimeFieldElement()) | |
| 1123 return WebTextInputTypeDateTimeField; | |
| 1124 } | |
| 1125 | |
| 1126 document->updateStyleAndLayoutTree(); | |
| 1127 if (hasEditableStyle(*element)) | |
| 1128 return WebTextInputTypeContentEditable; | |
| 1129 | |
| 1130 return WebTextInputTypeNone; | |
| 1131 } | |
| 1132 | |
| 934 DEFINE_TRACE(InputMethodController) { | 1133 DEFINE_TRACE(InputMethodController) { |
| 935 visitor->trace(m_frame); | 1134 visitor->trace(m_frame); |
| 936 visitor->trace(m_compositionRange); | 1135 visitor->trace(m_compositionRange); |
| 937 } | 1136 } |
| 938 | 1137 |
| 939 } // namespace blink | 1138 } // namespace blink |
| OLD | NEW |