Home | History | Annotate | Download | only in forms
      1 /*
      2  * Copyright (C) 1999 Lars Knoll (knoll (at) kde.org)
      3  *           (C) 1999 Antti Koivisto (koivisto (at) kde.org)
      4  *           (C) 2001 Dirk Mueller (mueller (at) kde.org)
      5  * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
      6  *           (C) 2006 Alexey Proskuryakov (ap (at) nypop.com)
      7  * Copyright (C) 2007 Samuel Weinig (sam (at) webkit.org)
      8  * Copyright (C) 2009, 2010, 2011, 2012 Google Inc. All rights reserved.
      9  * Copyright (C) 2012 Samsung Electronics. All rights reserved.
     10  *
     11  * This library is free software; you can redistribute it and/or
     12  * modify it under the terms of the GNU Library General Public
     13  * License as published by the Free Software Foundation; either
     14  * version 2 of the License, or (at your option) any later version.
     15  *
     16  * This library is distributed in the hope that it will be useful,
     17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     19  * Library General Public License for more details.
     20  *
     21  * You should have received a copy of the GNU Library General Public License
     22  * along with this library; see the file COPYING.LIB.  If not, write to
     23  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     24  * Boston, MA 02110-1301, USA.
     25  *
     26  */
     27 
     28 #include "config.h"
     29 #include "core/html/forms/InputType.h"
     30 
     31 #include "bindings/core/v8/ExceptionMessages.h"
     32 #include "bindings/core/v8/ExceptionState.h"
     33 #include "core/InputTypeNames.h"
     34 #include "core/accessibility/AXObjectCache.h"
     35 #include "core/dom/NodeRenderStyle.h"
     36 #include "core/events/KeyboardEvent.h"
     37 #include "core/events/ScopedEventQueue.h"
     38 #include "core/fileapi/FileList.h"
     39 #include "core/frame/FrameHost.h"
     40 #include "core/html/FormDataList.h"
     41 #include "core/html/HTMLInputElement.h"
     42 #include "core/html/HTMLShadowElement.h"
     43 #include "core/html/forms/ButtonInputType.h"
     44 #include "core/html/forms/CheckboxInputType.h"
     45 #include "core/html/forms/ColorChooser.h"
     46 #include "core/html/forms/ColorInputType.h"
     47 #include "core/html/forms/DateInputType.h"
     48 #include "core/html/forms/DateTimeLocalInputType.h"
     49 #include "core/html/forms/EmailInputType.h"
     50 #include "core/html/forms/FileInputType.h"
     51 #include "core/html/forms/FormController.h"
     52 #include "core/html/forms/HiddenInputType.h"
     53 #include "core/html/forms/ImageInputType.h"
     54 #include "core/html/forms/MonthInputType.h"
     55 #include "core/html/forms/NumberInputType.h"
     56 #include "core/html/forms/PasswordInputType.h"
     57 #include "core/html/forms/RadioInputType.h"
     58 #include "core/html/forms/RangeInputType.h"
     59 #include "core/html/forms/ResetInputType.h"
     60 #include "core/html/forms/SearchInputType.h"
     61 #include "core/html/forms/SubmitInputType.h"
     62 #include "core/html/forms/TelephoneInputType.h"
     63 #include "core/html/forms/TextInputType.h"
     64 #include "core/html/forms/TimeInputType.h"
     65 #include "core/html/forms/URLInputType.h"
     66 #include "core/html/forms/WeekInputType.h"
     67 #include "core/html/parser/HTMLParserIdioms.h"
     68 #include "core/rendering/RenderTheme.h"
     69 #include "platform/RuntimeEnabledFeatures.h"
     70 #include "platform/text/PlatformLocale.h"
     71 #include "platform/text/TextBreakIterator.h"
     72 
     73 namespace blink {
     74 
     75 using blink::WebLocalizedString;
     76 using namespace HTMLNames;
     77 
     78 typedef PassRefPtrWillBeRawPtr<InputType> (*InputTypeFactoryFunction)(HTMLInputElement&);
     79 typedef HashMap<AtomicString, InputTypeFactoryFunction, CaseFoldingHash> InputTypeFactoryMap;
     80 
     81 static PassOwnPtr<InputTypeFactoryMap> createInputTypeFactoryMap()
     82 {
     83     OwnPtr<InputTypeFactoryMap> map = adoptPtr(new InputTypeFactoryMap);
     84     map->add(InputTypeNames::button, ButtonInputType::create);
     85     map->add(InputTypeNames::checkbox, CheckboxInputType::create);
     86     map->add(InputTypeNames::color, ColorInputType::create);
     87     map->add(InputTypeNames::date, DateInputType::create);
     88     map->add(InputTypeNames::datetime_local, DateTimeLocalInputType::create);
     89     map->add(InputTypeNames::email, EmailInputType::create);
     90     map->add(InputTypeNames::file, FileInputType::create);
     91     map->add(InputTypeNames::hidden, HiddenInputType::create);
     92     map->add(InputTypeNames::image, ImageInputType::create);
     93     map->add(InputTypeNames::month, MonthInputType::create);
     94     map->add(InputTypeNames::number, NumberInputType::create);
     95     map->add(InputTypeNames::password, PasswordInputType::create);
     96     map->add(InputTypeNames::radio, RadioInputType::create);
     97     map->add(InputTypeNames::range, RangeInputType::create);
     98     map->add(InputTypeNames::reset, ResetInputType::create);
     99     map->add(InputTypeNames::search, SearchInputType::create);
    100     map->add(InputTypeNames::submit, SubmitInputType::create);
    101     map->add(InputTypeNames::tel, TelephoneInputType::create);
    102     map->add(InputTypeNames::time, TimeInputType::create);
    103     map->add(InputTypeNames::url, URLInputType::create);
    104     map->add(InputTypeNames::week, WeekInputType::create);
    105     // No need to register "text" because it is the default type.
    106     return map.release();
    107 }
    108 
    109 static const InputTypeFactoryMap* factoryMap()
    110 {
    111     static const InputTypeFactoryMap* factoryMap = createInputTypeFactoryMap().leakPtr();
    112     return factoryMap;
    113 }
    114 
    115 PassRefPtrWillBeRawPtr<InputType> InputType::create(HTMLInputElement& element, const AtomicString& typeName)
    116 {
    117     InputTypeFactoryFunction factory = typeName.isEmpty() ? 0 : factoryMap()->get(typeName);
    118     if (!factory)
    119         factory = TextInputType::create;
    120     return factory(element);
    121 }
    122 
    123 PassRefPtrWillBeRawPtr<InputType> InputType::createText(HTMLInputElement& element)
    124 {
    125     return TextInputType::create(element);
    126 }
    127 
    128 const AtomicString& InputType::normalizeTypeName(const AtomicString& typeName)
    129 {
    130     if (typeName.isEmpty())
    131         return InputTypeNames::text;
    132     InputTypeFactoryMap::const_iterator it = factoryMap()->find(typeName);
    133     return it == factoryMap()->end() ? InputTypeNames::text : it->key;
    134 }
    135 
    136 InputType::~InputType()
    137 {
    138 }
    139 
    140 bool InputType::isTextField() const
    141 {
    142     return false;
    143 }
    144 
    145 bool InputType::shouldSaveAndRestoreFormControlState() const
    146 {
    147     return true;
    148 }
    149 
    150 FormControlState InputType::saveFormControlState() const
    151 {
    152     String currentValue = element().value();
    153     if (currentValue == element().defaultValue())
    154         return FormControlState();
    155     return FormControlState(currentValue);
    156 }
    157 
    158 void InputType::restoreFormControlState(const FormControlState& state)
    159 {
    160     element().setValue(state[0]);
    161 }
    162 
    163 bool InputType::isFormDataAppendable() const
    164 {
    165     // There is no form data unless there's a name for non-image types.
    166     return !element().name().isEmpty();
    167 }
    168 
    169 bool InputType::appendFormData(FormDataList& encoding, bool) const
    170 {
    171     // Always successful.
    172     encoding.appendData(element().name(), element().value());
    173     return true;
    174 }
    175 
    176 String InputType::resultForDialogSubmit() const
    177 {
    178     return element().fastGetAttribute(valueAttr);
    179 }
    180 
    181 double InputType::valueAsDate() const
    182 {
    183     return DateComponents::invalidMilliseconds();
    184 }
    185 
    186 void InputType::setValueAsDate(double, ExceptionState& exceptionState) const
    187 {
    188     exceptionState.throwDOMException(InvalidStateError, "This input element does not support Date values.");
    189 }
    190 
    191 double InputType::valueAsDouble() const
    192 {
    193     return std::numeric_limits<double>::quiet_NaN();
    194 }
    195 
    196 void InputType::setValueAsDouble(double doubleValue, TextFieldEventBehavior eventBehavior, ExceptionState& exceptionState) const
    197 {
    198     exceptionState.throwDOMException(InvalidStateError, "This input element does not support Number values.");
    199 }
    200 
    201 void InputType::setValueAsDecimal(const Decimal& newValue, TextFieldEventBehavior eventBehavior, ExceptionState&) const
    202 {
    203     element().setValue(serialize(newValue), eventBehavior);
    204 }
    205 
    206 bool InputType::supportsValidation() const
    207 {
    208     return true;
    209 }
    210 
    211 bool InputType::typeMismatchFor(const String&) const
    212 {
    213     return false;
    214 }
    215 
    216 bool InputType::typeMismatch() const
    217 {
    218     return false;
    219 }
    220 
    221 bool InputType::supportsRequired() const
    222 {
    223     // Almost all validatable types support @required.
    224     return supportsValidation();
    225 }
    226 
    227 bool InputType::valueMissing(const String&) const
    228 {
    229     return false;
    230 }
    231 
    232 bool InputType::hasBadInput() const
    233 {
    234     return false;
    235 }
    236 
    237 bool InputType::tooLong(const String&, HTMLTextFormControlElement::NeedsToCheckDirtyFlag) const
    238 {
    239     return false;
    240 }
    241 
    242 bool InputType::patternMismatch(const String&) const
    243 {
    244     return false;
    245 }
    246 
    247 bool InputType::rangeUnderflow(const String& value) const
    248 {
    249     if (!isSteppable())
    250         return false;
    251 
    252     const Decimal numericValue = parseToNumberOrNaN(value);
    253     if (!numericValue.isFinite())
    254         return false;
    255 
    256     return numericValue < createStepRange(RejectAny).minimum();
    257 }
    258 
    259 bool InputType::rangeOverflow(const String& value) const
    260 {
    261     if (!isSteppable())
    262         return false;
    263 
    264     const Decimal numericValue = parseToNumberOrNaN(value);
    265     if (!numericValue.isFinite())
    266         return false;
    267 
    268     return numericValue > createStepRange(RejectAny).maximum();
    269 }
    270 
    271 Decimal InputType::defaultValueForStepUp() const
    272 {
    273     return 0;
    274 }
    275 
    276 double InputType::minimum() const
    277 {
    278     return createStepRange(RejectAny).minimum().toDouble();
    279 }
    280 
    281 double InputType::maximum() const
    282 {
    283     return createStepRange(RejectAny).maximum().toDouble();
    284 }
    285 
    286 bool InputType::isInRange(const String& value) const
    287 {
    288     if (!isSteppable())
    289         return false;
    290 
    291     const Decimal numericValue = parseToNumberOrNaN(value);
    292     if (!numericValue.isFinite())
    293         return true;
    294 
    295     StepRange stepRange(createStepRange(RejectAny));
    296     return numericValue >= stepRange.minimum() && numericValue <= stepRange.maximum();
    297 }
    298 
    299 bool InputType::isOutOfRange(const String& value) const
    300 {
    301     if (!isSteppable())
    302         return false;
    303 
    304     const Decimal numericValue = parseToNumberOrNaN(value);
    305     if (!numericValue.isFinite())
    306         return true;
    307 
    308     StepRange stepRange(createStepRange(RejectAny));
    309     return numericValue < stepRange.minimum() || numericValue > stepRange.maximum();
    310 }
    311 
    312 bool InputType::stepMismatch(const String& value) const
    313 {
    314     if (!isSteppable())
    315         return false;
    316 
    317     const Decimal numericValue = parseToNumberOrNaN(value);
    318     if (!numericValue.isFinite())
    319         return false;
    320 
    321     return createStepRange(RejectAny).stepMismatch(numericValue);
    322 }
    323 
    324 String InputType::badInputText() const
    325 {
    326     ASSERT_NOT_REACHED();
    327     return locale().queryString(WebLocalizedString::ValidationTypeMismatch);
    328 }
    329 
    330 String InputType::rangeOverflowText(const Decimal&) const
    331 {
    332     ASSERT_NOT_REACHED();
    333     return String();
    334 }
    335 
    336 String InputType::rangeUnderflowText(const Decimal&) const
    337 {
    338     ASSERT_NOT_REACHED();
    339     return String();
    340 }
    341 
    342 String InputType::typeMismatchText() const
    343 {
    344     return locale().queryString(WebLocalizedString::ValidationTypeMismatch);
    345 }
    346 
    347 String InputType::valueMissingText() const
    348 {
    349     return locale().queryString(WebLocalizedString::ValidationValueMissing);
    350 }
    351 
    352 String InputType::validationMessage() const
    353 {
    354     const String value = element().value();
    355 
    356     // The order of the following checks is meaningful. e.g. We'd like to show the
    357     // badInput message even if the control has other validation errors.
    358     if (hasBadInput())
    359         return badInputText();
    360 
    361     if (valueMissing(value))
    362         return valueMissingText();
    363 
    364     if (typeMismatch())
    365         return typeMismatchText();
    366 
    367     if (patternMismatch(value))
    368         return locale().queryString(WebLocalizedString::ValidationPatternMismatch);
    369 
    370     if (element().tooLong())
    371         return locale().validationMessageTooLongText(value.length(), element().maxLength());
    372 
    373     if (!isSteppable())
    374         return emptyString();
    375 
    376     const Decimal numericValue = parseToNumberOrNaN(value);
    377     if (!numericValue.isFinite())
    378         return emptyString();
    379 
    380     StepRange stepRange(createStepRange(RejectAny));
    381 
    382     if (numericValue < stepRange.minimum())
    383         return rangeUnderflowText(stepRange.minimum());
    384 
    385     if (numericValue > stepRange.maximum())
    386         return rangeOverflowText(stepRange.maximum());
    387 
    388     if (stepRange.stepMismatch(numericValue)) {
    389         ASSERT(stepRange.hasStep());
    390         Decimal candidate1 = stepRange.clampValue(numericValue);
    391         String localizedCandidate1 = localizeValue(serialize(candidate1));
    392         Decimal candidate2 = candidate1 < numericValue ? candidate1 + stepRange.step() : candidate1 - stepRange.step();
    393         if (!candidate2.isFinite() || candidate2 < stepRange.minimum() || candidate2 > stepRange.maximum())
    394             return locale().queryString(WebLocalizedString::ValidationStepMismatchCloseToLimit, localizedCandidate1);
    395         String localizedCandidate2 = localizeValue(serialize(candidate2));
    396         if (candidate1 < candidate2)
    397             return locale().queryString(WebLocalizedString::ValidationStepMismatch, localizedCandidate1, localizedCandidate2);
    398         return locale().queryString(WebLocalizedString::ValidationStepMismatch, localizedCandidate2, localizedCandidate1);
    399     }
    400 
    401     return emptyString();
    402 }
    403 
    404 bool InputType::shouldSubmitImplicitly(Event* event)
    405 {
    406     return event->isKeyboardEvent() && event->type() == EventTypeNames::keypress && toKeyboardEvent(event)->charCode() == '\r';
    407 }
    408 
    409 Decimal InputType::parseToNumber(const String&, const Decimal& defaultValue) const
    410 {
    411     ASSERT_NOT_REACHED();
    412     return defaultValue;
    413 }
    414 
    415 Decimal InputType::parseToNumberOrNaN(const String& string) const
    416 {
    417     return parseToNumber(string, Decimal::nan());
    418 }
    419 
    420 String InputType::serialize(const Decimal&) const
    421 {
    422     ASSERT_NOT_REACHED();
    423     return String();
    424 }
    425 
    426 void InputType::dispatchSimulatedClickIfActive(KeyboardEvent* event) const
    427 {
    428     if (element().active())
    429         element().dispatchSimulatedClick(event);
    430     event->setDefaultHandled();
    431 }
    432 
    433 Chrome* InputType::chrome() const
    434 {
    435     if (FrameHost* host = element().document().frameHost())
    436         return &host->chrome();
    437     return 0;
    438 }
    439 
    440 Locale& InputType::locale() const
    441 {
    442     return element().locale();
    443 }
    444 
    445 bool InputType::canSetStringValue() const
    446 {
    447     return true;
    448 }
    449 
    450 bool InputType::hasCustomFocusLogic() const
    451 {
    452     return true;
    453 }
    454 
    455 bool InputType::isKeyboardFocusable() const
    456 {
    457     return element().isFocusable();
    458 }
    459 
    460 bool InputType::shouldShowFocusRingOnMouseFocus() const
    461 {
    462     return false;
    463 }
    464 
    465 void InputType::enableSecureTextInput()
    466 {
    467 }
    468 
    469 void InputType::disableSecureTextInput()
    470 {
    471 }
    472 
    473 void InputType::accessKeyAction(bool)
    474 {
    475     element().focus(false);
    476 }
    477 
    478 void InputType::countUsage()
    479 {
    480 }
    481 
    482 bool InputType::shouldRespectAlignAttribute()
    483 {
    484     return false;
    485 }
    486 
    487 void InputType::sanitizeValueInResponseToMinOrMaxAttributeChange()
    488 {
    489 }
    490 
    491 bool InputType::canBeSuccessfulSubmitButton()
    492 {
    493     return false;
    494 }
    495 
    496 bool InputType::rendererIsNeeded()
    497 {
    498     return true;
    499 }
    500 
    501 FileList* InputType::files()
    502 {
    503     return 0;
    504 }
    505 
    506 void InputType::setFiles(PassRefPtrWillBeRawPtr<FileList>)
    507 {
    508 }
    509 
    510 bool InputType::getTypeSpecificValue(String&)
    511 {
    512     return false;
    513 }
    514 
    515 String InputType::fallbackValue() const
    516 {
    517     return String();
    518 }
    519 
    520 String InputType::defaultValue() const
    521 {
    522     return String();
    523 }
    524 
    525 bool InputType::canSetSuggestedValue()
    526 {
    527     return false;
    528 }
    529 
    530 bool InputType::shouldSendChangeEventAfterCheckedChanged()
    531 {
    532     return true;
    533 }
    534 
    535 bool InputType::storesValueSeparateFromAttribute()
    536 {
    537     return true;
    538 }
    539 
    540 bool InputType::shouldDispatchFormControlChangeEvent(String& oldValue, String& newValue)
    541 {
    542     return !equalIgnoringNullity(oldValue, newValue);
    543 }
    544 
    545 void InputType::setValue(const String& sanitizedValue, bool valueChanged, TextFieldEventBehavior eventBehavior)
    546 {
    547     element().setValueInternal(sanitizedValue, eventBehavior);
    548     element().setNeedsStyleRecalc(SubtreeStyleChange);
    549     if (!valueChanged)
    550         return;
    551     switch (eventBehavior) {
    552     case DispatchChangeEvent:
    553         element().dispatchFormControlChangeEvent();
    554         break;
    555     case DispatchInputAndChangeEvent:
    556         element().dispatchFormControlInputEvent();
    557         element().dispatchFormControlChangeEvent();
    558         break;
    559     case DispatchNoEvent:
    560         break;
    561     }
    562 }
    563 
    564 bool InputType::canSetValue(const String&)
    565 {
    566     return true;
    567 }
    568 
    569 String InputType::localizeValue(const String& proposedValue) const
    570 {
    571     return proposedValue;
    572 }
    573 
    574 String InputType::visibleValue() const
    575 {
    576     return element().value();
    577 }
    578 
    579 String InputType::sanitizeValue(const String& proposedValue) const
    580 {
    581     return proposedValue;
    582 }
    583 
    584 void InputType::warnIfValueIsInvalidAndElementIsVisible(const String& value) const
    585 {
    586     // Don't warn if the value is set in Modernizr.
    587     RenderStyle* style = element().renderStyle();
    588     if (style && style->visibility() != HIDDEN)
    589         warnIfValueIsInvalid(value);
    590 }
    591 
    592 void InputType::warnIfValueIsInvalid(const String&) const
    593 {
    594 }
    595 
    596 bool InputType::receiveDroppedFiles(const DragData*)
    597 {
    598     ASSERT_NOT_REACHED();
    599     return false;
    600 }
    601 
    602 String InputType::droppedFileSystemId()
    603 {
    604     ASSERT_NOT_REACHED();
    605     return String();
    606 }
    607 
    608 bool InputType::shouldRespectListAttribute()
    609 {
    610     return false;
    611 }
    612 
    613 bool InputType::shouldRespectSpeechAttribute()
    614 {
    615     return false;
    616 }
    617 
    618 bool InputType::isTextButton() const
    619 {
    620     return false;
    621 }
    622 
    623 bool InputType::isInteractiveContent() const
    624 {
    625     return true;
    626 }
    627 
    628 bool InputType::isEnumeratable()
    629 {
    630     return true;
    631 }
    632 
    633 bool InputType::isCheckable()
    634 {
    635     return false;
    636 }
    637 
    638 bool InputType::isSteppable() const
    639 {
    640     return false;
    641 }
    642 
    643 bool InputType::shouldRespectHeightAndWidthAttributes()
    644 {
    645     return false;
    646 }
    647 
    648 int InputType::maxLength() const
    649 {
    650     return HTMLInputElement::maximumLength;
    651 }
    652 
    653 bool InputType::supportsPlaceholder() const
    654 {
    655     return false;
    656 }
    657 
    658 bool InputType::supportsReadOnly() const
    659 {
    660     return false;
    661 }
    662 
    663 String InputType::defaultToolTip() const
    664 {
    665     return String();
    666 }
    667 
    668 Decimal InputType::findClosestTickMarkValue(const Decimal&)
    669 {
    670     ASSERT_NOT_REACHED();
    671     return Decimal::nan();
    672 }
    673 
    674 void InputType::handleDOMActivateEvent(Event*)
    675 {
    676 }
    677 
    678 bool InputType::hasLegalLinkAttribute(const QualifiedName&) const
    679 {
    680     return false;
    681 }
    682 
    683 const QualifiedName& InputType::subResourceAttributeName() const
    684 {
    685     return QualifiedName::null();
    686 }
    687 
    688 bool InputType::shouldAppearIndeterminate() const
    689 {
    690     return false;
    691 }
    692 
    693 bool InputType::supportsInputModeAttribute() const
    694 {
    695     return false;
    696 }
    697 
    698 bool InputType::supportsSelectionAPI() const
    699 {
    700     return false;
    701 }
    702 
    703 unsigned InputType::height() const
    704 {
    705     return 0;
    706 }
    707 
    708 unsigned InputType::width() const
    709 {
    710     return 0;
    711 }
    712 
    713 TextDirection InputType::computedTextDirection()
    714 {
    715     return element().computedStyle()->direction();
    716 }
    717 
    718 ColorChooserClient* InputType::colorChooserClient()
    719 {
    720     return 0;
    721 }
    722 
    723 void InputType::applyStep(const Decimal& current, int count, AnyStepHandling anyStepHandling, TextFieldEventBehavior eventBehavior, ExceptionState& exceptionState)
    724 {
    725     StepRange stepRange(createStepRange(anyStepHandling));
    726     if (!stepRange.hasStep()) {
    727         exceptionState.throwDOMException(InvalidStateError, "This form element does not have an allowed value step.");
    728         return;
    729     }
    730 
    731     EventQueueScope scope;
    732     const Decimal step = stepRange.step();
    733 
    734     const AtomicString& stepString = element().fastGetAttribute(stepAttr);
    735     if (!equalIgnoringCase(stepString, "any") && stepRange.stepMismatch(current)) {
    736         // Snap-to-step / clamping steps
    737         // If the current value is not matched to step value:
    738         // - The value should be the larger matched value nearest to 0 if count > 0
    739         //   e.g. <input type=number value=3 min=-100 step=3> -> 5
    740         // - The value should be the smaller matched value nearest to 0 if count < 0
    741         //   e.g. <input type=number value=3 min=-100 step=3> -> 2
    742         //
    743 
    744         ASSERT(!step.isZero());
    745         Decimal newValue;
    746         const Decimal base = stepRange.stepBase();
    747         if (count < 0)
    748             newValue = base + ((current - base) / step).floor() * step;
    749         else if (count > 0)
    750             newValue = base + ((current - base) / step).ceiling() * step;
    751         else
    752             newValue = current;
    753 
    754         if (newValue < stepRange.minimum())
    755             newValue = stepRange.minimum();
    756         if (newValue > stepRange.maximum())
    757             newValue = stepRange.maximum();
    758 
    759         setValueAsDecimal(newValue, count == 1 || count == -1 ? DispatchChangeEvent : DispatchNoEvent, IGNORE_EXCEPTION);
    760         if (count > 1) {
    761             applyStep(newValue, count - 1, AnyIsDefaultStep, DispatchChangeEvent, IGNORE_EXCEPTION);
    762             return;
    763         }
    764         if (count < -1) {
    765             applyStep(newValue, count + 1, AnyIsDefaultStep, DispatchChangeEvent, IGNORE_EXCEPTION);
    766             return;
    767         }
    768     } else {
    769         Decimal newValue = current + stepRange.step() * count;
    770 
    771         if (!equalIgnoringCase(stepString, "any"))
    772             newValue = stepRange.alignValueForStep(current, newValue);
    773 
    774         if (newValue > stepRange.maximum())
    775             newValue = newValue - stepRange.step();
    776         else if (newValue < stepRange.minimum())
    777             newValue = newValue + stepRange.step();
    778 
    779         setValueAsDecimal(newValue, eventBehavior, exceptionState);
    780     }
    781     if (AXObjectCache* cache = element().document().existingAXObjectCache())
    782         cache->postNotification(&element(), AXObjectCache::AXValueChanged, true);
    783 }
    784 
    785 bool InputType::getAllowedValueStep(Decimal* step) const
    786 {
    787     StepRange stepRange(createStepRange(RejectAny));
    788     *step = stepRange.step();
    789     return stepRange.hasStep();
    790 }
    791 
    792 StepRange InputType::createStepRange(AnyStepHandling) const
    793 {
    794     ASSERT_NOT_REACHED();
    795     return StepRange();
    796 }
    797 
    798 void InputType::stepUp(int n, ExceptionState& exceptionState)
    799 {
    800     if (!isSteppable()) {
    801         exceptionState.throwDOMException(InvalidStateError, "This form element is not steppable.");
    802         return;
    803     }
    804     const Decimal current = parseToNumber(element().value(), 0);
    805     applyStep(current, n, RejectAny, DispatchNoEvent, exceptionState);
    806 }
    807 
    808 void InputType::stepUpFromRenderer(int n)
    809 {
    810     // The only difference from stepUp()/stepDown() is the extra treatment
    811     // of the current value before applying the step:
    812     //
    813     // If the current value is not a number, including empty, the current value is assumed as 0.
    814     //   * If 0 is in-range, and matches to step value
    815     //     - The value should be the +step if n > 0
    816     //     - The value should be the -step if n < 0
    817     //     If -step or +step is out of range, new value should be 0.
    818     //   * If 0 is smaller than the minimum value
    819     //     - The value should be the minimum value for any n
    820     //   * If 0 is larger than the maximum value
    821     //     - The value should be the maximum value for any n
    822     //   * If 0 is in-range, but not matched to step value
    823     //     - The value should be the larger matched value nearest to 0 if n > 0
    824     //       e.g. <input type=number min=-100 step=3> -> 2
    825     //     - The value should be the smaler matched value nearest to 0 if n < 0
    826     //       e.g. <input type=number min=-100 step=3> -> -1
    827     //   As for date/datetime-local/month/time/week types, the current value is assumed as "the current local date/time".
    828     //   As for datetime type, the current value is assumed as "the current date/time in UTC".
    829     // If the current value is smaller than the minimum value:
    830     //  - The value should be the minimum value if n > 0
    831     //  - Nothing should happen if n < 0
    832     // If the current value is larger than the maximum value:
    833     //  - The value should be the maximum value if n < 0
    834     //  - Nothing should happen if n > 0
    835     //
    836     // n is assumed as -n if step < 0.
    837 
    838     ASSERT(isSteppable());
    839     if (!isSteppable())
    840         return;
    841     ASSERT(n);
    842     if (!n)
    843         return;
    844 
    845     StepRange stepRange(createStepRange(AnyIsDefaultStep));
    846 
    847     // FIXME: Not any changes after stepping, even if it is an invalid value, may be better.
    848     // (e.g. Stepping-up for <input type="number" value="foo" step="any" /> => "foo")
    849     if (!stepRange.hasStep())
    850         return;
    851 
    852     EventQueueScope scope;
    853     const Decimal step = stepRange.step();
    854 
    855     int sign;
    856     if (step > 0)
    857         sign = n;
    858     else if (step < 0)
    859         sign = -n;
    860     else
    861         sign = 0;
    862 
    863     Decimal current = parseToNumberOrNaN(element().value());
    864     if (!current.isFinite()) {
    865         current = defaultValueForStepUp();
    866         const Decimal nextDiff = step * n;
    867         if (current < stepRange.minimum() - nextDiff)
    868             current = stepRange.minimum() - nextDiff;
    869         if (current > stepRange.maximum() - nextDiff)
    870             current = stepRange.maximum() - nextDiff;
    871         setValueAsDecimal(current, DispatchNoEvent, IGNORE_EXCEPTION);
    872     }
    873     if ((sign > 0 && current < stepRange.minimum()) || (sign < 0 && current > stepRange.maximum())) {
    874         setValueAsDecimal(sign > 0 ? stepRange.minimum() : stepRange.maximum(), DispatchChangeEvent, IGNORE_EXCEPTION);
    875         return;
    876     }
    877     applyStep(current, n, AnyIsDefaultStep, DispatchChangeEvent, IGNORE_EXCEPTION);
    878 }
    879 
    880 void InputType::countUsageIfVisible(UseCounter::Feature feature) const
    881 {
    882     if (RenderStyle* style = element().renderStyle()) {
    883         if (style->visibility() != HIDDEN)
    884             UseCounter::count(element().document(), feature);
    885     }
    886 }
    887 
    888 Decimal InputType::findStepBase(const Decimal& defaultValue) const
    889 {
    890     Decimal stepBase = parseToNumber(element().fastGetAttribute(minAttr), Decimal::nan());
    891     if (!stepBase.isFinite())
    892         stepBase = parseToNumber(element().fastGetAttribute(valueAttr), defaultValue);
    893     return stepBase;
    894 }
    895 
    896 StepRange InputType::createStepRange(AnyStepHandling anyStepHandling, const Decimal& stepBaseDefault, const Decimal& minimumDefault, const Decimal& maximumDefault, const StepRange::StepDescription& stepDescription) const
    897 {
    898     const Decimal stepBase = findStepBase(stepBaseDefault);
    899     const Decimal minimum = parseToNumber(element().fastGetAttribute(minAttr), minimumDefault);
    900     const Decimal maximum = parseToNumber(element().fastGetAttribute(maxAttr), maximumDefault);
    901     const Decimal step = StepRange::parseStep(anyStepHandling, stepDescription, element().fastGetAttribute(stepAttr));
    902     return StepRange(stepBase, minimum, maximum, step, stepDescription);
    903 }
    904 
    905 } // namespace blink
    906