1/* 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) 3 * (C) 1999 Antti Koivisto (koivisto@kde.org) 4 * (C) 2001 Dirk Mueller (mueller@kde.org) 5 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2013 Apple Inc. All rights reserved. 6 * (C) 2006 Alexey Proskuryakov (ap@nypop.com) 7 * Copyright (C) 2007 Samuel Weinig (sam@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 "InputType.h" 30 31#include "AXObjectCache.h" 32#include "BeforeTextInsertedEvent.h" 33#include "ButtonInputType.h" 34#include "CheckboxInputType.h" 35#include "ColorInputType.h" 36#include "DateComponents.h" 37#include "DateInputType.h" 38#include "DateTimeInputType.h" 39#include "DateTimeLocalInputType.h" 40#include "EmailInputType.h" 41#include "ExceptionCode.h" 42#include "ExceptionCodePlaceholder.h" 43#include "FileInputType.h" 44#include "FileList.h" 45#include "FormController.h" 46#include "FormDataList.h" 47#include "HTMLFormElement.h" 48#include "HTMLInputElement.h" 49#include "HTMLNames.h" 50#include "HTMLParserIdioms.h" 51#include "HiddenInputType.h" 52#include "ImageInputType.h" 53#include "InputTypeNames.h" 54#include "KeyboardEvent.h" 55#include "LocalizedStrings.h" 56#include "MonthInputType.h" 57#include "NodeRenderStyle.h" 58#include "NumberInputType.h" 59#include "Page.h" 60#include "PasswordInputType.h" 61#include "RadioInputType.h" 62#include "RangeInputType.h" 63#include "RenderElement.h" 64#include "RenderTheme.h" 65#include "ResetInputType.h" 66#include "RuntimeEnabledFeatures.h" 67#include "ScopedEventQueue.h" 68#include "SearchInputType.h" 69#include "ShadowRoot.h" 70#include "SubmitInputType.h" 71#include "TelephoneInputType.h" 72#include "TextBreakIterator.h" 73#include "TextInputType.h" 74#include "TimeInputType.h" 75#include "URLInputType.h" 76#include "WeekInputType.h" 77#include <limits> 78#include <wtf/Assertions.h> 79#include <wtf/HashMap.h> 80#include <wtf/text/StringHash.h> 81 82namespace WebCore { 83 84using namespace HTMLNames; 85 86typedef bool (RuntimeEnabledFeatures::*InputTypeConditionalFunction)() const; 87typedef const AtomicString& (*InputTypeNameFunction)(); 88typedef std::unique_ptr<InputType> (*InputTypeFactoryFunction)(HTMLInputElement&); 89typedef HashMap<AtomicString, InputTypeFactoryFunction, CaseFoldingHash> InputTypeFactoryMap; 90 91template<class T> 92static std::unique_ptr<InputType> createInputType(HTMLInputElement& element) 93{ 94 return std::make_unique<T>(element); 95} 96 97static void populateInputTypeFactoryMap(InputTypeFactoryMap& map) 98{ 99 static const struct InputTypes { 100 InputTypeConditionalFunction conditionalFunction; 101 InputTypeNameFunction nameFunction; 102 InputTypeFactoryFunction factoryFunction; 103 } inputTypes[] = { 104 { nullptr, &InputTypeNames::button, &createInputType<ButtonInputType> }, 105 { nullptr, &InputTypeNames::checkbox, &createInputType<CheckboxInputType> }, 106#if ENABLE(INPUT_TYPE_COLOR) 107 { nullptr, &InputTypeNames::color, &createInputType<ColorInputType> }, 108#endif 109#if ENABLE(INPUT_TYPE_DATE) 110 { &RuntimeEnabledFeatures::inputTypeDateEnabled, &InputTypeNames::date, &createInputType<DateInputType> }, 111#endif 112#if ENABLE(INPUT_TYPE_DATETIME_INCOMPLETE) 113 { &RuntimeEnabledFeatures::inputTypeDateTimeEnabled, &InputTypeNames::datetime, &createInputType<DateTimeInputType> }, 114#endif 115#if ENABLE(INPUT_TYPE_DATETIMELOCAL) 116 { &RuntimeEnabledFeatures::inputTypeDateTimeLocalEnabled, &InputTypeNames::datetimelocal, &createInputType<DateTimeLocalInputType> }, 117#endif 118 { nullptr, &InputTypeNames::email, &createInputType<EmailInputType> }, 119 { nullptr, &InputTypeNames::file, &createInputType<FileInputType> }, 120 { nullptr, &InputTypeNames::hidden, &createInputType<HiddenInputType> }, 121 { nullptr, &InputTypeNames::image, &createInputType<ImageInputType> }, 122#if ENABLE(INPUT_TYPE_MONTH) 123 { &RuntimeEnabledFeatures::inputTypeMonthEnabled, &InputTypeNames::month, &createInputType<MonthInputType> }, 124#endif 125 { nullptr, &InputTypeNames::number, &createInputType<NumberInputType> }, 126 { nullptr, &InputTypeNames::password, &createInputType<PasswordInputType> }, 127 { nullptr, &InputTypeNames::radio, &createInputType<RadioInputType> }, 128 { nullptr, &InputTypeNames::range, &createInputType<RangeInputType> }, 129 { nullptr, &InputTypeNames::reset, &createInputType<ResetInputType> }, 130 { nullptr, &InputTypeNames::search, &createInputType<SearchInputType> }, 131 { nullptr, &InputTypeNames::submit, &createInputType<SubmitInputType> }, 132 { nullptr, &InputTypeNames::telephone, &createInputType<TelephoneInputType> }, 133#if ENABLE(INPUT_TYPE_TIME) 134 { &RuntimeEnabledFeatures::inputTypeTimeEnabled, &InputTypeNames::time, &createInputType<TimeInputType> }, 135#endif 136 { nullptr, &InputTypeNames::url, &createInputType<URLInputType> }, 137#if ENABLE(INPUT_TYPE_WEEK) 138 { &RuntimeEnabledFeatures::inputTypeWeekEnabled, &InputTypeNames::week, &createInputType<WeekInputType> }, 139#endif 140 // No need to register "text" because it is the default type. 141 }; 142 143 for (unsigned i = 0; i < WTF_ARRAY_LENGTH(inputTypes); ++i) { 144 auto conditionalFunction = inputTypes[i].conditionalFunction; 145 if (!conditionalFunction || (RuntimeEnabledFeatures::sharedFeatures().*conditionalFunction)()) 146 map.add(inputTypes[i].nameFunction(), inputTypes[i].factoryFunction); 147 } 148} 149 150std::unique_ptr<InputType> InputType::create(HTMLInputElement& element, const AtomicString& typeName) 151{ 152 static NeverDestroyed<InputTypeFactoryMap> factoryMap; 153 if (factoryMap.get().isEmpty()) 154 populateInputTypeFactoryMap(factoryMap); 155 156 if (!typeName.isEmpty()) { 157 if (auto factory = factoryMap.get().get(typeName)) 158 return factory(element); 159 } 160 return std::make_unique<TextInputType>(element); 161} 162 163std::unique_ptr<InputType> InputType::createText(HTMLInputElement& element) 164{ 165 return std::make_unique<TextInputType>(element); 166} 167 168InputType::~InputType() 169{ 170} 171 172bool InputType::themeSupportsDataListUI(InputType* type) 173{ 174 Document& document = type->element().document(); 175 RefPtr<RenderTheme> theme = document.page() ? &document.page()->theme() : RenderTheme::defaultTheme(); 176 return theme->supportsDataListUI(type->formControlType()); 177} 178 179bool InputType::isTextField() const 180{ 181 return false; 182} 183 184bool InputType::isTextType() const 185{ 186 return false; 187} 188 189bool InputType::isRangeControl() const 190{ 191 return false; 192} 193 194bool InputType::shouldSaveAndRestoreFormControlState() const 195{ 196 return true; 197} 198 199FormControlState InputType::saveFormControlState() const 200{ 201 String currentValue = element().value(); 202 if (currentValue == element().defaultValue()) 203 return FormControlState(); 204 return FormControlState(currentValue); 205} 206 207void InputType::restoreFormControlState(const FormControlState& state) 208{ 209 element().setValue(state[0]); 210} 211 212bool InputType::isFormDataAppendable() const 213{ 214 // There is no form data unless there's a name for non-image types. 215 return !element().name().isEmpty(); 216} 217 218bool InputType::appendFormData(FormDataList& encoding, bool) const 219{ 220 // Always successful. 221 encoding.appendData(element().name(), element().value()); 222 return true; 223} 224 225double InputType::valueAsDate() const 226{ 227 return DateComponents::invalidMilliseconds(); 228} 229 230void InputType::setValueAsDate(double, ExceptionCode& ec) const 231{ 232 ec = INVALID_STATE_ERR; 233} 234 235double InputType::valueAsDouble() const 236{ 237 return std::numeric_limits<double>::quiet_NaN(); 238} 239 240void InputType::setValueAsDouble(double doubleValue, TextFieldEventBehavior eventBehavior, ExceptionCode& ec) const 241{ 242 setValueAsDecimal(Decimal::fromDouble(doubleValue), eventBehavior, ec); 243} 244 245void InputType::setValueAsDecimal(const Decimal&, TextFieldEventBehavior, ExceptionCode& ec) const 246{ 247 ec = INVALID_STATE_ERR; 248} 249 250bool InputType::supportsValidation() const 251{ 252 return true; 253} 254 255bool InputType::typeMismatchFor(const String&) const 256{ 257 return false; 258} 259 260bool InputType::typeMismatch() const 261{ 262 return false; 263} 264 265bool InputType::supportsRequired() const 266{ 267 // Almost all validatable types support @required. 268 return supportsValidation(); 269} 270 271bool InputType::valueMissing(const String&) const 272{ 273 return false; 274} 275 276bool InputType::hasBadInput() const 277{ 278 return false; 279} 280 281bool InputType::patternMismatch(const String&) const 282{ 283 return false; 284} 285 286bool InputType::rangeUnderflow(const String& value) const 287{ 288 if (!isSteppable()) 289 return false; 290 291 const Decimal numericValue = parseToNumberOrNaN(value); 292 if (!numericValue.isFinite()) 293 return false; 294 295 return numericValue < createStepRange(RejectAny).minimum(); 296} 297 298bool InputType::rangeOverflow(const String& value) const 299{ 300 if (!isSteppable()) 301 return false; 302 303 const Decimal numericValue = parseToNumberOrNaN(value); 304 if (!numericValue.isFinite()) 305 return false; 306 307 return numericValue > createStepRange(RejectAny).maximum(); 308} 309 310Decimal InputType::defaultValueForStepUp() const 311{ 312 return 0; 313} 314 315double InputType::minimum() const 316{ 317 return createStepRange(RejectAny).minimum().toDouble(); 318} 319 320double InputType::maximum() const 321{ 322 return createStepRange(RejectAny).maximum().toDouble(); 323} 324 325bool InputType::sizeShouldIncludeDecoration(int, int& preferredSize) const 326{ 327 preferredSize = element().size(); 328 return false; 329} 330 331float InputType::decorationWidth() const 332{ 333 return 0; 334} 335 336bool InputType::isInRange(const String& value) const 337{ 338 if (!isSteppable()) 339 return false; 340 341 const Decimal numericValue = parseToNumberOrNaN(value); 342 if (!numericValue.isFinite()) 343 return true; 344 345 StepRange stepRange(createStepRange(RejectAny)); 346 return numericValue >= stepRange.minimum() && numericValue <= stepRange.maximum(); 347} 348 349bool InputType::isOutOfRange(const String& value) const 350{ 351 if (!isSteppable()) 352 return false; 353 354 const Decimal numericValue = parseToNumberOrNaN(value); 355 if (!numericValue.isFinite()) 356 return true; 357 358 StepRange stepRange(createStepRange(RejectAny)); 359 return numericValue < stepRange.minimum() || numericValue > stepRange.maximum(); 360} 361 362bool InputType::stepMismatch(const String& value) const 363{ 364 if (!isSteppable()) 365 return false; 366 367 const Decimal numericValue = parseToNumberOrNaN(value); 368 if (!numericValue.isFinite()) 369 return false; 370 371 return createStepRange(RejectAny).stepMismatch(numericValue); 372} 373 374String InputType::badInputText() const 375{ 376 ASSERT_NOT_REACHED(); 377 return validationMessageTypeMismatchText(); 378} 379 380String InputType::typeMismatchText() const 381{ 382 return validationMessageTypeMismatchText(); 383} 384 385String InputType::valueMissingText() const 386{ 387 return validationMessageValueMissingText(); 388} 389 390String InputType::validationMessage() const 391{ 392 String value = element().value(); 393 394 // The order of the following checks is meaningful. e.g. We'd like to show the 395 // badInput message even if the control has other validation errors. 396 if (hasBadInput()) 397 return badInputText(); 398 399 if (valueMissing(value)) 400 return valueMissingText(); 401 402 if (typeMismatch()) 403 return typeMismatchText(); 404 405 if (patternMismatch(value)) 406 return validationMessagePatternMismatchText(); 407 408 if (element().tooLong()) 409 return validationMessageTooLongText(numGraphemeClusters(value), element().maxLength()); 410 411 if (!isSteppable()) 412 return emptyString(); 413 414 const Decimal numericValue = parseToNumberOrNaN(value); 415 if (!numericValue.isFinite()) 416 return emptyString(); 417 418 StepRange stepRange(createStepRange(RejectAny)); 419 420 if (numericValue < stepRange.minimum()) 421 return validationMessageRangeUnderflowText(serialize(stepRange.minimum())); 422 423 if (numericValue > stepRange.maximum()) 424 return validationMessageRangeOverflowText(serialize(stepRange.maximum())); 425 426 if (stepRange.stepMismatch(numericValue)) { 427 const String stepString = stepRange.hasStep() ? serializeForNumberType(stepRange.step() / stepRange.stepScaleFactor()) : emptyString(); 428 return validationMessageStepMismatchText(serialize(stepRange.stepBase()), stepString); 429 } 430 431 return emptyString(); 432} 433 434void InputType::handleClickEvent(MouseEvent*) 435{ 436} 437 438void InputType::handleMouseDownEvent(MouseEvent*) 439{ 440} 441 442void InputType::handleDOMActivateEvent(Event*) 443{ 444} 445 446void InputType::handleKeydownEvent(KeyboardEvent*) 447{ 448} 449 450void InputType::handleKeypressEvent(KeyboardEvent*) 451{ 452} 453 454void InputType::handleKeyupEvent(KeyboardEvent*) 455{ 456} 457 458void InputType::handleBeforeTextInsertedEvent(BeforeTextInsertedEvent*) 459{ 460} 461 462#if ENABLE(TOUCH_EVENTS) 463void InputType::handleTouchEvent(TouchEvent*) 464{ 465} 466#endif 467 468void InputType::forwardEvent(Event*) 469{ 470} 471 472bool InputType::shouldSubmitImplicitly(Event* event) 473{ 474 return event->isKeyboardEvent() && event->type() == eventNames().keypressEvent && toKeyboardEvent(event)->charCode() == '\r'; 475} 476 477PassRefPtr<HTMLFormElement> InputType::formForSubmission() const 478{ 479 return element().form(); 480} 481 482RenderPtr<RenderElement> InputType::createInputRenderer(PassRef<RenderStyle> style) 483{ 484 return RenderPtr<RenderElement>(RenderElement::createFor(element(), WTF::move(style))); 485} 486 487void InputType::blur() 488{ 489 element().defaultBlur(); 490} 491 492void InputType::createShadowSubtree() 493{ 494} 495 496void InputType::destroyShadowSubtree() 497{ 498 ShadowRoot* root = element().userAgentShadowRoot(); 499 if (!root) 500 return; 501 502 root->removeChildren(); 503} 504 505Decimal InputType::parseToNumber(const String&, const Decimal& defaultValue) const 506{ 507 ASSERT_NOT_REACHED(); 508 return defaultValue; 509} 510 511Decimal InputType::parseToNumberOrNaN(const String& string) const 512{ 513 return parseToNumber(string, Decimal::nan()); 514} 515 516bool InputType::parseToDateComponents(const String&, DateComponents*) const 517{ 518 ASSERT_NOT_REACHED(); 519 return false; 520} 521 522String InputType::serialize(const Decimal&) const 523{ 524 ASSERT_NOT_REACHED(); 525 return String(); 526} 527 528#if PLATFORM(IOS) 529DateComponents::Type InputType::dateType() const 530{ 531 return DateComponents::Invalid; 532} 533#endif 534 535void InputType::dispatchSimulatedClickIfActive(KeyboardEvent* event) const 536{ 537 if (element().active()) 538 element().dispatchSimulatedClick(event); 539 event->setDefaultHandled(); 540} 541 542Chrome* InputType::chrome() const 543{ 544 if (Page* page = element().document().page()) 545 return &page->chrome(); 546 return 0; 547} 548 549bool InputType::canSetStringValue() const 550{ 551 return true; 552} 553 554bool InputType::hasCustomFocusLogic() const 555{ 556 return true; 557} 558 559bool InputType::isKeyboardFocusable(KeyboardEvent* event) const 560{ 561 return !element().isReadOnly() && element().isTextFormControlKeyboardFocusable(event); 562} 563 564bool InputType::isMouseFocusable() const 565{ 566 return element().isTextFormControlMouseFocusable(); 567} 568 569bool InputType::shouldUseInputMethod() const 570{ 571 return false; 572} 573 574void InputType::handleFocusEvent(Node*, FocusDirection) 575{ 576} 577 578void InputType::handleBlurEvent() 579{ 580} 581 582void InputType::accessKeyAction(bool) 583{ 584 element().focus(false); 585} 586 587void InputType::addSearchResult() 588{ 589} 590 591void InputType::attach() 592{ 593} 594 595void InputType::detach() 596{ 597} 598 599void InputType::altAttributeChanged() 600{ 601} 602 603void InputType::srcAttributeChanged() 604{ 605} 606 607bool InputType::shouldRespectAlignAttribute() 608{ 609 return false; 610} 611 612bool InputType::canChangeFromAnotherType() const 613{ 614 return true; 615} 616 617void InputType::minOrMaxAttributeChanged() 618{ 619} 620 621void InputType::stepAttributeChanged() 622{ 623} 624 625bool InputType::canBeSuccessfulSubmitButton() 626{ 627 return false; 628} 629 630HTMLElement* InputType::placeholderElement() const 631{ 632 return 0; 633} 634 635bool InputType::rendererIsNeeded() 636{ 637 return true; 638} 639 640FileList* InputType::files() 641{ 642 return 0; 643} 644 645void InputType::setFiles(PassRefPtr<FileList>) 646{ 647} 648 649bool InputType::getTypeSpecificValue(String&) 650{ 651 return false; 652} 653 654String InputType::fallbackValue() const 655{ 656 return String(); 657} 658 659String InputType::defaultValue() const 660{ 661 return String(); 662} 663 664bool InputType::canSetSuggestedValue() 665{ 666 return false; 667} 668 669bool InputType::shouldSendChangeEventAfterCheckedChanged() 670{ 671 return true; 672} 673 674bool InputType::storesValueSeparateFromAttribute() 675{ 676 return true; 677} 678 679void InputType::setValue(const String& sanitizedValue, bool valueChanged, TextFieldEventBehavior eventBehavior) 680{ 681 element().setValueInternal(sanitizedValue, eventBehavior); 682 element().setNeedsStyleRecalc(); 683 if (!valueChanged) 684 return; 685 switch (eventBehavior) { 686 case DispatchChangeEvent: 687 element().dispatchFormControlChangeEvent(); 688 break; 689 case DispatchInputAndChangeEvent: 690 element().dispatchFormControlInputEvent(); 691 element().dispatchFormControlChangeEvent(); 692 break; 693 case DispatchNoEvent: 694 break; 695 } 696} 697 698bool InputType::canSetValue(const String&) 699{ 700 return true; 701} 702 703void InputType::willDispatchClick(InputElementClickState&) 704{ 705} 706 707void InputType::didDispatchClick(Event*, const InputElementClickState&) 708{ 709} 710 711String InputType::localizeValue(const String& proposedValue) const 712{ 713 return proposedValue; 714} 715 716String InputType::visibleValue() const 717{ 718 return element().value(); 719} 720 721String InputType::sanitizeValue(const String& proposedValue) const 722{ 723 return proposedValue; 724} 725 726#if ENABLE(DRAG_SUPPORT) 727bool InputType::receiveDroppedFiles(const DragData&) 728{ 729 ASSERT_NOT_REACHED(); 730 return false; 731} 732#endif 733 734Icon* InputType::icon() const 735{ 736 ASSERT_NOT_REACHED(); 737 return 0; 738} 739 740#if PLATFORM(IOS) 741String InputType::displayString() const 742{ 743 ASSERT_NOT_REACHED(); 744 return String(); 745} 746#endif 747 748bool InputType::shouldResetOnDocumentActivation() 749{ 750 return false; 751} 752 753bool InputType::shouldRespectListAttribute() 754{ 755 return false; 756} 757 758bool InputType::shouldRespectSpeechAttribute() 759{ 760 return false; 761} 762 763bool InputType::isTextButton() const 764{ 765 return false; 766} 767 768bool InputType::isRadioButton() const 769{ 770 return false; 771} 772 773bool InputType::isSearchField() const 774{ 775 return false; 776} 777 778bool InputType::isHiddenType() const 779{ 780 return false; 781} 782 783bool InputType::isPasswordField() const 784{ 785 return false; 786} 787 788bool InputType::isCheckbox() const 789{ 790 return false; 791} 792 793bool InputType::isEmailField() const 794{ 795 return false; 796} 797 798bool InputType::isFileUpload() const 799{ 800 return false; 801} 802 803bool InputType::isImageButton() const 804{ 805 return false; 806} 807 808bool InputType::supportLabels() const 809{ 810 return true; 811} 812 813bool InputType::isNumberField() const 814{ 815 return false; 816} 817 818bool InputType::isSubmitButton() const 819{ 820 return false; 821} 822 823bool InputType::isTelephoneField() const 824{ 825 return false; 826} 827 828bool InputType::isURLField() const 829{ 830 return false; 831} 832 833bool InputType::isDateField() const 834{ 835 return false; 836} 837 838bool InputType::isDateTimeField() const 839{ 840 return false; 841} 842 843bool InputType::isDateTimeLocalField() const 844{ 845 return false; 846} 847 848bool InputType::isMonthField() const 849{ 850 return false; 851} 852 853bool InputType::isTimeField() const 854{ 855 return false; 856} 857 858bool InputType::isWeekField() const 859{ 860 return false; 861} 862 863bool InputType::isEnumeratable() 864{ 865 return true; 866} 867 868bool InputType::isCheckable() 869{ 870 return false; 871} 872 873bool InputType::isSteppable() const 874{ 875 return false; 876} 877 878#if ENABLE(INPUT_TYPE_COLOR) 879bool InputType::isColorControl() const 880{ 881 return false; 882} 883#endif 884 885bool InputType::shouldRespectHeightAndWidthAttributes() 886{ 887 return false; 888} 889 890bool InputType::supportsPlaceholder() const 891{ 892 return false; 893} 894 895bool InputType::supportsReadOnly() const 896{ 897 return false; 898} 899 900void InputType::updateInnerTextValue() 901{ 902} 903 904void InputType::updatePlaceholderText() 905{ 906} 907 908void InputType::attributeChanged() 909{ 910} 911 912void InputType::multipleAttributeChanged() 913{ 914} 915 916void InputType::disabledAttributeChanged() 917{ 918} 919 920void InputType::readonlyAttributeChanged() 921{ 922} 923 924void InputType::requiredAttributeChanged() 925{ 926} 927 928void InputType::valueAttributeChanged() 929{ 930} 931 932void InputType::subtreeHasChanged() 933{ 934 ASSERT_NOT_REACHED(); 935} 936 937#if ENABLE(TOUCH_EVENTS) 938bool InputType::hasTouchEventHandler() const 939{ 940 return false; 941} 942#endif 943 944String InputType::defaultToolTip() const 945{ 946 return String(); 947} 948 949#if ENABLE(DATALIST_ELEMENT) 950void InputType::listAttributeTargetChanged() 951{ 952} 953 954Decimal InputType::findClosestTickMarkValue(const Decimal&) 955{ 956 ASSERT_NOT_REACHED(); 957 return Decimal::nan(); 958} 959#endif 960 961void InputType::updateClearButtonVisibility() 962{ 963} 964 965bool InputType::supportsIndeterminateAppearance() const 966{ 967 return false; 968} 969 970bool InputType::supportsSelectionAPI() const 971{ 972 return false; 973} 974 975unsigned InputType::height() const 976{ 977 return 0; 978} 979 980unsigned InputType::width() const 981{ 982 return 0; 983} 984 985void InputType::applyStep(int count, AnyStepHandling anyStepHandling, TextFieldEventBehavior eventBehavior, ExceptionCode& ec) 986{ 987 StepRange stepRange(createStepRange(anyStepHandling)); 988 if (!stepRange.hasStep()) { 989 ec = INVALID_STATE_ERR; 990 return; 991 } 992 993 const Decimal current = parseToNumberOrNaN(element().value()); 994 if (!current.isFinite()) { 995 ec = INVALID_STATE_ERR; 996 return; 997 } 998 Decimal newValue = current + stepRange.step() * count; 999 if (!newValue.isFinite()) { 1000 ec = INVALID_STATE_ERR; 1001 return; 1002 } 1003 1004 const Decimal acceptableErrorValue = stepRange.acceptableError(); 1005 if (newValue - stepRange.minimum() < -acceptableErrorValue) { 1006 ec = INVALID_STATE_ERR; 1007 return; 1008 } 1009 if (newValue < stepRange.minimum()) 1010 newValue = stepRange.minimum(); 1011 1012 const AtomicString& stepString = element().fastGetAttribute(stepAttr); 1013 if (!equalIgnoringCase(stepString, "any")) 1014 newValue = stepRange.alignValueForStep(current, newValue); 1015 1016 if (newValue - stepRange.maximum() > acceptableErrorValue) { 1017 ec = INVALID_STATE_ERR; 1018 return; 1019 } 1020 if (newValue > stepRange.maximum()) 1021 newValue = stepRange.maximum(); 1022 1023 setValueAsDecimal(newValue, eventBehavior, ec); 1024 1025 if (AXObjectCache* cache = element().document().existingAXObjectCache()) 1026 cache->postNotification(&element(), AXObjectCache::AXValueChanged); 1027} 1028 1029bool InputType::getAllowedValueStep(Decimal* step) const 1030{ 1031 StepRange stepRange(createStepRange(RejectAny)); 1032 *step = stepRange.step(); 1033 return stepRange.hasStep(); 1034} 1035 1036StepRange InputType::createStepRange(AnyStepHandling) const 1037{ 1038 ASSERT_NOT_REACHED(); 1039 return StepRange(); 1040} 1041 1042void InputType::stepUp(int n, ExceptionCode& ec) 1043{ 1044 if (!isSteppable()) { 1045 ec = INVALID_STATE_ERR; 1046 return; 1047 } 1048 applyStep(n, RejectAny, DispatchNoEvent, ec); 1049} 1050 1051void InputType::stepUpFromRenderer(int n) 1052{ 1053 // The differences from stepUp()/stepDown(): 1054 // 1055 // Difference 1: the current value 1056 // If the current value is not a number, including empty, the current value is assumed as 0. 1057 // * If 0 is in-range, and matches to step value 1058 // - The value should be the +step if n > 0 1059 // - The value should be the -step if n < 0 1060 // If -step or +step is out of range, new value should be 0. 1061 // * If 0 is smaller than the minimum value 1062 // - The value should be the minimum value for any n 1063 // * If 0 is larger than the maximum value 1064 // - The value should be the maximum value for any n 1065 // * If 0 is in-range, but not matched to step value 1066 // - The value should be the larger matched value nearest to 0 if n > 0 1067 // e.g. <input type=number min=-100 step=3> -> 2 1068 // - The value should be the smaler matched value nearest to 0 if n < 0 1069 // e.g. <input type=number min=-100 step=3> -> -1 1070 // As for date/datetime-local/month/time/week types, the current value is assumed as "the current local date/time". 1071 // As for datetime type, the current value is assumed as "the current date/time in UTC". 1072 // If the current value is smaller than the minimum value: 1073 // - The value should be the minimum value if n > 0 1074 // - Nothing should happen if n < 0 1075 // If the current value is larger than the maximum value: 1076 // - The value should be the maximum value if n < 0 1077 // - Nothing should happen if n > 0 1078 // 1079 // Difference 2: clamping steps 1080 // If the current value is not matched to step value: 1081 // - The value should be the larger matched value nearest to 0 if n > 0 1082 // e.g. <input type=number value=3 min=-100 step=3> -> 5 1083 // - The value should be the smaler matched value nearest to 0 if n < 0 1084 // e.g. <input type=number value=3 min=-100 step=3> -> 2 1085 // 1086 // n is assumed as -n if step < 0. 1087 1088 ASSERT(isSteppable()); 1089 if (!isSteppable()) 1090 return; 1091 ASSERT(n); 1092 if (!n) 1093 return; 1094 1095 StepRange stepRange(createStepRange(AnyIsDefaultStep)); 1096 1097 // FIXME: Not any changes after stepping, even if it is an invalid value, may be better. 1098 // (e.g. Stepping-up for <input type="number" value="foo" step="any" /> => "foo") 1099 if (!stepRange.hasStep()) 1100 return; 1101 1102 EventQueueScope scope; 1103 const Decimal step = stepRange.step(); 1104 1105 int sign; 1106 if (step > 0) 1107 sign = n; 1108 else if (step < 0) 1109 sign = -n; 1110 else 1111 sign = 0; 1112 1113 String currentStringValue = element().value(); 1114 Decimal current = parseToNumberOrNaN(currentStringValue); 1115 if (!current.isFinite()) { 1116 current = defaultValueForStepUp(); 1117 const Decimal nextDiff = step * n; 1118 if (current < stepRange.minimum() - nextDiff) 1119 current = stepRange.minimum() - nextDiff; 1120 if (current > stepRange.maximum() - nextDiff) 1121 current = stepRange.maximum() - nextDiff; 1122 setValueAsDecimal(current, DispatchNoEvent, IGNORE_EXCEPTION); 1123 } 1124 if ((sign > 0 && current < stepRange.minimum()) || (sign < 0 && current > stepRange.maximum())) 1125 setValueAsDecimal(sign > 0 ? stepRange.minimum() : stepRange.maximum(), DispatchInputAndChangeEvent, IGNORE_EXCEPTION); 1126 else { 1127 if (stepMismatch(element().value())) { 1128 ASSERT(!step.isZero()); 1129 const Decimal base = stepRange.stepBase(); 1130 Decimal newValue; 1131 if (sign < 0) 1132 newValue = base + ((current - base) / step).floor() * step; 1133 else if (sign > 0) 1134 newValue = base + ((current - base) / step).ceiling() * step; 1135 else 1136 newValue = current; 1137 1138 if (newValue < stepRange.minimum()) 1139 newValue = stepRange.minimum(); 1140 if (newValue > stepRange.maximum()) 1141 newValue = stepRange.maximum(); 1142 1143 setValueAsDecimal(newValue, n == 1 || n == -1 ? DispatchInputAndChangeEvent : DispatchNoEvent, IGNORE_EXCEPTION); 1144 if (n > 1) 1145 applyStep(n - 1, AnyIsDefaultStep, DispatchInputAndChangeEvent, IGNORE_EXCEPTION); 1146 else if (n < -1) 1147 applyStep(n + 1, AnyIsDefaultStep, DispatchInputAndChangeEvent, IGNORE_EXCEPTION); 1148 } else 1149 applyStep(n, AnyIsDefaultStep, DispatchInputAndChangeEvent, IGNORE_EXCEPTION); 1150 } 1151} 1152 1153} // namespace WebCore 1154