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/v8/ExceptionMessages.h"
     32 #include "bindings/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/ColorInputType.h"
     46 #include "core/html/forms/DateInputType.h"
     47 #include "core/html/forms/DateTimeLocalInputType.h"
     48 #include "core/html/forms/EmailInputType.h"
     49 #include "core/html/forms/FileInputType.h"
     50 #include "core/html/forms/FormController.h"
     51 #include "core/html/forms/HiddenInputType.h"
     52 #include "core/html/forms/ImageInputType.h"
     53 #include "core/html/forms/MonthInputType.h"
     54 #include "core/html/forms/NumberInputType.h"
     55 #include "core/html/forms/PasswordInputType.h"
     56 #include "core/html/forms/RadioInputType.h"
     57 #include "core/html/forms/RangeInputType.h"
     58 #include "core/html/forms/ResetInputType.h"
     59 #include "core/html/forms/SearchInputType.h"
     60 #include "core/html/forms/SubmitInputType.h"
     61 #include "core/html/forms/TelephoneInputType.h"
     62 #include "core/html/forms/TextInputType.h"
     63 #include "core/html/forms/TimeInputType.h"
     64 #include "core/html/forms/URLInputType.h"
     65 #include "core/html/forms/WeekInputType.h"
     66 #include "core/html/parser/HTMLParserIdioms.h"
     67 #include "core/rendering/RenderTheme.h"
     68 #include "platform/ColorChooser.h"
     69 #include "platform/RuntimeEnabledFeatures.h"
     70 #include "platform/text/PlatformLocale.h"
     71 #include "platform/text/TextBreakIterator.h"
     72 
     73 namespace WebCore {
     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::isTextType() const
    146 {
    147     return false;
    148 }
    149 
    150 bool InputType::isRangeControl() const
    151 {
    152     return false;
    153 }
    154 
    155 bool InputType::shouldSaveAndRestoreFormControlState() const
    156 {
    157     return true;
    158 }
    159 
    160 FormControlState InputType::saveFormControlState() const
    161 {
    162     String currentValue = element().value();
    163     if (currentValue == element().defaultValue())
    164         return FormControlState();
    165     return FormControlState(currentValue);
    166 }
    167 
    168 void InputType::restoreFormControlState(const FormControlState& state)
    169 {
    170     element().setValue(state[0]);
    171 }
    172 
    173 bool InputType::isFormDataAppendable() const
    174 {
    175     // There is no form data unless there's a name for non-image types.
    176     return !element().name().isEmpty();
    177 }
    178 
    179 bool InputType::appendFormData(FormDataList& encoding, bool) const
    180 {
    181     // Always successful.
    182     encoding.appendData(element().name(), element().value());
    183     return true;
    184 }
    185 
    186 String InputType::resultForDialogSubmit() const
    187 {
    188     return element().fastGetAttribute(valueAttr);
    189 }
    190 
    191 double InputType::valueAsDate() const
    192 {
    193     return DateComponents::invalidMilliseconds();
    194 }
    195 
    196 void InputType::setValueAsDate(double, ExceptionState& exceptionState) const
    197 {
    198     exceptionState.throwDOMException(InvalidStateError, "This input element does not support Date values.");
    199 }
    200 
    201 double InputType::valueAsDouble() const
    202 {
    203     return std::numeric_limits<double>::quiet_NaN();
    204 }
    205 
    206 void InputType::setValueAsDouble(double doubleValue, TextFieldEventBehavior eventBehavior, ExceptionState& exceptionState) const
    207 {
    208     exceptionState.throwDOMException(InvalidStateError, "This input element does not support Number values.");
    209 }
    210 
    211 void InputType::setValueAsDecimal(const Decimal& newValue, TextFieldEventBehavior eventBehavior, ExceptionState&) const
    212 {
    213     element().setValue(serialize(newValue), eventBehavior);
    214 }
    215 
    216 bool InputType::supportsValidation() const
    217 {
    218     return true;
    219 }
    220 
    221 bool InputType::typeMismatchFor(const String&) const
    222 {
    223     return false;
    224 }
    225 
    226 bool InputType::typeMismatch() const
    227 {
    228     return false;
    229 }
    230 
    231 bool InputType::supportsRequired() const
    232 {
    233     // Almost all validatable types support @required.
    234     return supportsValidation();
    235 }
    236 
    237 bool InputType::valueMissing(const String&) const
    238 {
    239     return false;
    240 }
    241 
    242 bool InputType::hasBadInput() const
    243 {
    244     return false;
    245 }
    246 
    247 bool InputType::patternMismatch(const String&) const
    248 {
    249     return false;
    250 }
    251 
    252 bool InputType::rangeUnderflow(const String& value) const
    253 {
    254     if (!isSteppable())
    255         return false;
    256 
    257     const Decimal numericValue = parseToNumberOrNaN(value);
    258     if (!numericValue.isFinite())
    259         return false;
    260 
    261     return numericValue < createStepRange(RejectAny).minimum();
    262 }
    263 
    264 bool InputType::rangeOverflow(const String& value) const
    265 {
    266     if (!isSteppable())
    267         return false;
    268 
    269     const Decimal numericValue = parseToNumberOrNaN(value);
    270     if (!numericValue.isFinite())
    271         return false;
    272 
    273     return numericValue > createStepRange(RejectAny).maximum();
    274 }
    275 
    276 Decimal InputType::defaultValueForStepUp() const
    277 {
    278     return 0;
    279 }
    280 
    281 double InputType::minimum() const
    282 {
    283     return createStepRange(RejectAny).minimum().toDouble();
    284 }
    285 
    286 double InputType::maximum() const
    287 {
    288     return createStepRange(RejectAny).maximum().toDouble();
    289 }
    290 
    291 bool InputType::isInRange(const String& value) const
    292 {
    293     if (!isSteppable())
    294         return false;
    295 
    296     const Decimal numericValue = parseToNumberOrNaN(value);
    297     if (!numericValue.isFinite())
    298         return true;
    299 
    300     StepRange stepRange(createStepRange(RejectAny));
    301     return numericValue >= stepRange.minimum() && numericValue <= stepRange.maximum();
    302 }
    303 
    304 bool InputType::isOutOfRange(const String& value) const
    305 {
    306     if (!isSteppable())
    307         return false;
    308 
    309     const Decimal numericValue = parseToNumberOrNaN(value);
    310     if (!numericValue.isFinite())
    311         return true;
    312 
    313     StepRange stepRange(createStepRange(RejectAny));
    314     return numericValue < stepRange.minimum() || numericValue > stepRange.maximum();
    315 }
    316 
    317 bool InputType::stepMismatch(const String& value) const
    318 {
    319     if (!isSteppable())
    320         return false;
    321 
    322     const Decimal numericValue = parseToNumberOrNaN(value);
    323     if (!numericValue.isFinite())
    324         return false;
    325 
    326     return createStepRange(RejectAny).stepMismatch(numericValue);
    327 }
    328 
    329 String InputType::badInputText() const
    330 {
    331     ASSERT_NOT_REACHED();
    332     return locale().queryString(WebLocalizedString::ValidationTypeMismatch);
    333 }
    334 
    335 String InputType::rangeOverflowText(const Decimal&) const
    336 {
    337     ASSERT_NOT_REACHED();
    338     return String();
    339 }
    340 
    341 String InputType::rangeUnderflowText(const Decimal&) const
    342 {
    343     ASSERT_NOT_REACHED();
    344     return String();
    345 }
    346 
    347 String InputType::typeMismatchText() const
    348 {
    349     return locale().queryString(WebLocalizedString::ValidationTypeMismatch);
    350 }
    351 
    352 String InputType::valueMissingText() const
    353 {
    354     return locale().queryString(WebLocalizedString::ValidationValueMissing);
    355 }
    356 
    357 String InputType::validationMessage() const
    358 {
    359     const String value = element().value();
    360 
    361     // The order of the following checks is meaningful. e.g. We'd like to show the
    362     // badInput message even if the control has other validation errors.
    363     if (hasBadInput())
    364         return badInputText();
    365 
    366     if (valueMissing(value))
    367         return valueMissingText();
    368 
    369     if (typeMismatch())
    370         return typeMismatchText();
    371 
    372     if (patternMismatch(value))
    373         return locale().queryString(WebLocalizedString::ValidationPatternMismatch);
    374 
    375     if (element().tooLong())
    376         return locale().validationMessageTooLongText(value.length(), element().maxLength());
    377 
    378     if (!isSteppable())
    379         return emptyString();
    380 
    381     const Decimal numericValue = parseToNumberOrNaN(value);
    382     if (!numericValue.isFinite())
    383         return emptyString();
    384 
    385     StepRange stepRange(createStepRange(RejectAny));
    386 
    387     if (numericValue < stepRange.minimum())
    388         return rangeUnderflowText(stepRange.minimum());
    389 
    390     if (numericValue > stepRange.maximum())
    391         return rangeOverflowText(stepRange.maximum());
    392 
    393     if (stepRange.stepMismatch(numericValue)) {
    394         ASSERT(stepRange.hasStep());
    395         Decimal candidate1 = stepRange.clampValue(numericValue);
    396         String localizedCandidate1 = localizeValue(serialize(candidate1));
    397         Decimal candidate2 = candidate1 < numericValue ? candidate1 + stepRange.step() : candidate1 - stepRange.step();
    398         if (!candidate2.isFinite() || candidate2 < stepRange.minimum() || candidate2 > stepRange.maximum())
    399             return locale().queryString(WebLocalizedString::ValidationStepMismatchCloseToLimit, localizedCandidate1);
    400         String localizedCandidate2 = localizeValue(serialize(candidate2));
    401         if (candidate1 < candidate2)
    402             return locale().queryString(WebLocalizedString::ValidationStepMismatch, localizedCandidate1, localizedCandidate2);
    403         return locale().queryString(WebLocalizedString::ValidationStepMismatch, localizedCandidate2, localizedCandidate1);
    404     }
    405 
    406     return emptyString();
    407 }
    408 
    409 bool InputType::shouldSubmitImplicitly(Event* event)
    410 {
    411     return event->isKeyboardEvent() && event->type() == EventTypeNames::keypress && toKeyboardEvent(event)->charCode() == '\r';
    412 }
    413 
    414 Decimal InputType::parseToNumber(const String&, const Decimal& defaultValue) const
    415 {
    416     ASSERT_NOT_REACHED();
    417     return defaultValue;
    418 }
    419 
    420 Decimal InputType::parseToNumberOrNaN(const String& string) const
    421 {
    422     return parseToNumber(string, Decimal::nan());
    423 }
    424 
    425 String InputType::serialize(const Decimal&) const
    426 {
    427     ASSERT_NOT_REACHED();
    428     return String();
    429 }
    430 
    431 void InputType::dispatchSimulatedClickIfActive(KeyboardEvent* event) const
    432 {
    433     if (element().active())
    434         element().dispatchSimulatedClick(event);
    435     event->setDefaultHandled();
    436 }
    437 
    438 Chrome* InputType::chrome() const
    439 {
    440     if (FrameHost* host = element().document().frameHost())
    441         return &host->chrome();
    442     return 0;
    443 }
    444 
    445 Locale& InputType::locale() const
    446 {
    447     return element().locale();
    448 }
    449 
    450 bool InputType::canSetStringValue() const
    451 {
    452     return true;
    453 }
    454 
    455 bool InputType::hasCustomFocusLogic() const
    456 {
    457     return true;
    458 }
    459 
    460 bool InputType::isKeyboardFocusable() const
    461 {
    462     return element().isFocusable();
    463 }
    464 
    465 bool InputType::shouldShowFocusRingOnMouseFocus() const
    466 {
    467     return false;
    468 }
    469 
    470 bool InputType::shouldUseInputMethod() const
    471 {
    472     return false;
    473 }
    474 
    475 void InputType::enableSecureTextInput()
    476 {
    477 }
    478 
    479 void InputType::disableSecureTextInput()
    480 {
    481 }
    482 
    483 void InputType::accessKeyAction(bool)
    484 {
    485     element().focus(false);
    486 }
    487 
    488 void InputType::countUsage()
    489 {
    490 }
    491 
    492 bool InputType::shouldRespectAlignAttribute()
    493 {
    494     return false;
    495 }
    496 
    497 void InputType::sanitizeValueInResponseToMinOrMaxAttributeChange()
    498 {
    499 }
    500 
    501 bool InputType::canBeSuccessfulSubmitButton()
    502 {
    503     return false;
    504 }
    505 
    506 bool InputType::rendererIsNeeded()
    507 {
    508     return true;
    509 }
    510 
    511 FileList* InputType::files()
    512 {
    513     return 0;
    514 }
    515 
    516 void InputType::setFiles(PassRefPtrWillBeRawPtr<FileList>)
    517 {
    518 }
    519 
    520 bool InputType::getTypeSpecificValue(String&)
    521 {
    522     return false;
    523 }
    524 
    525 String InputType::fallbackValue() const
    526 {
    527     return String();
    528 }
    529 
    530 String InputType::defaultValue() const
    531 {
    532     return String();
    533 }
    534 
    535 bool InputType::canSetSuggestedValue()
    536 {
    537     return false;
    538 }
    539 
    540 bool InputType::shouldSendChangeEventAfterCheckedChanged()
    541 {
    542     return true;
    543 }
    544 
    545 bool InputType::storesValueSeparateFromAttribute()
    546 {
    547     return true;
    548 }
    549 
    550 bool InputType::shouldDispatchFormControlChangeEvent(String& oldValue, String& newValue)
    551 {
    552     return !equalIgnoringNullity(oldValue, newValue);
    553 }
    554 
    555 void InputType::setValue(const String& sanitizedValue, bool valueChanged, TextFieldEventBehavior eventBehavior)
    556 {
    557     element().setValueInternal(sanitizedValue, eventBehavior);
    558     element().setNeedsStyleRecalc(SubtreeStyleChange);
    559     if (!valueChanged)
    560         return;
    561     switch (eventBehavior) {
    562     case DispatchChangeEvent:
    563         element().dispatchFormControlChangeEvent();
    564         break;
    565     case DispatchInputAndChangeEvent:
    566         element().dispatchFormControlInputEvent();
    567         element().dispatchFormControlChangeEvent();
    568         break;
    569     case DispatchNoEvent:
    570         break;
    571     }
    572 }
    573 
    574 bool InputType::canSetValue(const String&)
    575 {
    576     return true;
    577 }
    578 
    579 String InputType::localizeValue(const String& proposedValue) const
    580 {
    581     return proposedValue;
    582 }
    583 
    584 String InputType::visibleValue() const
    585 {
    586     return element().value();
    587 }
    588 
    589 String InputType::sanitizeValue(const String& proposedValue) const
    590 {
    591     return proposedValue;
    592 }
    593 
    594 bool InputType::receiveDroppedFiles(const DragData*)
    595 {
    596     ASSERT_NOT_REACHED();
    597     return false;
    598 }
    599 
    600 String InputType::droppedFileSystemId()
    601 {
    602     ASSERT_NOT_REACHED();
    603     return String();
    604 }
    605 
    606 bool InputType::shouldRespectListAttribute()
    607 {
    608     return false;
    609 }
    610 
    611 bool InputType::shouldRespectSpeechAttribute()
    612 {
    613     return false;
    614 }
    615 
    616 bool InputType::isTextButton() const
    617 {
    618     return false;
    619 }
    620 
    621 bool InputType::isRadioButton() const
    622 {
    623     return false;
    624 }
    625 
    626 bool InputType::isSearchField() const
    627 {
    628     return false;
    629 }
    630 
    631 bool InputType::isHiddenType() const
    632 {
    633     return false;
    634 }
    635 
    636 bool InputType::isPasswordField() const
    637 {
    638     return false;
    639 }
    640 
    641 bool InputType::isCheckbox() const
    642 {
    643     return false;
    644 }
    645 
    646 bool InputType::isEmailField() const
    647 {
    648     return false;
    649 }
    650 
    651 bool InputType::isFileUpload() const
    652 {
    653     return false;
    654 }
    655 
    656 bool InputType::isImageButton() const
    657 {
    658     return false;
    659 }
    660 
    661 bool InputType::isInteractiveContent() const
    662 {
    663     return true;
    664 }
    665 
    666 bool InputType::isNumberField() const
    667 {
    668     return false;
    669 }
    670 
    671 bool InputType::isTelephoneField() const
    672 {
    673     return false;
    674 }
    675 
    676 bool InputType::isURLField() const
    677 {
    678     return false;
    679 }
    680 
    681 bool InputType::isDateField() const
    682 {
    683     return false;
    684 }
    685 
    686 bool InputType::isDateTimeLocalField() const
    687 {
    688     return false;
    689 }
    690 
    691 bool InputType::isMonthField() const
    692 {
    693     return false;
    694 }
    695 
    696 bool InputType::isTimeField() const
    697 {
    698     return false;
    699 }
    700 
    701 bool InputType::isWeekField() const
    702 {
    703     return false;
    704 }
    705 
    706 bool InputType::isEnumeratable()
    707 {
    708     return true;
    709 }
    710 
    711 bool InputType::isCheckable()
    712 {
    713     return false;
    714 }
    715 
    716 bool InputType::isSteppable() const
    717 {
    718     return false;
    719 }
    720 
    721 bool InputType::isColorControl() const
    722 {
    723     return false;
    724 }
    725 
    726 bool InputType::shouldRespectHeightAndWidthAttributes()
    727 {
    728     return false;
    729 }
    730 
    731 bool InputType::supportsPlaceholder() const
    732 {
    733     return false;
    734 }
    735 
    736 bool InputType::supportsReadOnly() const
    737 {
    738     return false;
    739 }
    740 
    741 String InputType::defaultToolTip() const
    742 {
    743     return String();
    744 }
    745 
    746 Decimal InputType::findClosestTickMarkValue(const Decimal&)
    747 {
    748     ASSERT_NOT_REACHED();
    749     return Decimal::nan();
    750 }
    751 
    752 void InputType::handleDOMActivateEvent(Event*)
    753 {
    754 }
    755 
    756 bool InputType::hasLegalLinkAttribute(const QualifiedName&) const
    757 {
    758     return false;
    759 }
    760 
    761 const QualifiedName& InputType::subResourceAttributeName() const
    762 {
    763     return QualifiedName::null();
    764 }
    765 
    766 bool InputType::supportsIndeterminateAppearance() const
    767 {
    768     return false;
    769 }
    770 
    771 bool InputType::supportsInputModeAttribute() const
    772 {
    773     return false;
    774 }
    775 
    776 bool InputType::supportsSelectionAPI() const
    777 {
    778     return false;
    779 }
    780 
    781 unsigned InputType::height() const
    782 {
    783     return 0;
    784 }
    785 
    786 unsigned InputType::width() const
    787 {
    788     return 0;
    789 }
    790 
    791 void InputType::applyStep(const Decimal& current, int count, AnyStepHandling anyStepHandling, TextFieldEventBehavior eventBehavior, ExceptionState& exceptionState)
    792 {
    793     StepRange stepRange(createStepRange(anyStepHandling));
    794     if (!stepRange.hasStep()) {
    795         exceptionState.throwDOMException(InvalidStateError, "This form element does not have an allowed value step.");
    796         return;
    797     }
    798 
    799     EventQueueScope scope;
    800     const Decimal step = stepRange.step();
    801 
    802     const AtomicString& stepString = element().fastGetAttribute(stepAttr);
    803     if (!equalIgnoringCase(stepString, "any") && stepRange.stepMismatch(current)) {
    804         // Snap-to-step / clamping steps
    805         // If the current value is not matched to step value:
    806         // - The value should be the larger matched value nearest to 0 if count > 0
    807         //   e.g. <input type=number value=3 min=-100 step=3> -> 5
    808         // - The value should be the smaller matched value nearest to 0 if count < 0
    809         //   e.g. <input type=number value=3 min=-100 step=3> -> 2
    810         //
    811 
    812         ASSERT(!step.isZero());
    813         Decimal newValue;
    814         const Decimal base = stepRange.stepBase();
    815         if (count < 0)
    816             newValue = base + ((current - base) / step).floor() * step;
    817         else if (count > 0)
    818             newValue = base + ((current - base) / step).ceiling() * step;
    819         else
    820             newValue = current;
    821 
    822         if (newValue < stepRange.minimum())
    823             newValue = stepRange.minimum();
    824         if (newValue > stepRange.maximum())
    825             newValue = stepRange.maximum();
    826 
    827         setValueAsDecimal(newValue, count == 1 || count == -1 ? DispatchChangeEvent : DispatchNoEvent, IGNORE_EXCEPTION);
    828         if (count > 1) {
    829             applyStep(newValue, count - 1, AnyIsDefaultStep, DispatchChangeEvent, IGNORE_EXCEPTION);
    830             return;
    831         }
    832         if (count < -1) {
    833             applyStep(newValue, count + 1, AnyIsDefaultStep, DispatchChangeEvent, IGNORE_EXCEPTION);
    834             return;
    835         }
    836     } else {
    837         Decimal newValue = current + stepRange.step() * count;
    838 
    839         if (!equalIgnoringCase(stepString, "any"))
    840             newValue = stepRange.alignValueForStep(current, newValue);
    841 
    842         if (newValue > stepRange.maximum())
    843             newValue = newValue - stepRange.step();
    844         else if (newValue < stepRange.minimum())
    845             newValue = newValue + stepRange.step();
    846 
    847         setValueAsDecimal(newValue, eventBehavior, exceptionState);
    848     }
    849     if (AXObjectCache* cache = element().document().existingAXObjectCache())
    850         cache->postNotification(&element(), AXObjectCache::AXValueChanged, true);
    851 }
    852 
    853 bool InputType::getAllowedValueStep(Decimal* step) const
    854 {
    855     StepRange stepRange(createStepRange(RejectAny));
    856     *step = stepRange.step();
    857     return stepRange.hasStep();
    858 }
    859 
    860 StepRange InputType::createStepRange(AnyStepHandling) const
    861 {
    862     ASSERT_NOT_REACHED();
    863     return StepRange();
    864 }
    865 
    866 void InputType::stepUp(int n, ExceptionState& exceptionState)
    867 {
    868     if (!isSteppable()) {
    869         exceptionState.throwDOMException(InvalidStateError, "This form element is not steppable.");
    870         return;
    871     }
    872     const Decimal current = parseToNumber(element().value(), 0);
    873     applyStep(current, n, RejectAny, DispatchNoEvent, exceptionState);
    874 }
    875 
    876 void InputType::stepUpFromRenderer(int n)
    877 {
    878     // The only difference from stepUp()/stepDown() is the extra treatment
    879     // of the current value before applying the step:
    880     //
    881     // If the current value is not a number, including empty, the current value is assumed as 0.
    882     //   * If 0 is in-range, and matches to step value
    883     //     - The value should be the +step if n > 0
    884     //     - The value should be the -step if n < 0
    885     //     If -step or +step is out of range, new value should be 0.
    886     //   * If 0 is smaller than the minimum value
    887     //     - The value should be the minimum value for any n
    888     //   * If 0 is larger than the maximum value
    889     //     - The value should be the maximum value for any n
    890     //   * If 0 is in-range, but not matched to step value
    891     //     - The value should be the larger matched value nearest to 0 if n > 0
    892     //       e.g. <input type=number min=-100 step=3> -> 2
    893     //     - The value should be the smaler matched value nearest to 0 if n < 0
    894     //       e.g. <input type=number min=-100 step=3> -> -1
    895     //   As for date/datetime-local/month/time/week types, the current value is assumed as "the current local date/time".
    896     //   As for datetime type, the current value is assumed as "the current date/time in UTC".
    897     // If the current value is smaller than the minimum value:
    898     //  - The value should be the minimum value if n > 0
    899     //  - Nothing should happen if n < 0
    900     // If the current value is larger than the maximum value:
    901     //  - The value should be the maximum value if n < 0
    902     //  - Nothing should happen if n > 0
    903     //
    904     // n is assumed as -n if step < 0.
    905 
    906     ASSERT(isSteppable());
    907     if (!isSteppable())
    908         return;
    909     ASSERT(n);
    910     if (!n)
    911         return;
    912 
    913     StepRange stepRange(createStepRange(AnyIsDefaultStep));
    914 
    915     // FIXME: Not any changes after stepping, even if it is an invalid value, may be better.
    916     // (e.g. Stepping-up for <input type="number" value="foo" step="any" /> => "foo")
    917     if (!stepRange.hasStep())
    918         return;
    919 
    920     EventQueueScope scope;
    921     const Decimal step = stepRange.step();
    922 
    923     int sign;
    924     if (step > 0)
    925         sign = n;
    926     else if (step < 0)
    927         sign = -n;
    928     else
    929         sign = 0;
    930 
    931     Decimal current = parseToNumberOrNaN(element().value());
    932     if (!current.isFinite()) {
    933         current = defaultValueForStepUp();
    934         const Decimal nextDiff = step * n;
    935         if (current < stepRange.minimum() - nextDiff)
    936             current = stepRange.minimum() - nextDiff;
    937         if (current > stepRange.maximum() - nextDiff)
    938             current = stepRange.maximum() - nextDiff;
    939         setValueAsDecimal(current, DispatchNoEvent, IGNORE_EXCEPTION);
    940     }
    941     if ((sign > 0 && current < stepRange.minimum()) || (sign < 0 && current > stepRange.maximum())) {
    942         setValueAsDecimal(sign > 0 ? stepRange.minimum() : stepRange.maximum(), DispatchChangeEvent, IGNORE_EXCEPTION);
    943         return;
    944     }
    945     applyStep(current, n, AnyIsDefaultStep, DispatchChangeEvent, IGNORE_EXCEPTION);
    946 }
    947 
    948 void InputType::countUsageIfVisible(UseCounter::Feature feature) const
    949 {
    950     if (RenderStyle* style = element().renderStyle()) {
    951         if (style->visibility() != HIDDEN)
    952             UseCounter::count(element().document(), feature);
    953     }
    954 }
    955 
    956 Decimal InputType::findStepBase(const Decimal& defaultValue) const
    957 {
    958     Decimal stepBase = parseToNumber(element().fastGetAttribute(minAttr), Decimal::nan());
    959     if (!stepBase.isFinite())
    960         stepBase = parseToNumber(element().fastGetAttribute(valueAttr), defaultValue);
    961     return stepBase;
    962 }
    963 
    964 StepRange InputType::createStepRange(AnyStepHandling anyStepHandling, const Decimal& stepBaseDefault, const Decimal& minimumDefault, const Decimal& maximumDefault, const StepRange::StepDescription& stepDescription) const
    965 {
    966     const Decimal stepBase = findStepBase(stepBaseDefault);
    967     const Decimal minimum = parseToNumber(element().fastGetAttribute(minAttr), minimumDefault);
    968     const Decimal maximum = parseToNumber(element().fastGetAttribute(maxAttr), maximumDefault);
    969     const Decimal step = StepRange::parseStep(anyStepHandling, stepDescription, element().fastGetAttribute(stepAttr));
    970     return StepRange(stepBase, minimum, maximum, step, stepDescription);
    971 }
    972 
    973 } // namespace WebCore
    974