| Index: Source/core/html/RangeInputType.cpp
|
| diff --git a/Source/core/html/RangeInputType.cpp b/Source/core/html/RangeInputType.cpp
|
| deleted file mode 100644
|
| index 08f3608850508f43f3175cc749390ad67a47cdf8..0000000000000000000000000000000000000000
|
| --- a/Source/core/html/RangeInputType.cpp
|
| +++ /dev/null
|
| @@ -1,396 +0,0 @@
|
| -/*
|
| - * Copyright (C) 2010 Google Inc. All rights reserved.
|
| - * Copyright (C) 2011 Apple Inc. All rights reserved.
|
| - *
|
| - * Redistribution and use in source and binary forms, with or without
|
| - * modification, are permitted provided that the following conditions are
|
| - * met:
|
| - *
|
| - * * Redistributions of source code must retain the above copyright
|
| - * notice, this list of conditions and the following disclaimer.
|
| - * * Redistributions in binary form must reproduce the above
|
| - * copyright notice, this list of conditions and the following disclaimer
|
| - * in the documentation and/or other materials provided with the
|
| - * distribution.
|
| - * * Neither the name of Google Inc. nor the names of its
|
| - * contributors may be used to endorse or promote products derived from
|
| - * this software without specific prior written permission.
|
| - *
|
| - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
| - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
| - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
| - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
| - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
| - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
| - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
| - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
| - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
| - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| - */
|
| -
|
| -#include "config.h"
|
| -#include "core/html/RangeInputType.h"
|
| -
|
| -#include <limits>
|
| -#include "HTMLNames.h"
|
| -#include "bindings/v8/ExceptionStatePlaceholder.h"
|
| -#include "core/accessibility/AXObjectCache.h"
|
| -#include "core/dom/KeyboardEvent.h"
|
| -#include "core/dom/MouseEvent.h"
|
| -#include "core/dom/ScopedEventQueue.h"
|
| -#include "core/dom/Touch.h"
|
| -#include "core/dom/TouchEvent.h"
|
| -#include "core/dom/TouchList.h"
|
| -#include "core/dom/shadow/ShadowRoot.h"
|
| -#include "core/html/HTMLDataListElement.h"
|
| -#include "core/html/HTMLDivElement.h"
|
| -#include "core/html/HTMLInputElement.h"
|
| -#include "core/html/HTMLOptionElement.h"
|
| -#include "core/html/InputTypeNames.h"
|
| -#include "core/html/StepRange.h"
|
| -#include "core/html/parser/HTMLParserIdioms.h"
|
| -#include "core/html/shadow/ShadowElementNames.h"
|
| -#include "core/html/shadow/SliderThumbElement.h"
|
| -#include "core/platform/PlatformMouseEvent.h"
|
| -#include "core/rendering/RenderSlider.h"
|
| -#include "wtf/MathExtras.h"
|
| -#include "wtf/NonCopyingSort.h"
|
| -#include "wtf/PassOwnPtr.h"
|
| -
|
| -namespace WebCore {
|
| -
|
| -using namespace HTMLNames;
|
| -using namespace std;
|
| -
|
| -static const int rangeDefaultMinimum = 0;
|
| -static const int rangeDefaultMaximum = 100;
|
| -static const int rangeDefaultStep = 1;
|
| -static const int rangeDefaultStepBase = 0;
|
| -static const int rangeStepScaleFactor = 1;
|
| -
|
| -static Decimal ensureMaximum(const Decimal& proposedValue, const Decimal& minimum, const Decimal& fallbackValue)
|
| -{
|
| - return proposedValue >= minimum ? proposedValue : std::max(minimum, fallbackValue);
|
| -}
|
| -
|
| -PassRefPtr<InputType> RangeInputType::create(HTMLInputElement* element)
|
| -{
|
| - return adoptRef(new RangeInputType(element));
|
| -}
|
| -
|
| -RangeInputType::RangeInputType(HTMLInputElement* element)
|
| - : InputType(element)
|
| - , m_tickMarkValuesDirty(true)
|
| -{
|
| -}
|
| -
|
| -void RangeInputType::countUsage()
|
| -{
|
| - observeFeatureIfVisible(UseCounter::InputTypeRange);
|
| -}
|
| -
|
| -bool RangeInputType::isRangeControl() const
|
| -{
|
| - return true;
|
| -}
|
| -
|
| -const AtomicString& RangeInputType::formControlType() const
|
| -{
|
| - return InputTypeNames::range();
|
| -}
|
| -
|
| -double RangeInputType::valueAsDouble() const
|
| -{
|
| - return parseToDoubleForNumberType(element()->value());
|
| -}
|
| -
|
| -void RangeInputType::setValueAsDecimal(const Decimal& newValue, TextFieldEventBehavior eventBehavior, ExceptionState&) const
|
| -{
|
| - element()->setValue(serialize(newValue), eventBehavior);
|
| -}
|
| -
|
| -bool RangeInputType::typeMismatchFor(const String& value) const
|
| -{
|
| - return !value.isEmpty() && !std::isfinite(parseToDoubleForNumberType(value));
|
| -}
|
| -
|
| -bool RangeInputType::supportsRequired() const
|
| -{
|
| - return false;
|
| -}
|
| -
|
| -StepRange RangeInputType::createStepRange(AnyStepHandling anyStepHandling) const
|
| -{
|
| - DEFINE_STATIC_LOCAL(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 AtomicString& precisionValue = element()->fastGetAttribute(precisionAttr);
|
| - if (!precisionValue.isNull()) {
|
| - const Decimal step = equalIgnoringCase(precisionValue, "float") ? Decimal::nan() : 1;
|
| - return StepRange(minimum, minimum, maximum, step, stepDescription);
|
| - }
|
| -
|
| - const Decimal step = StepRange::parseStep(anyStepHandling, stepDescription, element()->fastGetAttribute(stepAttr));
|
| - return StepRange(minimum, minimum, maximum, step, stepDescription);
|
| -}
|
| -
|
| -bool RangeInputType::isSteppable() const
|
| -{
|
| - return true;
|
| -}
|
| -
|
| -void RangeInputType::handleMouseDownEvent(MouseEvent* event)
|
| -{
|
| - if (element()->isDisabledOrReadOnly())
|
| - return;
|
| -
|
| - Node* targetNode = event->target()->toNode();
|
| - if (event->button() != LeftButton || !targetNode)
|
| - return;
|
| - ASSERT(element()->shadow());
|
| - if (targetNode != element() && !targetNode->isDescendantOf(element()->userAgentShadowRoot()))
|
| - return;
|
| - SliderThumbElement* thumb = sliderThumbElement();
|
| - if (targetNode == thumb)
|
| - return;
|
| - thumb->dragFrom(event->absoluteLocation());
|
| -}
|
| -
|
| -void RangeInputType::handleTouchEvent(TouchEvent* event)
|
| -{
|
| - if (element()->isDisabledOrReadOnly())
|
| - return;
|
| -
|
| - if (event->type() == eventNames().touchendEvent) {
|
| - event->setDefaultHandled();
|
| - return;
|
| - }
|
| -
|
| - TouchList* touches = event->targetTouches();
|
| - if (touches->length() == 1) {
|
| - sliderThumbElement()->setPositionFromPoint(touches->item(0)->absoluteLocation());
|
| - event->setDefaultHandled();
|
| - }
|
| -}
|
| -
|
| -bool RangeInputType::hasTouchEventHandler() const
|
| -{
|
| - return true;
|
| -}
|
| -
|
| -void RangeInputType::handleKeydownEvent(KeyboardEvent* event)
|
| -{
|
| - if (element()->isDisabledOrReadOnly())
|
| - return;
|
| -
|
| - const String& key = event->keyIdentifier();
|
| -
|
| - const Decimal current = parseToNumberOrNaN(element()->value());
|
| - ASSERT(current.isFinite());
|
| -
|
| - StepRange stepRange(createStepRange(RejectAny));
|
| -
|
| -
|
| - // 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);
|
| -
|
| - bool isVertical = false;
|
| - if (element()->renderer()) {
|
| - ControlPart part = element()->renderer()->style()->appearance();
|
| - isVertical = part == SliderVerticalPart || part == MediaVolumeSliderPart;
|
| - }
|
| -
|
| - Decimal newValue;
|
| - if (key == "Up")
|
| - newValue = current + step;
|
| - else if (key == "Down")
|
| - newValue = current - step;
|
| - else if (key == "Left")
|
| - newValue = isVertical ? current + step : current - step;
|
| - else if (key == "Right")
|
| - newValue = isVertical ? current - step : current + step;
|
| - else if (key == "PageUp")
|
| - newValue = current + bigStep;
|
| - else if (key == "PageDown")
|
| - newValue = current - bigStep;
|
| - else if (key == "Home")
|
| - newValue = isVertical ? stepRange.maximum() : stepRange.minimum();
|
| - else if (key == "End")
|
| - newValue = isVertical ? stepRange.minimum() : stepRange.maximum();
|
| - else
|
| - return; // Did not match any key binding.
|
| -
|
| - newValue = stepRange.clampValue(newValue);
|
| -
|
| - if (newValue != current) {
|
| - EventQueueScope scope;
|
| - TextFieldEventBehavior eventBehavior = DispatchChangeEvent;
|
| - setValueAsDecimal(newValue, eventBehavior, IGNORE_EXCEPTION);
|
| -
|
| - if (AXObjectCache* cache = element()->document().existingAXObjectCache())
|
| - cache->postNotification(element(), AXObjectCache::AXValueChanged, true);
|
| - element()->dispatchFormControlChangeEvent();
|
| - }
|
| -
|
| - event->setDefaultHandled();
|
| -}
|
| -
|
| -void RangeInputType::createShadowSubtree()
|
| -{
|
| - ASSERT(element()->shadow());
|
| -
|
| - Document& document = element()->document();
|
| - RefPtr<HTMLDivElement> track = HTMLDivElement::create(document);
|
| - track->setPart(AtomicString("-webkit-slider-runnable-track", AtomicString::ConstructFromLiteral));
|
| - track->setAttribute(idAttr, ShadowElementNames::sliderTrack());
|
| - track->appendChild(SliderThumbElement::create(document));
|
| - RefPtr<HTMLElement> container = SliderContainerElement::create(document);
|
| - container->appendChild(track.release());
|
| - element()->userAgentShadowRoot()->appendChild(container.release());
|
| -}
|
| -
|
| -RenderObject* RangeInputType::createRenderer(RenderStyle*) const
|
| -{
|
| - return new RenderSlider(element());
|
| -}
|
| -
|
| -Decimal RangeInputType::parseToNumber(const String& src, const Decimal& defaultValue) const
|
| -{
|
| - return parseToDecimalForNumberType(src, defaultValue);
|
| -}
|
| -
|
| -String RangeInputType::serialize(const Decimal& value) const
|
| -{
|
| - if (!value.isFinite())
|
| - return String();
|
| - return serializeForNumberType(value);
|
| -}
|
| -
|
| -// FIXME: Could share this with BaseClickableWithKeyInputType and BaseCheckableInputType if we had a common base class.
|
| -void RangeInputType::accessKeyAction(bool sendMouseEvents)
|
| -{
|
| - InputType::accessKeyAction(sendMouseEvents);
|
| -
|
| - element()->dispatchSimulatedClick(0, sendMouseEvents ? SendMouseUpDownEvents : SendNoEvents);
|
| -}
|
| -
|
| -void RangeInputType::sanitizeValueInResponseToMinOrMaxAttributeChange()
|
| -{
|
| - if (element()->hasDirtyValue())
|
| - element()->setValue(element()->value());
|
| -
|
| - sliderThumbElement()->setPositionFromValue();
|
| -}
|
| -
|
| -void RangeInputType::setValue(const String& value, bool valueChanged, TextFieldEventBehavior eventBehavior)
|
| -{
|
| - InputType::setValue(value, valueChanged, eventBehavior);
|
| -
|
| - if (!valueChanged)
|
| - return;
|
| -
|
| - sliderThumbElement()->setPositionFromValue();
|
| -}
|
| -
|
| -String RangeInputType::fallbackValue() const
|
| -{
|
| - return serializeForNumberType(createStepRange(RejectAny).defaultValue());
|
| -}
|
| -
|
| -String RangeInputType::sanitizeValue(const String& proposedValue) const
|
| -{
|
| - StepRange stepRange(createStepRange(RejectAny));
|
| - const Decimal proposedNumericValue = parseToNumber(proposedValue, stepRange.defaultValue());
|
| - return serializeForNumberType(stepRange.clampValue(proposedNumericValue));
|
| -}
|
| -
|
| -bool RangeInputType::shouldRespectListAttribute()
|
| -{
|
| - return InputType::themeSupportsDataListUI(this);
|
| -}
|
| -
|
| -inline SliderThumbElement* RangeInputType::sliderThumbElement() const
|
| -{
|
| - return toSliderThumbElement(element()->userAgentShadowRoot()->getElementById(ShadowElementNames::sliderThumb()));
|
| -}
|
| -
|
| -inline Element* RangeInputType::sliderTrackElement() const
|
| -{
|
| - return element()->userAgentShadowRoot()->getElementById(ShadowElementNames::sliderTrack());
|
| -}
|
| -
|
| -void RangeInputType::listAttributeTargetChanged()
|
| -{
|
| - m_tickMarkValuesDirty = true;
|
| - Element* sliderTrackElement = this->sliderTrackElement();
|
| - if (sliderTrackElement->renderer())
|
| - sliderTrackElement->renderer()->setNeedsLayout();
|
| -}
|
| -
|
| -static bool decimalCompare(const Decimal& a, const Decimal& b)
|
| -{
|
| - return a < b;
|
| -}
|
| -
|
| -void RangeInputType::updateTickMarkValues()
|
| -{
|
| - if (!m_tickMarkValuesDirty)
|
| - return;
|
| - m_tickMarkValues.clear();
|
| - m_tickMarkValuesDirty = false;
|
| - HTMLDataListElement* dataList = element()->dataList();
|
| - if (!dataList)
|
| - return;
|
| - RefPtr<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();
|
| - if (!element()->isValidValue(optionValue))
|
| - continue;
|
| - m_tickMarkValues.append(parseToNumber(optionValue, Decimal::nan()));
|
| - }
|
| - m_tickMarkValues.shrinkToFit();
|
| - nonCopyingSort(m_tickMarkValues.begin(), m_tickMarkValues.end(), decimalCompare);
|
| -}
|
| -
|
| -Decimal RangeInputType::findClosestTickMarkValue(const Decimal& value)
|
| -{
|
| - updateTickMarkValues();
|
| - if (!m_tickMarkValues.size())
|
| - return Decimal::nan();
|
| -
|
| - size_t left = 0;
|
| - size_t right = m_tickMarkValues.size();
|
| - size_t middle;
|
| - while (true) {
|
| - ASSERT(left <= right);
|
| - middle = left + (right - left) / 2;
|
| - if (!middle)
|
| - break;
|
| - if (middle == m_tickMarkValues.size() - 1 && m_tickMarkValues[middle] < value) {
|
| - middle++;
|
| - break;
|
| - }
|
| - if (m_tickMarkValues[middle - 1] <= value && m_tickMarkValues[middle] >= value)
|
| - break;
|
| -
|
| - if (m_tickMarkValues[middle] < value)
|
| - left = middle;
|
| - 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)
|
| - return closestRight;
|
| - return closestLeft;
|
| -}
|
| -
|
| -} // namespace WebCore
|
|
|