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