Improve use of NeverDestroyed
[WebKit-https.git] / Source / WebCore / html / InputType.cpp
index 64d231f..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 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.
@@ -37,8 +37,8 @@
 #include "DateInputType.h"
 #include "DateTimeInputType.h"
 #include "DateTimeLocalInputType.h"
-#include "ElementShadow.h"
 #include "EmailInputType.h"
+#include "EventNames.h"
 #include "ExceptionCode.h"
 #include "FileInputType.h"
 #include "FileList.h"
@@ -48,7 +48,6 @@
 #include "HTMLInputElement.h"
 #include "HTMLNames.h"
 #include "HTMLParserIdioms.h"
-#include "HTMLShadowElement.h"
 #include "HiddenInputType.h"
 #include "ImageInputType.h"
 #include "InputTypeNames.h"
 #include "PasswordInputType.h"
 #include "RadioInputType.h"
 #include "RangeInputType.h"
-#include "RegularExpression.h"
-#include "RenderObject.h"
+#include "RenderElement.h"
 #include "RenderTheme.h"
 #include "ResetInputType.h"
 #include "RuntimeEnabledFeatures.h"
+#include "ScopedEventQueue.h"
 #include "SearchInputType.h"
 #include "ShadowRoot.h"
 #include "SubmitInputType.h"
 #include "TelephoneInputType.h"
-#include "TextBreakIterator.h"
 #include "TextInputType.h"
 #include "TimeInputType.h"
 #include "URLInputType.h"
 #include <wtf/Assertions.h>
 #include <wtf/HashMap.h>
 #include <wtf/text/StringHash.h>
+#include <wtf/text/TextBreakIterator.h>
 
 namespace WebCore {
 
 using namespace HTMLNames;
-using namespace std;
 
-typedef PassOwnPtr<InputType> (*InputTypeFactoryFunction)(HTMLInputElement*);
-typedef HashMap<AtomicString, InputTypeFactoryFunction, CaseFoldingHash> InputTypeFactoryMap;
+typedef bool (RuntimeEnabledFeatures::*InputTypeConditionalFunction)() const;
+typedef const AtomicString& (*InputTypeNameFunction)();
+typedef std::unique_ptr<InputType> (*InputTypeFactoryFunction)(HTMLInputElement&);
+typedef HashMap<AtomicString, InputTypeFactoryFunction, ASCIICaseInsensitiveHash> InputTypeFactoryMap;
 
-static PassOwnPtr<InputTypeFactoryMap> createInputTypeFactoryMap()
+template<class T>
+static std::unique_ptr<InputType> createInputType(HTMLInputElement& element)
 {
-    OwnPtr<InputTypeFactoryMap> map = adoptPtr(new InputTypeFactoryMap);
-    map->add(InputTypeNames::button(), ButtonInputType::create);
-    map->add(InputTypeNames::checkbox(), CheckboxInputType::create);
+    return std::make_unique<T>(element);
+}
+
+static InputTypeFactoryMap createInputTypeFactoryMap()
+{
+    static const struct InputTypes {
+        InputTypeConditionalFunction conditionalFunction;
+        InputTypeNameFunction nameFunction;
+        InputTypeFactoryFunction factoryFunction;
+    } inputTypes[] = {
+        { nullptr, &InputTypeNames::button, &createInputType<ButtonInputType> },
+        { nullptr, &InputTypeNames::checkbox, &createInputType<CheckboxInputType> },
 #if ENABLE(INPUT_TYPE_COLOR)
-    map->add(InputTypeNames::color(), ColorInputType::create);
+        { nullptr, &InputTypeNames::color, &createInputType<ColorInputType> },
 #endif
 #if ENABLE(INPUT_TYPE_DATE)
-    if (RuntimeEnabledFeatures::inputTypeDateEnabled())
-        map->add(InputTypeNames::date(), DateInputType::create);
+        { &RuntimeEnabledFeatures::inputTypeDateEnabled, &InputTypeNames::date, &createInputType<DateInputType> },
 #endif
-#if ENABLE(INPUT_TYPE_DATETIME)
-    if (RuntimeEnabledFeatures::inputTypeDateTimeEnabled())
-        map->add(InputTypeNames::datetime(), DateTimeInputType::create);
+#if ENABLE(INPUT_TYPE_DATETIME_INCOMPLETE)
+        { &RuntimeEnabledFeatures::inputTypeDateTimeEnabled, &InputTypeNames::datetime, &createInputType<DateTimeInputType> },
 #endif
 #if ENABLE(INPUT_TYPE_DATETIMELOCAL)
-    if (RuntimeEnabledFeatures::inputTypeDateTimeLocalEnabled())
-        map->add(InputTypeNames::datetimelocal(), DateTimeLocalInputType::create);
+        { &RuntimeEnabledFeatures::inputTypeDateTimeLocalEnabled, &InputTypeNames::datetimelocal, &createInputType<DateTimeLocalInputType> },
 #endif
-    map->add(InputTypeNames::email(), EmailInputType::create);
-    map->add(InputTypeNames::file(), FileInputType::create);
-    map->add(InputTypeNames::hidden(), HiddenInputType::create);
-    map->add(InputTypeNames::image(), ImageInputType::create);
+        { nullptr, &InputTypeNames::email, &createInputType<EmailInputType> },
+        { nullptr, &InputTypeNames::file, &createInputType<FileInputType> },
+        { nullptr, &InputTypeNames::hidden, &createInputType<HiddenInputType> },
+        { nullptr, &InputTypeNames::image, &createInputType<ImageInputType> },
 #if ENABLE(INPUT_TYPE_MONTH)
-    if (RuntimeEnabledFeatures::inputTypeMonthEnabled())
-        map->add(InputTypeNames::month(), MonthInputType::create);
+        { &RuntimeEnabledFeatures::inputTypeMonthEnabled, &InputTypeNames::month, &createInputType<MonthInputType> },
 #endif
-    map->add(InputTypeNames::number(), NumberInputType::create);
-    map->add(InputTypeNames::password(), PasswordInputType::create);
-    map->add(InputTypeNames::radio(), RadioInputType::create);
-    map->add(InputTypeNames::range(), RangeInputType::create);
-    map->add(InputTypeNames::reset(), ResetInputType::create);
-    map->add(InputTypeNames::search(), SearchInputType::create);
-    map->add(InputTypeNames::submit(), SubmitInputType::create);
-    map->add(InputTypeNames::telephone(), TelephoneInputType::create);
+        { nullptr, &InputTypeNames::number, &createInputType<NumberInputType> },
+        { nullptr, &InputTypeNames::password, &createInputType<PasswordInputType> },
+        { nullptr, &InputTypeNames::radio, &createInputType<RadioInputType> },
+        { nullptr, &InputTypeNames::range, &createInputType<RangeInputType> },
+        { nullptr, &InputTypeNames::reset, &createInputType<ResetInputType> },
+        { nullptr, &InputTypeNames::search, &createInputType<SearchInputType> },
+        { nullptr, &InputTypeNames::submit, &createInputType<SubmitInputType> },
+        { nullptr, &InputTypeNames::telephone, &createInputType<TelephoneInputType> },
 #if ENABLE(INPUT_TYPE_TIME)
-    if (RuntimeEnabledFeatures::inputTypeTimeEnabled())
-        map->add(InputTypeNames::time(), TimeInputType::create);
+        { &RuntimeEnabledFeatures::inputTypeTimeEnabled, &InputTypeNames::time, &createInputType<TimeInputType> },
 #endif
-    map->add(InputTypeNames::url(), URLInputType::create);
+        { nullptr, &InputTypeNames::url, &createInputType<URLInputType> },
 #if ENABLE(INPUT_TYPE_WEEK)
-    if (RuntimeEnabledFeatures::inputTypeWeekEnabled())
-        map->add(InputTypeNames::week(), WeekInputType::create);
+        { &RuntimeEnabledFeatures::inputTypeWeekEnabled, &InputTypeNames::week, &createInputType<WeekInputType> },
 #endif
-    // No need to register "text" because it is the default type.
-    return map.release();
+        // 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;
 }
 
-PassOwnPtr<InputType> InputType::create(HTMLInputElement* element, const AtomicString& typeName)
+std::unique_ptr<InputType> InputType::create(HTMLInputElement& element, const AtomicString& typeName)
 {
-    static const InputTypeFactoryMap* factoryMap = createInputTypeFactoryMap().leakPtr();
-    PassOwnPtr<InputType> (*factory)(HTMLInputElement*) = typeName.isEmpty() ? 0 : factoryMap->get(typeName);
-    if (!factory)
-        factory = TextInputType::create;
-    return factory(element);
+    if (!typeName.isEmpty()) {
+        static const auto factoryMap = makeNeverDestroyed(createInputTypeFactoryMap());
+        if (auto factory = factoryMap.get().get(typeName))
+            return factory(element);
+    }
+    return std::make_unique<TextInputType>(element);
 }
 
-PassOwnPtr<InputType> InputType::createText(HTMLInputElement* element)
+std::unique_ptr<InputType> InputType::createText(HTMLInputElement& element)
 {
-    return TextInputType::create(element);
+    return std::make_unique<TextInputType>(element);
 }
 
 InputType::~InputType()
@@ -157,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
@@ -184,27 +195,27 @@ bool InputType::shouldSaveAndRestoreFormControlState() const
 
 FormControlState InputType::saveFormControlState() const
 {
-    String currentValue = element()->value();
-    if (currentValue == element()->defaultValue())
+    String currentValue = element().value();
+    if (currentValue == element().defaultValue())
         return FormControlState();
     return FormControlState(currentValue);
 }
 
 void InputType::restoreFormControlState(const FormControlState& state)
 {
-    element()->setValue(state[0]);
+    element().setValue(state[0]);
 }
 
 bool InputType::isFormDataAppendable() const
 {
     // There is no form data unless there's a name for non-image types.
-    return !element()->name().isEmpty();
+    return !element().name().isEmpty();
 }
 
 bool InputType::appendFormData(FormDataList& encoding, bool) const
 {
     // Always successful.
-    encoding.appendData(element()->name(), element()->value());
+    encoding.appendData(element().name(), element().value());
     return true;
 }
 
@@ -213,24 +224,24 @@ 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
 {
-    return numeric_limits<double>::quiet_NaN();
+    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
@@ -310,33 +321,44 @@ double InputType::maximum() const
 
 bool InputType::sizeShouldIncludeDecoration(int, int& preferredSize) const
 {
-    preferredSize = element()->size();
+    preferredSize = element().size();
     return false;
 }
 
+float InputType::decorationWidth() const
+{
+    return 0;
+}
+
 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();
 }
 
@@ -370,24 +392,27 @@ String InputType::valueMissingText() const
 
 String InputType::validationMessage() const
 {
-    const String value = element()->value();
+    String value = element().value();
 
     // The order of the following checks is meaningful. e.g. We'd like to show the
-    // valueMissing message even if the control has other validation errors.
+    // badInput message even if the control has other validation errors.
+    if (hasBadInput())
+        return badInputText();
+
     if (valueMissing(value))
         return valueMissingText();
 
     if (typeMismatch())
         return typeMismatchText();
 
-    if (hasBadInput())
-        return badInputText();
-
     if (patternMismatch(value))
         return validationMessagePatternMismatchText();
 
-    if (element()->tooLong())
-        return validationMessageTooLongText(numGraphemeClusters(value), element()->maxLength());
+    if (element().tooShort())
+        return validationMessageTooShortText(numGraphemeClusters(value), element().minLength());
+
+    if (element().tooLong())
+        return validationMessageTooLongText(numGraphemeClusters(value), element().effectiveMaxLength());
 
     if (!isSteppable())
         return emptyString();
@@ -412,67 +437,57 @@ 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 event->isKeyboardEvent() && event->type() == eventNames().keypressEvent && static_cast<KeyboardEvent*>(event)->charCode() == '\r';
+    return is<KeyboardEvent>(event) && event.type() == eventNames().keypressEvent && downcast<KeyboardEvent>(event).charCode() == '\r';
 }
 
-PassRefPtr<HTMLFormElement> InputType::formForSubmission() const
+RenderPtr<RenderElement> InputType::createInputRenderer(RenderStyle&& style)
 {
-    return element()->form();
-}
-
-RenderObject* InputType::createRenderer(RenderArena*, RenderStyle* style) const
-{
-    return RenderObject::createObject(element(), style);
+    return RenderPtr<RenderElement>(RenderElement::createFor(element(), WTFMove(style)));
 }
 
 void InputType::blur()
 {
-    element()->defaultBlur();
-}
-
-bool InputType::willCancelFocus(bool, FocusDirection)
-{
-    return false;
+    element().defaultBlur();
 }
 
 void InputType::createShadowSubtree()
@@ -481,23 +496,11 @@ void InputType::createShadowSubtree()
 
 void InputType::destroyShadowSubtree()
 {
-    ShadowRoot* root = element()->userAgentShadowRoot();
+    ShadowRoot* root = element().userAgentShadowRoot();
     if (!root)
         return;
 
     root->removeChildren();
-
-    // It's ok to clear contents of all other ShadowRoots because they must have
-    // been created by TextFieldDecorationElement, and we don't allow adding
-    // AuthorShadowRoot to HTMLInputElement.
-    while ((root = root->youngerShadowRoot())) {
-#if ENABLE(SHADOW_DOM)
-        root->removeChildren();
-        root->appendChild(HTMLShadowElement::create(shadowTag, element()->document()));
-#else
-        ASSERT_NOT_REACHED();
-#endif
-    }
 }
 
 Decimal InputType::parseToNumber(const String&, const Decimal& defaultValue) const
@@ -523,18 +526,25 @@ String InputType::serialize(const Decimal&) const
     return String();
 }
 
-void InputType::dispatchSimulatedClickIfActive(KeyboardEvent* event) const
+#if PLATFORM(IOS)
+DateComponents::Type InputType::dateType() const
+{
+    return DateComponents::Invalid;
+}
+#endif
+
+void InputType::dispatchSimulatedClickIfActive(KeyboardEvent& event) const
 {
-    if (element()->active())
-        element()->dispatchSimulatedClick(event);
-    event->setDefaultHandled();
+    if (element().active())
+        element().dispatchSimulatedClick(&event);
+    event.setDefaultHandled();
 }
 
 Chrome* InputType::chrome() const
 {
-    if (Page* page = element()->document()->page())
-        return page->chrome();
-    return 0;
+    if (Page* page = element().document().page())
+        return &page->chrome();
+    return nullptr;
 }
 
 bool InputType::canSetStringValue() const
@@ -547,14 +557,14 @@ bool InputType::hasCustomFocusLogic() const
     return true;
 }
 
-bool InputType::isKeyboardFocusable(KeyboardEvent* event) const
+bool InputType::isKeyboardFocusable(KeyboardEvent& event) const
 {
-    return element()->isTextFormControlKeyboardFocusable(event);
+    return !element().isReadOnly() && element().isTextFormControlKeyboardFocusable(event);
 }
 
 bool InputType::isMouseFocusable() const
 {
-    return element()->isTextFormControlMouseFocusable();
+    return element().isTextFormControlMouseFocusable();
 }
 
 bool InputType::shouldUseInputMethod() const
@@ -562,7 +572,7 @@ bool InputType::shouldUseInputMethod() const
     return false;
 }
 
-void InputType::handleFocusEvent(FocusDirection)
+void InputType::handleFocusEvent(Node*, FocusDirection)
 {
 }
 
@@ -572,7 +582,7 @@ void InputType::handleBlurEvent()
 
 void InputType::accessKeyAction(bool)
 {
-    element()->focus(false);
+    element().focus(false);
 }
 
 void InputType::addSearchResult()
@@ -595,7 +605,7 @@ void InputType::srcAttributeChanged()
 {
 }
 
-void InputType::willMoveToNewOwnerDocument()
+void InputType::maxResultsAttributeChanged()
 {
 }
 
@@ -604,11 +614,6 @@ bool InputType::shouldRespectAlignAttribute()
     return false;
 }
 
-bool InputType::canChangeFromAnotherType() const
-{
-    return true;
-}
-
 void InputType::minOrMaxAttributeChanged()
 {
 }
@@ -624,7 +629,7 @@ bool InputType::canBeSuccessfulSubmitButton()
 
 HTMLElement* InputType::placeholderElement() const
 {
-    return 0;
+    return nullptr;
 }
 
 bool InputType::rendererIsNeeded()
@@ -634,10 +639,10 @@ bool InputType::rendererIsNeeded()
 
 FileList* InputType::files()
 {
-    return 0;
+    return nullptr;
 }
 
-void InputType::setFiles(PassRefPtr<FileList>)
+void InputType::setFiles(RefPtr<FileList>&&)
 {
 }
 
@@ -656,11 +661,6 @@ String InputType::defaultValue() const
     return String();
 }
 
-bool InputType::canSetSuggestedValue()
-{
-    return false;
-}
-
 bool InputType::shouldSendChangeEventAfterCheckedChanged()
 {
     return true;
@@ -673,17 +673,17 @@ bool InputType::storesValueSeparateFromAttribute()
 
 void InputType::setValue(const String& sanitizedValue, bool valueChanged, TextFieldEventBehavior eventBehavior)
 {
-    element()->setValueInternal(sanitizedValue, eventBehavior);
-    element()->setNeedsStyleRecalc();
+    element().setValueInternal(sanitizedValue, eventBehavior);
+    element().invalidateStyleForSubtree();
     if (!valueChanged)
         return;
     switch (eventBehavior) {
     case DispatchChangeEvent:
-        element()->dispatchFormControlChangeEvent();
+        element().dispatchFormControlChangeEvent();
         break;
     case DispatchInputAndChangeEvent:
-        element()->dispatchFormControlInputEvent();
-        element()->dispatchFormControlChangeEvent();
+        element().dispatchFormControlInputEvent();
+        element().dispatchFormControlChangeEvent();
         break;
     case DispatchNoEvent:
         break;
@@ -695,12 +695,11 @@ bool InputType::canSetValue(const String&)
     return true;
 }
 
-PassOwnPtr<ClickHandlingState> InputType::willDispatchClick()
+void InputType::willDispatchClick(InputElementClickState&)
 {
-    return nullptr;
 }
 
-void InputType::didDispatchClick(Event*, const ClickHandlingState&)
+void InputType::didDispatchClick(Event*, const InputElementClickState&)
 {
 }
 
@@ -711,7 +710,12 @@ String InputType::localizeValue(const String& proposedValue) const
 
 String InputType::visibleValue() const
 {
-    return element()->value();
+    return element().value();
+}
+
+bool InputType::isEmptyValue() const
+{
+    return true;
 }
 
 String InputType::sanitizeValue(const String& proposedValue) const
@@ -719,29 +723,26 @@ String InputType::sanitizeValue(const String& proposedValue) const
     return proposedValue;
 }
 
-bool InputType::receiveDroppedFiles(const DragData*)
+#if ENABLE(DRAG_SUPPORT)
+
+bool InputType::receiveDroppedFiles(const DragData&)
 {
     ASSERT_NOT_REACHED();
     return false;
 }
 
-#if ENABLE(FILE_SYSTEM)
-String InputType::droppedFileSystemId()
-{
-    ASSERT_NOT_REACHED();
-    return String();
-}
 #endif
 
 Icon* InputType::icon() const
 {
     ASSERT_NOT_REACHED();
-    return 0;
+    return nullptr;
 }
 
-bool InputType::shouldApplyLocaleDirection() const
+String InputType::displayString() const
 {
-    return false;
+    ASSERT_NOT_REACHED();
+    return String();
 }
 
 bool InputType::shouldResetOnDocumentActivation()
@@ -754,11 +755,6 @@ bool InputType::shouldRespectListAttribute()
     return false;
 }
 
-bool InputType::shouldRespectSpeechAttribute()
-{
-    return false;
-}
-
 bool InputType::isTextButton() const
 {
     return false;
@@ -874,12 +870,10 @@ bool InputType::isSteppable() const
     return false;
 }
 
-#if ENABLE(INPUT_TYPE_COLOR)
 bool InputType::isColorControl() const
 {
     return false;
 }
-#endif
 
 bool InputType::shouldRespectHeightAndWidthAttributes()
 {
@@ -904,6 +898,10 @@ void InputType::updatePlaceholderText()
 {
 }
 
+void InputType::attributeChanged(const QualifiedName&)
+{
+}
+
 void InputType::multipleAttributeChanged()
 {
 }
@@ -916,6 +914,18 @@ void InputType::readonlyAttributeChanged()
 {
 }
 
+void InputType::requiredAttributeChanged()
+{
+}
+
+void InputType::capsLockStateMayHaveChanged()
+{
+}
+
+void InputType::updateAutoFillButton()
+{
+}
+
 void InputType::subtreeHasChanged()
 {
     ASSERT_NOT_REACHED();
@@ -938,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;
 }
@@ -965,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;
-    }
+    const Decimal current = parseToNumberOrNaN(element().value());
+    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);
 
-    if (AXObjectCache::accessibilityEnabled())
-         element()->document()->axObjectCache()->postNotification(element(), AXObjectCache::AXValueChanged, true);
+    return result;
 }
 
 bool InputType::getAllowedValueStep(Decimal* step) const
@@ -1022,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)
@@ -1048,7 +1054,7 @@ void InputType::stepUpFromRenderer(int n)
     //   * If 0 is in-range, but not matched to step value
     //     - The value should be the larger matched value nearest to 0 if n > 0
     //       e.g. <input type=number min=-100 step=3> -> 2
-    //     - The value should be the smaler matched value nearest to 0 if n < 0
+    //     - The value should be the smaller matched value nearest to 0 if n < 0
     //       e.g. <input type=number min=-100 step=3> -> -1
     //   As for date/datetime-local/month/time/week types, the current value is assumed as "the current local date/time".
     //   As for datetime type, the current value is assumed as "the current date/time in UTC".
@@ -1063,7 +1069,7 @@ void InputType::stepUpFromRenderer(int n)
     // If the current value is not matched to step value:
     // - The value should be the larger matched value nearest to 0 if n > 0
     //   e.g. <input type=number value=3 min=-100 step=3> -> 5
-    // - The value should be the smaler matched value nearest to 0 if n < 0
+    // - The value should be the smaller matched value nearest to 0 if n < 0
     //   e.g. <input type=number value=3 min=-100 step=3> -> 2
     //
     // n is assumed as -n if step < 0.
@@ -1082,6 +1088,7 @@ void InputType::stepUpFromRenderer(int n)
     if (!stepRange.hasStep())
       return;
 
+    EventQueueScope scope;
     const Decimal step = stepRange.step();
 
     int sign;
@@ -1092,24 +1099,21 @@ void InputType::stepUpFromRenderer(int n)
     else
         sign = 0;
 
-    String currentStringValue = element()->value();
+    String currentStringValue = element().value();
     Decimal current = parseToNumberOrNaN(currentStringValue);
     if (!current.isFinite()) {
-        ExceptionCode ec;
         current = defaultValueForStepUp();
         const Decimal nextDiff = step * n;
         if (current < stepRange.minimum() - nextDiff)
             current = stepRange.minimum() - nextDiff;
         if (current > stepRange.maximum() - nextDiff)
             current = stepRange.maximum() - nextDiff;
-        setValueAsDecimal(current, DispatchInputAndChangeEvent, ec);
+        setValueAsDecimal(current, DispatchNoEvent);
     }
-    if ((sign > 0 && current < stepRange.minimum()) || (sign < 0 && current > stepRange.maximum())) {
-        ExceptionCode ec;
-        setValueAsDecimal(sign > 0 ? stepRange.minimum() : stepRange.maximum(), DispatchInputAndChangeEvent, ec);
-    } else {
-        ExceptionCode ec;
-        if (stepMismatch(element()->value())) {
+    if ((sign > 0 && current < stepRange.minimum()) || (sign < 0 && current > stepRange.maximum()))
+        setValueAsDecimal(sign > 0 ? stepRange.minimum() : stepRange.maximum(), DispatchInputAndChangeEvent);
+    else {
+        if (stepMismatch(element().value())) {
             ASSERT(!step.isZero());
             const Decimal base = stepRange.stepBase();
             Decimal newValue;
@@ -1125,22 +1129,23 @@ void InputType::stepUpFromRenderer(int n)
             if (newValue > stepRange.maximum())
                 newValue = stepRange.maximum();
 
-            setValueAsDecimal(newValue, n == 1 || n == -1 ? DispatchInputAndChangeEvent : DispatchNoEvent, ec);
+            setValueAsDecimal(newValue, n == 1 || n == -1 ? DispatchInputAndChangeEvent : DispatchNoEvent);
             if (n > 1)
-                applyStep(n - 1, AnyIsDefaultStep, DispatchInputAndChangeEvent, ec);
+                applyStep(n - 1, AnyIsDefaultStep, DispatchInputAndChangeEvent);
             else if (n < -1)
-                applyStep(n + 1, AnyIsDefaultStep, DispatchInputAndChangeEvent, ec);
+                applyStep(n + 1, AnyIsDefaultStep, DispatchInputAndChangeEvent);
         } else
-            applyStep(n, AnyIsDefaultStep, DispatchInputAndChangeEvent, ec);
+            applyStep(n, AnyIsDefaultStep, DispatchInputAndChangeEvent);
     }
 }
 
-void InputType::observeFeatureIfVisible(FeatureObserver::Feature feature) const
+Color InputType::valueAsColor() const
+{
+    return Color::transparent;
+}
+
+void InputType::selectColor(const Color&)
 {
-    if (RenderStyle* style = element()->renderStyle()) {
-        if (style->visibility() != HIDDEN)
-            FeatureObserver::observe(element()->document(), feature);
-    }
 }
 
 } // namespace WebCore