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