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