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