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