REGRESSION (r238078): Do not draw caps lock indicator when Strong Password button...
[WebKit-https.git] / Source / WebCore / html / TextFieldInputType.cpp
index 6fefffd..471b77a 100644 (file)
@@ -51,6 +51,7 @@
 #include "RenderLayer.h"
 #include "RenderTextControlSingleLine.h"
 #include "RenderTheme.h"
+#include "RuntimeEnabledFeatures.h"
 #include "ShadowRoot.h"
 #include "TextControlInnerElements.h"
 #include "TextEvent.h"
@@ -84,7 +85,7 @@ TextFieldInputType::~TextFieldInputType()
 bool TextFieldInputType::isKeyboardFocusable(KeyboardEvent*) const
 {
     ASSERT(element());
-#if PLATFORM(IOS)
+#if PLATFORM(IOS_FAMILY)
     if (element()->isReadOnly())
         return false;
 #endif
@@ -260,8 +261,13 @@ void TextFieldInputType::handleFocusEvent(Node* oldFocusedNode, FocusDirection)
 {
     ASSERT(element());
     ASSERT_UNUSED(oldFocusedNode, oldFocusedNode != element());
-    if (RefPtr<Frame> frame = element()->document().frame())
+    if (RefPtr<Frame> frame = element()->document().frame()) {
         frame->editor().textFieldDidBeginEditing(element());
+#if ENABLE(DATALIST_ELEMENT) && PLATFORM(IOS_FAMILY)
+        if (element()->list() && m_dataListDropdownIndicator)
+            m_dataListDropdownIndicator->setInlineStyleProperty(CSSPropertyDisplay, suggestions().size() ? CSSValueBlock : CSSValueNone, true);
+#endif
+    }
 }
 
 void TextFieldInputType::handleBlurEvent()
@@ -269,6 +275,10 @@ void TextFieldInputType::handleBlurEvent()
     InputType::handleBlurEvent();
     ASSERT(element());
     element()->endEditing();
+#if ENABLE(DATALIST_ELEMENT) && PLATFORM(IOS_FAMILY)
+    if (element()->list() && m_dataListDropdownIndicator)
+        m_dataListDropdownIndicator->setInlineStyleProperty(CSSPropertyDisplay, CSSValueNone, true);
+#endif
 }
 
 bool TextFieldInputType::shouldSubmitImplicitly(Event& event)
@@ -285,6 +295,9 @@ RenderPtr<RenderElement> TextFieldInputType::createInputRenderer(RenderStyle&& s
 
 bool TextFieldInputType::needsContainer() const
 {
+#if ENABLE(DATALIST_ELEMENT)
+    return element()->hasAttributeWithoutSynchronization(listAttr);
+#endif
     return false;
 }
 
@@ -343,6 +356,12 @@ void TextFieldInputType::createShadowSubtree()
     }
 
     updateAutoFillButton();
+
+#if ENABLE(DATALIST_ELEMENT)
+    m_dataListDropdownIndicator = DataListButtonElement::create(element()->document(), *this);
+    m_dataListDropdownIndicator->setInlineStyleProperty(CSSPropertyDisplay, CSSValueNone, true);
+    m_container->appendChild(*m_dataListDropdownIndicator);
+#endif
 }
 
 HTMLElement* TextFieldInputType::containerElement() const
@@ -392,6 +411,9 @@ void TextFieldInputType::destroyShadowSubtree()
     m_innerSpinButton = nullptr;
     m_capsLockIndicator = nullptr;
     m_autoFillButton = nullptr;
+#if ENABLE(DATALIST)
+    m_dataListDropdownIndicator = nullptr;
+#endif
     m_container = nullptr;
 }
 
@@ -458,6 +480,8 @@ static String autoFillButtonTypeToAccessibilityLabel(AutoFillButtonType autoFill
         return AXAutoFillCredentialsLabel();
     case AutoFillButtonType::StrongPassword:
         return AXAutoFillStrongPasswordLabel();
+    case AutoFillButtonType::CreditCard:
+        return AXAutoFillCreditCardLabel();
     case AutoFillButtonType::None:
         ASSERT_NOT_REACHED();
         return { };
@@ -471,6 +495,7 @@ static String autoFillButtonTypeToAutoFillButtonText(AutoFillButtonType autoFill
     switch (autoFillButtonType) {
     case AutoFillButtonType::Contacts:
     case AutoFillButtonType::Credentials:
+    case AutoFillButtonType::CreditCard:
         return emptyString();
     case AutoFillButtonType::StrongPassword:
         return autoFillStrongPasswordLabel();
@@ -491,6 +516,8 @@ static AtomicString autoFillButtonTypeToAutoFillButtonPseudoClassName(AutoFillBu
         return { "-webkit-credentials-auto-fill-button", AtomicString::ConstructFromLiteral };
     case AutoFillButtonType::StrongPassword:
         return { "-webkit-strong-password-auto-fill-button", AtomicString::ConstructFromLiteral };
+    case AutoFillButtonType::CreditCard:
+        return { "-webkit-credit-card-auto-fill-button", AtomicString::ConstructFromLiteral };
     case AutoFillButtonType::None:
         ASSERT_NOT_REACHED();
         return emptyAtom();
@@ -507,6 +534,8 @@ static bool isAutoFillButtonTypeChanged(const AtomicString& attribute, AutoFillB
         return true;
     if (attribute == "-webkit-strong-password-auto-fill-button" && autoFillButtonType != AutoFillButtonType::StrongPassword)
         return true;
+    if (attribute == "-webkit-credit-card-auto-fill-button" && autoFillButtonType != AutoFillButtonType::CreditCard)
+        return true;
     return false;
 }
 
@@ -561,7 +590,7 @@ void TextFieldInputType::handleBeforeTextInsertedEvent(BeforeTextInsertedEvent&
 bool TextFieldInputType::shouldRespectListAttribute()
 {
 #if ENABLE(DATALIST_ELEMENT)
-    return true;
+    return RuntimeEnabledFeatures::sharedFeatures().dataListElementEnabled();
 #else
     return InputType::themeSupportsDataListUI(this);
 #endif
@@ -636,6 +665,10 @@ void TextFieldInputType::didSetValueByUserEdit()
     if (RefPtr<Frame> frame = element()->document().frame())
         frame->editor().textDidChangeInTextField(element());
 #if ENABLE(DATALIST_ELEMENT)
+#if PLATFORM(IOS_FAMILY)
+    if (element()->list() && m_dataListDropdownIndicator)
+        m_dataListDropdownIndicator->setInlineStyleProperty(CSSPropertyDisplay, suggestions().size() ? CSSValueBlock : CSSValueNone, true);
+#endif
     if (element()->list())
         displaySuggestions(DataListSuggestionActivationType::TextChanged);
 #endif
@@ -691,6 +724,9 @@ bool TextFieldInputType::shouldDrawCapsLockIndicator() const
     if (element()->isDisabledOrReadOnly())
         return false;
 
+    if (element()->hasAutoFillStrongPasswordButton())
+        return false;
+
     RefPtr<Frame> frame = element()->document().frame();
     if (!frame)
         return false;
@@ -759,6 +795,8 @@ void TextFieldInputType::createAutoFillButton(AutoFillButtonType autoFillButtonT
 
 void TextFieldInputType::updateAutoFillButton()
 {
+    capsLockStateMayHaveChanged();
+
     if (shouldDrawAutoFillButton()) {
         if (!m_container)
             createContainer();
@@ -785,6 +823,29 @@ void TextFieldInputType::updateAutoFillButton()
 
 #if ENABLE(DATALIST_ELEMENT)
 
+void TextFieldInputType::listAttributeTargetChanged()
+{
+    m_cachedSuggestions = std::make_pair(String(), Vector<String>());
+
+    if (!m_dataListDropdownIndicator)
+        return;
+
+#if !PLATFORM(IOS_FAMILY)
+    m_dataListDropdownIndicator->setInlineStyleProperty(CSSPropertyDisplay, element()->list() ? CSSValueBlock : CSSValueNone, true);
+#endif
+}
+
+HTMLElement* TextFieldInputType::dataListButtonElement() const
+{
+    return m_dataListDropdownIndicator.get();
+}
+
+void TextFieldInputType::dataListButtonElementWasClicked()
+{
+    if (element()->list())
+        displaySuggestions(DataListSuggestionActivationType::IndicatorClicked);
+}
+
 IntRect TextFieldInputType::elementRectInRootViewCoordinates() const
 {
     if (!element()->renderer())
@@ -792,9 +853,15 @@ IntRect TextFieldInputType::elementRectInRootViewCoordinates() const
     return element()->document().view()->contentsToRootView(element()->renderer()->absoluteBoundingBoxRect());
 }
 
-Vector<String> TextFieldInputType::suggestions() const
+Vector<String> TextFieldInputType::suggestions()
 {
     Vector<String> suggestions;
+    Vector<String> matchesContainingValue;
+
+    String elementValue = element()->value();
+
+    if (!m_cachedSuggestions.first.isNull() && equalIgnoringASCIICase(m_cachedSuggestions.first, elementValue))
+        return m_cachedSuggestions.second;
 
     if (auto dataList = element()->dataList()) {
         Ref<HTMLCollection> options = dataList->options();
@@ -803,11 +870,18 @@ Vector<String> TextFieldInputType::suggestions() const
                 continue;
 
             String value = sanitizeValue(option->value());
-            if (!suggestions.contains(value) && (element()->value().isEmpty() || value.containsIgnoringASCIICase(element()->value())))
+            if (elementValue.isEmpty())
+                suggestions.append(value);
+            else if (value.startsWithIgnoringASCIICase(elementValue))
                 suggestions.append(value);
+            else if (value.containsIgnoringASCIICase(elementValue))
+                matchesContainingValue.append(value);
         }
     }
 
+    suggestions.appendVector(matchesContainingValue);
+    m_cachedSuggestions = std::make_pair(elementValue, suggestions);
+
     return suggestions;
 }
 
@@ -818,7 +892,10 @@ void TextFieldInputType::didSelectDataListOption(const String& selectedOption)
 
 void TextFieldInputType::didCloseSuggestions()
 {
+    m_cachedSuggestions = std::make_pair(String(), Vector<String>());
     m_suggestionPicker = nullptr;
+    if (element()->renderer())
+        element()->renderer()->repaint();
 }
 
 void TextFieldInputType::displaySuggestions(DataListSuggestionActivationType type)
@@ -826,7 +903,7 @@ void TextFieldInputType::displaySuggestions(DataListSuggestionActivationType typ
     if (element()->isDisabledFormControl() || !element()->renderer())
         return;
 
-    if (!UserGestureIndicator::processingUserGesture())
+    if (!UserGestureIndicator::processingUserGesture() && type != DataListSuggestionActivationType::TextChanged)
         return;
 
     if (!m_suggestionPicker && suggestions().size() > 0)
@@ -844,6 +921,11 @@ void TextFieldInputType::closeSuggestions()
         m_suggestionPicker->close();
 }
 
+bool TextFieldInputType::isPresentingAttachedView() const
+{
+    return !!m_suggestionPicker;
+}
+
 #endif
 
 } // namespace WebCore