Improve use of NeverDestroyed
[WebKit-https.git] / Source / WebCore / html / InputType.cpp
index 6a7ba5e..de0e779 100644 (file)
@@ -2,7 +2,7 @@
  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
  *           (C) 2001 Dirk Mueller (mueller@kde.org)
- * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2013, 2014 Apple Inc. All rights reserved.
+ * Copyright (C) 2004-2017 Apple Inc. All rights reserved.
  *           (C) 2006 Alexey Proskuryakov (ap@nypop.com)
  * Copyright (C) 2007 Samuel Weinig (sam@webkit.org)
  * Copyright (C) 2009, 2010, 2011, 2012 Google Inc. All rights reserved.
@@ -38,8 +38,8 @@
 #include "DateTimeInputType.h"
 #include "DateTimeLocalInputType.h"
 #include "EmailInputType.h"
+#include "EventNames.h"
 #include "ExceptionCode.h"
-#include "ExceptionCodePlaceholder.h"
 #include "FileInputType.h"
 #include "FileList.h"
 #include "FormController.h"
@@ -69,7 +69,6 @@
 #include "ShadowRoot.h"
 #include "SubmitInputType.h"
 #include "TelephoneInputType.h"
-#include "TextBreakIterator.h"
 #include "TextInputType.h"
 #include "TimeInputType.h"
 #include "URLInputType.h"
@@ -78,6 +77,7 @@
 #include <wtf/Assertions.h>
 #include <wtf/HashMap.h>
 #include <wtf/text/StringHash.h>
+#include <wtf/text/TextBreakIterator.h>
 
 namespace WebCore {
 
@@ -86,7 +86,7 @@ using namespace HTMLNames;
 typedef bool (RuntimeEnabledFeatures::*InputTypeConditionalFunction)() const;
 typedef const AtomicString& (*InputTypeNameFunction)();
 typedef std::unique_ptr<InputType> (*InputTypeFactoryFunction)(HTMLInputElement&);
-typedef HashMap<AtomicString, InputTypeFactoryFunction, CaseFoldingHash> InputTypeFactoryMap;
+typedef HashMap<AtomicString, InputTypeFactoryFunction, ASCIICaseInsensitiveHash> InputTypeFactoryMap;
 
 template<class T>
 static std::unique_ptr<InputType> createInputType(HTMLInputElement& element)
@@ -94,7 +94,7 @@ static std::unique_ptr<InputType> createInputType(HTMLInputElement& element)
     return std::make_unique<T>(element);
 }
 
-static void populateInputTypeFactoryMap(InputTypeFactoryMap& map)
+static InputTypeFactoryMap createInputTypeFactoryMap()
 {
     static const struct InputTypes {
         InputTypeConditionalFunction conditionalFunction;
@@ -140,20 +140,19 @@ static void populateInputTypeFactoryMap(InputTypeFactoryMap& map)
         // No need to register "text" because it is the default type.
     };
 
+    InputTypeFactoryMap map;
     for (auto& inputType : inputTypes) {
         auto conditionalFunction = inputType.conditionalFunction;
         if (!conditionalFunction || (RuntimeEnabledFeatures::sharedFeatures().*conditionalFunction)())
             map.add(inputType.nameFunction(), inputType.factoryFunction);
     }
+    return map;
 }
 
 std::unique_ptr<InputType> InputType::create(HTMLInputElement& element, const AtomicString& typeName)
 {
-    static NeverDestroyed<InputTypeFactoryMap> factoryMap;
-    if (factoryMap.get().isEmpty())
-        populateInputTypeFactoryMap(factoryMap);
-
     if (!typeName.isEmpty()) {
+        static const auto factoryMap = makeNeverDestroyed(createInputTypeFactoryMap());
         if (auto factory = factoryMap.get().get(typeName))
             return factory(element);
     }
@@ -171,9 +170,7 @@ InputType::~InputType()
 
 bool InputType::themeSupportsDataListUI(InputType* type)
 {
-    Document& document = type->element().document();
-    RefPtr<RenderTheme> theme = document.page() ? &document.page()->theme() : RenderTheme::defaultTheme();
-    return theme->supportsDataListUI(type->formControlType());
+    return RenderTheme::singleton().supportsDataListUI(type->formControlType());
 }
 
 bool InputType::isTextField() const
@@ -227,9 +224,9 @@ double InputType::valueAsDate() const
     return DateComponents::invalidMilliseconds();
 }
 
-void InputType::setValueAsDate(double, ExceptionCode& ec) const
+ExceptionOr<void> InputType::setValueAsDate(double) const
 {
-    ec = INVALID_STATE_ERR;
+    return Exception { INVALID_STATE_ERR };
 }
 
 double InputType::valueAsDouble() const
@@ -237,14 +234,14 @@ double InputType::valueAsDouble() const
     return std::numeric_limits<double>::quiet_NaN();
 }
 
-void InputType::setValueAsDouble(double doubleValue, TextFieldEventBehavior eventBehavior, ExceptionCode& ec) const
+ExceptionOr<void> InputType::setValueAsDouble(double doubleValue, TextFieldEventBehavior eventBehavior) const
 {
-    setValueAsDecimal(Decimal::fromDouble(doubleValue), eventBehavior, ec);
+    return setValueAsDecimal(Decimal::fromDouble(doubleValue), eventBehavior);
 }
 
-void InputType::setValueAsDecimal(const Decimal&, TextFieldEventBehavior, ExceptionCode& ec) const
+ExceptionOr<void> InputType::setValueAsDecimal(const Decimal&, TextFieldEventBehavior) const
 {
-    ec = INVALID_STATE_ERR;
+    return Exception { INVALID_STATE_ERR };
 }
 
 bool InputType::supportsValidation() const
@@ -338,24 +335,30 @@ bool InputType::isInRange(const String& value) const
     if (!isSteppable())
         return false;
 
+    StepRange stepRange(createStepRange(RejectAny));
+    if (!stepRange.hasRangeLimitations())
+        return false;
+    
     const Decimal numericValue = parseToNumberOrNaN(value);
     if (!numericValue.isFinite())
         return true;
 
-    StepRange stepRange(createStepRange(RejectAny));
     return numericValue >= stepRange.minimum() && numericValue <= stepRange.maximum();
 }
 
 bool InputType::isOutOfRange(const String& value) const
 {
-    if (!isSteppable())
+    if (!isSteppable() || value.isEmpty())
+        return false;
+
+    StepRange stepRange(createStepRange(RejectAny));
+    if (!stepRange.hasRangeLimitations())
         return false;
 
     const Decimal numericValue = parseToNumberOrNaN(value);
     if (!numericValue.isFinite())
         return true;
 
-    StepRange stepRange(createStepRange(RejectAny));
     return numericValue < stepRange.minimum() || numericValue > stepRange.maximum();
 }
 
@@ -405,8 +408,11 @@ String InputType::validationMessage() const
     if (patternMismatch(value))
         return validationMessagePatternMismatchText();
 
+    if (element().tooShort())
+        return validationMessageTooShortText(numGraphemeClusters(value), element().minLength());
+
     if (element().tooLong())
-        return validationMessageTooLongText(numGraphemeClusters(value), element().maxLength());
+        return validationMessageTooLongText(numGraphemeClusters(value), element().effectiveMaxLength());
 
     if (!isSteppable())
         return emptyString();
@@ -431,55 +437,50 @@ String InputType::validationMessage() const
     return emptyString();
 }
 
-void InputType::handleClickEvent(MouseEvent*)
+void InputType::handleClickEvent(MouseEvent&)
 {
 }
 
-void InputType::handleMouseDownEvent(MouseEvent*)
+void InputType::handleMouseDownEvent(MouseEvent&)
 {
 }
 
-void InputType::handleDOMActivateEvent(Event*)
+void InputType::handleDOMActivateEvent(Event&)
 {
 }
 
-void InputType::handleKeydownEvent(KeyboardEvent*)
+void InputType::handleKeydownEvent(KeyboardEvent&)
 {
 }
 
-void InputType::handleKeypressEvent(KeyboardEvent*)
+void InputType::handleKeypressEvent(KeyboardEvent&)
 {
 }
 
-void InputType::handleKeyupEvent(KeyboardEvent*)
+void InputType::handleKeyupEvent(KeyboardEvent&)
 {
 }
 
-void InputType::handleBeforeTextInsertedEvent(BeforeTextInsertedEvent*)
+void InputType::handleBeforeTextInsertedEvent(BeforeTextInsertedEvent&)
 {
 }
 
 #if ENABLE(TOUCH_EVENTS)
-void InputType::handleTouchEvent(TouchEvent*)
+void InputType::handleTouchEvent(TouchEvent&)
 {
 }
 #endif
 
-void InputType::forwardEvent(Event*)
+void InputType::forwardEvent(Event&)
 {
 }
 
-bool InputType::shouldSubmitImplicitly(Event* event)
+bool InputType::shouldSubmitImplicitly(Event& event)
 {
-    return is<KeyboardEvent>(*event) && event->type() == eventNames().keypressEvent && downcast<KeyboardEvent>(*event).charCode() == '\r';
+    return is<KeyboardEvent>(event) && event.type() == eventNames().keypressEvent && downcast<KeyboardEvent>(event).charCode() == '\r';
 }
 
-PassRefPtr<HTMLFormElement> InputType::formForSubmission() const
-{
-    return element().form();
-}
-
-RenderPtr<RenderElement> InputType::createInputRenderer(Ref<RenderStyle>&& style)
+RenderPtr<RenderElement> InputType::createInputRenderer(RenderStyle&& style)
 {
     return RenderPtr<RenderElement>(RenderElement::createFor(element(), WTFMove(style)));
 }
@@ -532,18 +533,18 @@ DateComponents::Type InputType::dateType() const
 }
 #endif
 
-void InputType::dispatchSimulatedClickIfActive(KeyboardEvent* event) const
+void InputType::dispatchSimulatedClickIfActive(KeyboardEvent& event) const
 {
     if (element().active())
-        element().dispatchSimulatedClick(event);
-    event->setDefaultHandled();
+        element().dispatchSimulatedClick(&event);
+    event.setDefaultHandled();
 }
 
 Chrome* InputType::chrome() const
 {
     if (Page* page = element().document().page())
         return &page->chrome();
-    return 0;
+    return nullptr;
 }
 
 bool InputType::canSetStringValue() const
@@ -556,7 +557,7 @@ bool InputType::hasCustomFocusLogic() const
     return true;
 }
 
-bool InputType::isKeyboardFocusable(KeyboardEvent* event) const
+bool InputType::isKeyboardFocusable(KeyboardEvent& event) const
 {
     return !element().isReadOnly() && element().isTextFormControlKeyboardFocusable(event);
 }
@@ -613,11 +614,6 @@ bool InputType::shouldRespectAlignAttribute()
     return false;
 }
 
-bool InputType::canChangeFromAnotherType() const
-{
-    return true;
-}
-
 void InputType::minOrMaxAttributeChanged()
 {
 }
@@ -633,7 +629,7 @@ bool InputType::canBeSuccessfulSubmitButton()
 
 HTMLElement* InputType::placeholderElement() const
 {
-    return 0;
+    return nullptr;
 }
 
 bool InputType::rendererIsNeeded()
@@ -643,10 +639,10 @@ bool InputType::rendererIsNeeded()
 
 FileList* InputType::files()
 {
-    return 0;
+    return nullptr;
 }
 
-void InputType::setFiles(PassRefPtr<FileList>)
+void InputType::setFiles(RefPtr<FileList>&&)
 {
 }
 
@@ -678,7 +674,7 @@ bool InputType::storesValueSeparateFromAttribute()
 void InputType::setValue(const String& sanitizedValue, bool valueChanged, TextFieldEventBehavior eventBehavior)
 {
     element().setValueInternal(sanitizedValue, eventBehavior);
-    element().setNeedsStyleRecalc();
+    element().invalidateStyleForSubtree();
     if (!valueChanged)
         return;
     switch (eventBehavior) {
@@ -728,26 +724,26 @@ String InputType::sanitizeValue(const String& proposedValue) const
 }
 
 #if ENABLE(DRAG_SUPPORT)
+
 bool InputType::receiveDroppedFiles(const DragData&)
 {
     ASSERT_NOT_REACHED();
     return false;
 }
+
 #endif
 
 Icon* InputType::icon() const
 {
     ASSERT_NOT_REACHED();
-    return 0;
+    return nullptr;
 }
 
-#if PLATFORM(IOS)
 String InputType::displayString() const
 {
     ASSERT_NOT_REACHED();
     return String();
 }
-#endif
 
 bool InputType::shouldResetOnDocumentActivation()
 {
@@ -902,7 +898,7 @@ void InputType::updatePlaceholderText()
 {
 }
 
-void InputType::attributeChanged()
+void InputType::attributeChanged(const QualifiedName&)
 {
 }
 
@@ -952,14 +948,19 @@ void InputType::listAttributeTargetChanged()
 {
 }
 
-Decimal InputType::findClosestTickMarkValue(const Decimal&)
+std::optional<Decimal> InputType::findClosestTickMarkValue(const Decimal&)
 {
     ASSERT_NOT_REACHED();
-    return Decimal::nan();
+    return std::nullopt;
 }
 #endif
 
-bool InputType::supportsIndeterminateAppearance() const
+bool InputType::matchesIndeterminatePseudoClass() const
+{
+    return false;
+}
+
+bool InputType::shouldAppearIndeterminate() const
 {
     return false;
 }
@@ -979,48 +980,41 @@ unsigned InputType::width() const
     return 0;
 }
 
-void InputType::applyStep(int count, AnyStepHandling anyStepHandling, TextFieldEventBehavior eventBehavior, ExceptionCode& ec)
+ExceptionOr<void> InputType::applyStep(int count, AnyStepHandling anyStepHandling, TextFieldEventBehavior eventBehavior)
 {
     StepRange stepRange(createStepRange(anyStepHandling));
-    if (!stepRange.hasStep()) {
-        ec = INVALID_STATE_ERR;
-        return;
-    }
+    if (!stepRange.hasStep())
+        return Exception { INVALID_STATE_ERR };
 
     const Decimal current = parseToNumberOrNaN(element().value());
-    if (!current.isFinite()) {
-        ec = INVALID_STATE_ERR;
-        return;
-    }
+    if (!current.isFinite())
+        return Exception { INVALID_STATE_ERR };
     Decimal newValue = current + stepRange.step() * count;
-    if (!newValue.isFinite()) {
-        ec = INVALID_STATE_ERR;
-        return;
-    }
+    if (!newValue.isFinite())
+        return Exception { INVALID_STATE_ERR };
 
     const Decimal acceptableErrorValue = stepRange.acceptableError();
-    if (newValue - stepRange.minimum() < -acceptableErrorValue) {
-        ec = INVALID_STATE_ERR;
-        return;
-    }
+    if (newValue - stepRange.minimum() < -acceptableErrorValue)
+        return Exception { INVALID_STATE_ERR };
     if (newValue < stepRange.minimum())
         newValue = stepRange.minimum();
 
-    const AtomicString& stepString = element().fastGetAttribute(stepAttr);
-    if (!equalIgnoringCase(stepString, "any"))
+    if (!equalLettersIgnoringASCIICase(element().attributeWithoutSynchronization(stepAttr), "any"))
         newValue = stepRange.alignValueForStep(current, newValue);
 
-    if (newValue - stepRange.maximum() > acceptableErrorValue) {
-        ec = INVALID_STATE_ERR;
-        return;
-    }
+    if (newValue - stepRange.maximum() > acceptableErrorValue)
+        return Exception { INVALID_STATE_ERR };
     if (newValue > stepRange.maximum())
         newValue = stepRange.maximum();
 
-    setValueAsDecimal(newValue, eventBehavior, ec);
+    auto result = setValueAsDecimal(newValue, eventBehavior);
+    if (result.hasException())
+        return result;
 
     if (AXObjectCache* cache = element().document().existingAXObjectCache())
         cache->postNotification(&element(), AXObjectCache::AXValueChanged);
+
+    return result;
 }
 
 bool InputType::getAllowedValueStep(Decimal* step) const
@@ -1036,13 +1030,11 @@ StepRange InputType::createStepRange(AnyStepHandling) const
     return StepRange();
 }
 
-void InputType::stepUp(int n, ExceptionCode& ec)
+ExceptionOr<void> InputType::stepUp(int n)
 {
-    if (!isSteppable()) {
-        ec = INVALID_STATE_ERR;
-        return;
-    }
-    applyStep(n, RejectAny, DispatchNoEvent, ec);
+    if (!isSteppable())
+        return Exception { INVALID_STATE_ERR };
+    return applyStep(n, RejectAny, DispatchNoEvent);
 }
 
 void InputType::stepUpFromRenderer(int n)
@@ -1116,10 +1108,10 @@ void InputType::stepUpFromRenderer(int n)
             current = stepRange.minimum() - nextDiff;
         if (current > stepRange.maximum() - nextDiff)
             current = stepRange.maximum() - nextDiff;
-        setValueAsDecimal(current, DispatchNoEvent, IGNORE_EXCEPTION);
+        setValueAsDecimal(current, DispatchNoEvent);
     }
     if ((sign > 0 && current < stepRange.minimum()) || (sign < 0 && current > stepRange.maximum()))
-        setValueAsDecimal(sign > 0 ? stepRange.minimum() : stepRange.maximum(), DispatchInputAndChangeEvent, IGNORE_EXCEPTION);
+        setValueAsDecimal(sign > 0 ? stepRange.minimum() : stepRange.maximum(), DispatchInputAndChangeEvent);
     else {
         if (stepMismatch(element().value())) {
             ASSERT(!step.isZero());
@@ -1137,13 +1129,13 @@ void InputType::stepUpFromRenderer(int n)
             if (newValue > stepRange.maximum())
                 newValue = stepRange.maximum();
 
-            setValueAsDecimal(newValue, n == 1 || n == -1 ? DispatchInputAndChangeEvent : DispatchNoEvent, IGNORE_EXCEPTION);
+            setValueAsDecimal(newValue, n == 1 || n == -1 ? DispatchInputAndChangeEvent : DispatchNoEvent);
             if (n > 1)
-                applyStep(n - 1, AnyIsDefaultStep, DispatchInputAndChangeEvent, IGNORE_EXCEPTION);
+                applyStep(n - 1, AnyIsDefaultStep, DispatchInputAndChangeEvent);
             else if (n < -1)
-                applyStep(n + 1, AnyIsDefaultStep, DispatchInputAndChangeEvent, IGNORE_EXCEPTION);
+                applyStep(n + 1, AnyIsDefaultStep, DispatchInputAndChangeEvent);
         } else
-            applyStep(n, AnyIsDefaultStep, DispatchInputAndChangeEvent, IGNORE_EXCEPTION);
+            applyStep(n, AnyIsDefaultStep, DispatchInputAndChangeEvent);
     }
 }