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