[WTF] Import std::optional reference implementation as WTF::Optional
[WebKit-https.git] / Source / WebCore / html / RangeInputType.cpp
index 6284ab8..dbabfcd 100644 (file)
 #include "RangeInputType.h"
 
 #include "AXObjectCache.h"
-#include "ExceptionCodePlaceholder.h"
-#include "HTMLDivElement.h"
+#include "EventNames.h"
 #include "HTMLInputElement.h"
-#include "HTMLNames.h"
 #include "HTMLParserIdioms.h"
 #include "InputTypeNames.h"
 #include "KeyboardEvent.h"
 #include "ScopedEventQueue.h"
 #include "ShadowRoot.h"
 #include "SliderThumbElement.h"
-#include "StepRange.h"
 #include <limits>
 #include <wtf/MathExtras.h>
-#include <wtf/PassOwnPtr.h>
+#include <wtf/NeverDestroyed.h>
 
 #if ENABLE(TOUCH_EVENTS)
 #include "Touch.h"
@@ -65,7 +62,6 @@
 namespace WebCore {
 
 using namespace HTMLNames;
-using namespace std;
 
 static const int rangeDefaultMinimum = 0;
 static const int rangeDefaultMaximum = 100;
@@ -78,24 +74,11 @@ static Decimal ensureMaximum(const Decimal& proposedValue, const Decimal& minimu
     return proposedValue >= minimum ? proposedValue : std::max(minimum, fallbackValue);
 }
 
-OwnPtr<InputType> RangeInputType::create(HTMLInputElement& element)
-{
-    return adoptPtr(new RangeInputType(element));
-}
-
 RangeInputType::RangeInputType(HTMLInputElement& element)
     : InputType(element)
-#if ENABLE(DATALIST_ELEMENT)
-    , m_tickMarkValuesDirty(true)
-#endif
 {
 }
 
-void RangeInputType::attach()
-{
-    observeFeatureIfVisible(FeatureObserver::InputTypeRange);
-}
-
 bool RangeInputType::isRangeControl() const
 {
     return true;
@@ -111,9 +94,10 @@ double RangeInputType::valueAsDouble() const
     return parseToDoubleForNumberType(element().value());
 }
 
-void RangeInputType::setValueAsDecimal(const Decimal& newValue, TextFieldEventBehavior eventBehavior, ExceptionCode&) const
+ExceptionOr<void> RangeInputType::setValueAsDecimal(const Decimal& newValue, TextFieldEventBehavior eventBehavior) const
 {
     element().setValue(serialize(newValue), eventBehavior);
+    return { };
 }
 
 bool RangeInputType::typeMismatchFor(const String& value) const
@@ -128,19 +112,19 @@ bool RangeInputType::supportsRequired() const
 
 StepRange RangeInputType::createStepRange(AnyStepHandling anyStepHandling) const
 {
-    DEFINE_STATIC_LOCAL(const StepRange::StepDescription, stepDescription, (rangeDefaultStep, rangeDefaultStepBase, rangeStepScaleFactor));
+    static NeverDestroyed<const StepRange::StepDescription> stepDescription(rangeDefaultStep, rangeDefaultStepBase, rangeStepScaleFactor);
 
-    const Decimal minimum = parseToNumber(element().fastGetAttribute(minAttr), rangeDefaultMinimum);
-    const Decimal maximum = ensureMaximum(parseToNumber(element().fastGetAttribute(maxAttr), rangeDefaultMaximum), minimum, rangeDefaultMaximum);
+    const Decimal minimum = parseToNumber(element().attributeWithoutSynchronization(minAttr), rangeDefaultMinimum);
+    const Decimal maximum = ensureMaximum(parseToNumber(element().attributeWithoutSynchronization(maxAttr), rangeDefaultMaximum), minimum, rangeDefaultMaximum);
 
-    const AtomicString& precisionValue = element().fastGetAttribute(precisionAttr);
+    const AtomicString& precisionValue = element().attributeWithoutSynchronization(precisionAttr);
     if (!precisionValue.isNull()) {
-        const Decimal step = equalIgnoringCase(precisionValue, "float") ? Decimal::nan() : 1;
-        return StepRange(minimum, minimum, maximum, step, stepDescription);
+        const Decimal step = equalLettersIgnoringASCIICase(precisionValue, "float") ? Decimal::nan() : 1;
+        return StepRange(minimum, RangeLimitations::Valid, minimum, maximum, step, stepDescription);
     }
 
-    const Decimal step = StepRange::parseStep(anyStepHandling, stepDescription, element().fastGetAttribute(stepAttr));
-    return StepRange(minimum, minimum, maximum, step, stepDescription);
+    const Decimal step = StepRange::parseStep(anyStepHandling, stepDescription, element().attributeWithoutSynchronization(stepAttr));
+    return StepRange(minimum, RangeLimitations::Valid, minimum, maximum, step, stepDescription);
 }
 
 bool RangeInputType::isSteppable() const
@@ -148,13 +132,14 @@ bool RangeInputType::isSteppable() const
     return true;
 }
 
-void RangeInputType::handleMouseDownEvent(MouseEvent* event)
+#if !PLATFORM(IOS)
+void RangeInputType::handleMouseDownEvent(MouseEvent& event)
 {
     if (element().isDisabledOrReadOnly())
         return;
 
-    Node* targetNode = event->target()->toNode();
-    if (event->button() != LeftButton || !targetNode)
+    Node* targetNode = event.target()->toNode();
+    if (event.button() != LeftButton || !targetNode)
         return;
     ASSERT(element().shadowRoot());
     if (targetNode != &element() && !targetNode->isDescendantOf(element().userAgentShadowRoot()))
@@ -162,41 +147,55 @@ void RangeInputType::handleMouseDownEvent(MouseEvent* event)
     SliderThumbElement& thumb = typedSliderThumbElement();
     if (targetNode == &thumb)
         return;
-    thumb.dragFrom(event->absoluteLocation());
+    thumb.dragFrom(event.absoluteLocation());
 }
+#endif
 
 #if ENABLE(TOUCH_EVENTS)
-#if ENABLE(TOUCH_SLIDER)
-void RangeInputType::handleTouchEvent(TouchEvent* event)
+void RangeInputType::handleTouchEvent(TouchEvent& event)
 {
+#if PLATFORM(IOS)
+    typedSliderThumbElement().handleTouchEvent(event);
+#elif ENABLE(TOUCH_SLIDER)
     if (element().isDisabledOrReadOnly())
         return;
 
-    if (event->type() == eventNames().touchendEvent) {
-        event->setDefaultHandled();
+    if (event.type() == eventNames().touchendEvent) {
+        event.setDefaultHandled();
         return;
     }
 
-    TouchList* touches = event->targetTouches();
+    TouchList* touches = event.targetTouches();
     if (touches->length() == 1) {
         typedSliderThumbElement().setPositionFromPoint(touches->item(0)->absoluteLocation());
-        event->setDefaultHandled();
+        event.setDefaultHandled();
     }
+#else
+    UNUSED_PARAM(event);
+#endif
 }
 
+#if ENABLE(TOUCH_SLIDER)
 bool RangeInputType::hasTouchEventHandler() const
 {
     return true;
 }
 #endif
+
+#if PLATFORM(IOS)
+void RangeInputType::disabledAttributeChanged()
+{
+    typedSliderThumbElement().disabledAttributeChanged();
+}
 #endif
+#endif // ENABLE(TOUCH_EVENTS)
 
-void RangeInputType::handleKeydownEvent(KeyboardEvent* event)
+void RangeInputType::handleKeydownEvent(KeyboardEvent& event)
 {
     if (element().isDisabledOrReadOnly())
         return;
 
-    const String& key = event->keyIdentifier();
+    const String& key = event.keyIdentifier();
 
     const Decimal current = parseToNumberOrNaN(element().value());
     ASSERT(current.isFinite());
@@ -206,12 +205,12 @@ void RangeInputType::handleKeydownEvent(KeyboardEvent* event)
 
     // FIXME: We can't use stepUp() for the step value "any". So, we increase
     // or decrease the value by 1/100 of the value range. Is it reasonable?
-    const Decimal step = equalIgnoringCase(element().fastGetAttribute(stepAttr), "any") ? (stepRange.maximum() - stepRange.minimum()) / 100 : stepRange.step();
-    const Decimal bigStep = max((stepRange.maximum() - stepRange.minimum()) / 10, step);
+    const Decimal step = equalLettersIgnoringASCIICase(element().attributeWithoutSynchronization(stepAttr), "any") ? (stepRange.maximum() - stepRange.minimum()) / 100 : stepRange.step();
+    const Decimal bigStep = std::max((stepRange.maximum() - stepRange.minimum()) / 10, step);
 
     bool isVertical = false;
     if (element().renderer()) {
-        ControlPart part = element().renderer()->style()->appearance();
+        ControlPart part = element().renderer()->style().appearance();
         isVertical = part == SliderVerticalPart || part == MediaVolumeSliderPart;
     }
 
@@ -239,15 +238,13 @@ void RangeInputType::handleKeydownEvent(KeyboardEvent* event)
 
     if (newValue != current) {
         EventQueueScope scope;
-        TextFieldEventBehavior eventBehavior = DispatchChangeEvent;
-        setValueAsDecimal(newValue, eventBehavior, IGNORE_EXCEPTION);
+        setValueAsDecimal(newValue, DispatchInputAndChangeEvent);
 
         if (AXObjectCache* cache = element().document().existingAXObjectCache())
             cache->postNotification(&element(), AXObjectCache::AXValueChanged);
-        element().dispatchFormControlChangeEvent();
     }
 
-    event->setDefaultHandled();
+    event.setDefaultHandled();
 }
 
 void RangeInputType::createShadowSubtree()
@@ -255,12 +252,12 @@ void RangeInputType::createShadowSubtree()
     ASSERT(element().userAgentShadowRoot());
 
     Document& document = element().document();
-    RefPtr<HTMLDivElement> track = HTMLDivElement::create(document);
+    auto track = HTMLDivElement::create(document);
     track->setPseudo(AtomicString("-webkit-slider-runnable-track", AtomicString::ConstructFromLiteral));
-    track->appendChild(SliderThumbElement::create(document), IGNORE_EXCEPTION);
-    RefPtr<HTMLElement> container = SliderContainerElement::create(document);
-    container->appendChild(track.release(), IGNORE_EXCEPTION);
-    element().userAgentShadowRoot()->appendChild(container.release(), IGNORE_EXCEPTION);
+    track->appendChild(SliderThumbElement::create(document));
+    auto container = SliderContainerElement::create(document);
+    container->appendChild(track);
+    element().userAgentShadowRoot()->appendChild(container);
 }
 
 HTMLElement* RangeInputType::sliderTrackElement() const
@@ -270,7 +267,7 @@ HTMLElement* RangeInputType::sliderTrackElement() const
     ASSERT(element().userAgentShadowRoot()->firstChild()->isHTMLElement());
     ASSERT(element().userAgentShadowRoot()->firstChild()->firstChild()); // track
 
-    return &toHTMLElement(*element().userAgentShadowRoot()->firstChild()->firstChild());
+    return downcast<HTMLElement>(element().userAgentShadowRoot()->firstChild()->firstChild());
 }
 
 SliderThumbElement& RangeInputType::typedSliderThumbElement() const
@@ -286,9 +283,9 @@ HTMLElement* RangeInputType::sliderThumbElement() const
     return &typedSliderThumbElement();
 }
 
-RenderElement* RangeInputType::createRenderer(RenderArena& arena, RenderStyle&) const
+RenderPtr<RenderElement> RangeInputType::createInputRenderer(RenderStyle&& style)
 {
-    return new (arena) RenderSlider(&element());
+    return createRenderer<RenderSlider>(element(), WTFMove(style));
 }
 
 Decimal RangeInputType::parseToNumber(const String& src, const Decimal& defaultValue) const
@@ -329,6 +326,9 @@ void RangeInputType::setValue(const String& value, bool valueChanged, TextFieldE
     if (!valueChanged)
         return;
 
+    if (eventBehavior == DispatchNoEvent)
+        element().setTextAsOfLastFormControlChangeEvent(value);
+
     typedSliderThumbElement().setPositionFromValue();
 }
 
@@ -367,12 +367,12 @@ void RangeInputType::updateTickMarkValues()
     HTMLDataListElement* dataList = element().dataList();
     if (!dataList)
         return;
-    RefPtr<HTMLCollection> options = dataList->options();
+    Ref<HTMLCollection> options = dataList->options();
     m_tickMarkValues.reserveCapacity(options->length());
     for (unsigned i = 0; i < options->length(); ++i) {
         Node* node = options->item(i);
-        HTMLOptionElement* optionElement = toHTMLOptionElement(node);
-        String optionValue = optionElement->value();
+        HTMLOptionElement& optionElement = downcast<HTMLOptionElement>(*node);
+        String optionValue = optionElement.value();
         if (!element().isValidValue(optionValue))
             continue;
         m_tickMarkValues.append(parseToNumber(optionValue, Decimal::nan()));
@@ -381,11 +381,11 @@ void RangeInputType::updateTickMarkValues()
     std::sort(m_tickMarkValues.begin(), m_tickMarkValues.end());
 }
 
-Decimal RangeInputType::findClosestTickMarkValue(const Decimal& value)
+std::optional<Decimal> RangeInputType::findClosestTickMarkValue(const Decimal& value)
 {
     updateTickMarkValues();
     if (!m_tickMarkValues.size())
-        return Decimal::nan();
+        return std::nullopt;
 
     size_t left = 0;
     size_t right = m_tickMarkValues.size();
@@ -407,10 +407,18 @@ Decimal RangeInputType::findClosestTickMarkValue(const Decimal& value)
         else
             right = middle;
     }
-    const Decimal closestLeft = middle ? m_tickMarkValues[middle - 1] : Decimal::infinity(Decimal::Negative);
-    const Decimal closestRight = middle != m_tickMarkValues.size() ? m_tickMarkValues[middle] : Decimal::infinity(Decimal::Positive);
-    if (closestRight - value < value - closestLeft)
+
+    std::optional<Decimal> closestLeft = middle ? std::make_optional(m_tickMarkValues[middle - 1]) : std::nullopt;
+    std::optional<Decimal> closestRight = middle != m_tickMarkValues.size() ? std::make_optional(m_tickMarkValues[middle]) : std::nullopt;
+
+    if (!closestLeft)
         return closestRight;
+    if (!closestRight)
+        return closestLeft;
+
+    if (*closestRight - value < value - *closestLeft)
+        return closestRight;
+
     return closestLeft;
 }
 #endif