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