Remove FeatureObserver.
[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 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 "ExceptionCode.h"
42 #include "ExceptionCodePlaceholder.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 "TextBreakIterator.h"
73 #include "TextInputType.h"
74 #include "TimeInputType.h"
75 #include "URLInputType.h"
76 #include "WeekInputType.h"
77 #include <limits>
78 #include <wtf/Assertions.h>
79 #include <wtf/HashMap.h>
80 #include <wtf/text/StringHash.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, CaseFoldingHash> 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 (unsigned i = 0; i < WTF_ARRAY_LENGTH(inputTypes); ++i) {
144         auto conditionalFunction = inputTypes[i].conditionalFunction;
145         if (!conditionalFunction || (RuntimeEnabledFeatures::sharedFeatures().*conditionalFunction)())
146             map.add(inputTypes[i].nameFunction(), inputTypes[i].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     Document& document = type->element().document();
175     RefPtr<RenderTheme> theme = document.page() ? &document.page()->theme() : RenderTheme::defaultTheme();
176     return theme->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 void InputType::setValueAsDate(double, ExceptionCode& ec) const
231 {
232     ec = INVALID_STATE_ERR;
233 }
234
235 double InputType::valueAsDouble() const
236 {
237     return std::numeric_limits<double>::quiet_NaN();
238 }
239
240 void InputType::setValueAsDouble(double doubleValue, TextFieldEventBehavior eventBehavior, ExceptionCode& ec) const
241 {
242     setValueAsDecimal(Decimal::fromDouble(doubleValue), eventBehavior, ec);
243 }
244
245 void InputType::setValueAsDecimal(const Decimal&, TextFieldEventBehavior, ExceptionCode& ec) const
246 {
247     ec = 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     const Decimal numericValue = parseToNumberOrNaN(value);
342     if (!numericValue.isFinite())
343         return true;
344
345     StepRange stepRange(createStepRange(RejectAny));
346     return numericValue >= stepRange.minimum() && numericValue <= stepRange.maximum();
347 }
348
349 bool InputType::isOutOfRange(const String& value) const
350 {
351     if (!isSteppable())
352         return false;
353
354     const Decimal numericValue = parseToNumberOrNaN(value);
355     if (!numericValue.isFinite())
356         return true;
357
358     StepRange stepRange(createStepRange(RejectAny));
359     return numericValue < stepRange.minimum() || numericValue > stepRange.maximum();
360 }
361
362 bool InputType::stepMismatch(const String& value) const
363 {
364     if (!isSteppable())
365         return false;
366
367     const Decimal numericValue = parseToNumberOrNaN(value);
368     if (!numericValue.isFinite())
369         return false;
370
371     return createStepRange(RejectAny).stepMismatch(numericValue);
372 }
373
374 String InputType::badInputText() const
375 {
376     ASSERT_NOT_REACHED();
377     return validationMessageTypeMismatchText();
378 }
379
380 String InputType::typeMismatchText() const
381 {
382     return validationMessageTypeMismatchText();
383 }
384
385 String InputType::valueMissingText() const
386 {
387     return validationMessageValueMissingText();
388 }
389
390 String InputType::validationMessage() const
391 {
392     String value = element().value();
393
394     // The order of the following checks is meaningful. e.g. We'd like to show the
395     // badInput message even if the control has other validation errors.
396     if (hasBadInput())
397         return badInputText();
398
399     if (valueMissing(value))
400         return valueMissingText();
401
402     if (typeMismatch())
403         return typeMismatchText();
404
405     if (patternMismatch(value))
406         return validationMessagePatternMismatchText();
407
408     if (element().tooLong())
409         return validationMessageTooLongText(numGraphemeClusters(value), element().maxLength());
410
411     if (!isSteppable())
412         return emptyString();
413
414     const Decimal numericValue = parseToNumberOrNaN(value);
415     if (!numericValue.isFinite())
416         return emptyString();
417
418     StepRange stepRange(createStepRange(RejectAny));
419
420     if (numericValue < stepRange.minimum())
421         return validationMessageRangeUnderflowText(serialize(stepRange.minimum()));
422
423     if (numericValue > stepRange.maximum())
424         return validationMessageRangeOverflowText(serialize(stepRange.maximum()));
425
426     if (stepRange.stepMismatch(numericValue)) {
427         const String stepString = stepRange.hasStep() ? serializeForNumberType(stepRange.step() / stepRange.stepScaleFactor()) : emptyString();
428         return validationMessageStepMismatchText(serialize(stepRange.stepBase()), stepString);
429     }
430
431     return emptyString();
432 }
433
434 void InputType::handleClickEvent(MouseEvent*)
435 {
436 }
437
438 void InputType::handleMouseDownEvent(MouseEvent*)
439 {
440 }
441
442 void InputType::handleDOMActivateEvent(Event*)
443 {
444 }
445
446 void InputType::handleKeydownEvent(KeyboardEvent*)
447 {
448 }
449
450 void InputType::handleKeypressEvent(KeyboardEvent*)
451 {
452 }
453
454 void InputType::handleKeyupEvent(KeyboardEvent*)
455 {
456 }
457
458 void InputType::handleBeforeTextInsertedEvent(BeforeTextInsertedEvent*)
459 {
460 }
461
462 #if ENABLE(TOUCH_EVENTS)
463 void InputType::handleTouchEvent(TouchEvent*)
464 {
465 }
466 #endif
467
468 void InputType::forwardEvent(Event*)
469 {
470 }
471
472 bool InputType::shouldSubmitImplicitly(Event* event)
473 {
474     return event->isKeyboardEvent() && event->type() == eventNames().keypressEvent && toKeyboardEvent(event)->charCode() == '\r';
475 }
476
477 PassRefPtr<HTMLFormElement> InputType::formForSubmission() const
478 {
479     return element().form();
480 }
481
482 RenderPtr<RenderElement> InputType::createInputRenderer(PassRef<RenderStyle> style)
483 {
484     return RenderPtr<RenderElement>(RenderElement::createFor(element(), std::move(style)));
485 }
486
487 void InputType::blur()
488 {
489     element().defaultBlur();
490 }
491
492 void InputType::createShadowSubtree()
493 {
494 }
495
496 void InputType::destroyShadowSubtree()
497 {
498     ShadowRoot* root = element().userAgentShadowRoot();
499     if (!root)
500         return;
501
502     root->removeChildren();
503 }
504
505 Decimal InputType::parseToNumber(const String&, const Decimal& defaultValue) const
506 {
507     ASSERT_NOT_REACHED();
508     return defaultValue;
509 }
510
511 Decimal InputType::parseToNumberOrNaN(const String& string) const
512 {
513     return parseToNumber(string, Decimal::nan());
514 }
515
516 bool InputType::parseToDateComponents(const String&, DateComponents*) const
517 {
518     ASSERT_NOT_REACHED();
519     return false;
520 }
521
522 String InputType::serialize(const Decimal&) const
523 {
524     ASSERT_NOT_REACHED();
525     return String();
526 }
527
528 #if PLATFORM(IOS)
529 DateComponents::Type InputType::dateType() const
530 {
531     return DateComponents::Invalid;
532 }
533 #endif
534
535 void InputType::dispatchSimulatedClickIfActive(KeyboardEvent* event) const
536 {
537     if (element().active())
538         element().dispatchSimulatedClick(event);
539     event->setDefaultHandled();
540 }
541
542 Chrome* InputType::chrome() const
543 {
544     if (Page* page = element().document().page())
545         return &page->chrome();
546     return 0;
547 }
548
549 bool InputType::canSetStringValue() const
550 {
551     return true;
552 }
553
554 bool InputType::hasCustomFocusLogic() const
555 {
556     return true;
557 }
558
559 bool InputType::isKeyboardFocusable(KeyboardEvent* event) const
560 {
561     return !element().isReadOnly() && element().isTextFormControlKeyboardFocusable(event);
562 }
563
564 bool InputType::isMouseFocusable() const
565 {
566     return element().isTextFormControlMouseFocusable();
567 }
568
569 bool InputType::shouldUseInputMethod() const
570 {
571     return false;
572 }
573
574 void InputType::handleFocusEvent(Node*, FocusDirection)
575 {
576 }
577
578 void InputType::handleBlurEvent()
579 {
580 }
581
582 void InputType::accessKeyAction(bool)
583 {
584     element().focus(false);
585 }
586
587 void InputType::addSearchResult()
588 {
589 }
590
591 void InputType::attach()
592 {
593 }
594
595 void InputType::detach()
596 {
597 }
598
599 void InputType::altAttributeChanged()
600 {
601 }
602
603 void InputType::srcAttributeChanged()
604 {
605 }
606
607 bool InputType::shouldRespectAlignAttribute()
608 {
609     return false;
610 }
611
612 bool InputType::canChangeFromAnotherType() const
613 {
614     return true;
615 }
616
617 void InputType::minOrMaxAttributeChanged()
618 {
619 }
620
621 void InputType::stepAttributeChanged()
622 {
623 }
624
625 bool InputType::canBeSuccessfulSubmitButton()
626 {
627     return false;
628 }
629
630 HTMLElement* InputType::placeholderElement() const
631 {
632     return 0;
633 }
634
635 bool InputType::rendererIsNeeded()
636 {
637     return true;
638 }
639
640 FileList* InputType::files()
641 {
642     return 0;
643 }
644
645 void InputType::setFiles(PassRefPtr<FileList>)
646 {
647 }
648
649 bool InputType::getTypeSpecificValue(String&)
650 {
651     return false;
652 }
653
654 String InputType::fallbackValue() const
655 {
656     return String();
657 }
658
659 String InputType::defaultValue() const
660 {
661     return String();
662 }
663
664 bool InputType::canSetSuggestedValue()
665 {
666     return false;
667 }
668
669 bool InputType::shouldSendChangeEventAfterCheckedChanged()
670 {
671     return true;
672 }
673
674 bool InputType::storesValueSeparateFromAttribute()
675 {
676     return true;
677 }
678
679 void InputType::setValue(const String& sanitizedValue, bool valueChanged, TextFieldEventBehavior eventBehavior)
680 {
681     element().setValueInternal(sanitizedValue, eventBehavior);
682     element().setNeedsStyleRecalc();
683     if (!valueChanged)
684         return;
685     switch (eventBehavior) {
686     case DispatchChangeEvent:
687         element().dispatchFormControlChangeEvent();
688         break;
689     case DispatchInputAndChangeEvent:
690         element().dispatchFormControlInputEvent();
691         element().dispatchFormControlChangeEvent();
692         break;
693     case DispatchNoEvent:
694         break;
695     }
696 }
697
698 bool InputType::canSetValue(const String&)
699 {
700     return true;
701 }
702
703 void InputType::willDispatchClick(InputElementClickState&)
704 {
705 }
706
707 void InputType::didDispatchClick(Event*, const InputElementClickState&)
708 {
709 }
710
711 String InputType::localizeValue(const String& proposedValue) const
712 {
713     return proposedValue;
714 }
715
716 String InputType::visibleValue() const
717 {
718     return element().value();
719 }
720
721 String InputType::sanitizeValue(const String& proposedValue) const
722 {
723     return proposedValue;
724 }
725
726 #if ENABLE(DRAG_SUPPORT)
727 bool InputType::receiveDroppedFiles(const DragData&)
728 {
729     ASSERT_NOT_REACHED();
730     return false;
731 }
732 #endif
733
734 Icon* InputType::icon() const
735 {
736     ASSERT_NOT_REACHED();
737     return 0;
738 }
739
740 #if PLATFORM(IOS)
741 String InputType::displayString() const
742 {
743     ASSERT_NOT_REACHED();
744     return String();
745 }
746 #endif
747
748 bool InputType::shouldResetOnDocumentActivation()
749 {
750     return false;
751 }
752
753 bool InputType::shouldRespectListAttribute()
754 {
755     return false;
756 }
757
758 bool InputType::shouldRespectSpeechAttribute()
759 {
760     return false;
761 }
762
763 bool InputType::isTextButton() const
764 {
765     return false;
766 }
767
768 bool InputType::isRadioButton() const
769 {
770     return false;
771 }
772
773 bool InputType::isSearchField() const
774 {
775     return false;
776 }
777
778 bool InputType::isHiddenType() const
779 {
780     return false;
781 }
782
783 bool InputType::isPasswordField() const
784 {
785     return false;
786 }
787
788 bool InputType::isCheckbox() const
789 {
790     return false;
791 }
792
793 bool InputType::isEmailField() const
794 {
795     return false;
796 }
797
798 bool InputType::isFileUpload() const
799 {
800     return false;
801 }
802
803 bool InputType::isImageButton() const
804 {
805     return false;
806 }
807
808 bool InputType::supportLabels() const
809 {
810     return true;
811 }
812
813 bool InputType::isNumberField() const
814 {
815     return false;
816 }
817
818 bool InputType::isSubmitButton() const
819 {
820     return false;
821 }
822
823 bool InputType::isTelephoneField() const
824 {
825     return false;
826 }
827
828 bool InputType::isURLField() const
829 {
830     return false;
831 }
832
833 bool InputType::isDateField() const
834 {
835     return false;
836 }
837
838 bool InputType::isDateTimeField() const
839 {
840     return false;
841 }
842
843 bool InputType::isDateTimeLocalField() const
844 {
845     return false;
846 }
847
848 bool InputType::isMonthField() const
849 {
850     return false;
851 }
852
853 bool InputType::isTimeField() const
854 {
855     return false;
856 }
857
858 bool InputType::isWeekField() const
859 {
860     return false;
861 }
862
863 bool InputType::isEnumeratable()
864 {
865     return true;
866 }
867
868 bool InputType::isCheckable()
869 {
870     return false;
871 }
872
873 bool InputType::isSteppable() const
874 {
875     return false;
876 }
877
878 #if ENABLE(INPUT_TYPE_COLOR)
879 bool InputType::isColorControl() const
880 {
881     return false;
882 }
883 #endif
884
885 bool InputType::shouldRespectHeightAndWidthAttributes()
886 {
887     return false;
888 }
889
890 bool InputType::supportsPlaceholder() const
891 {
892     return false;
893 }
894
895 bool InputType::supportsReadOnly() const
896 {
897     return false;
898 }
899
900 void InputType::updateInnerTextValue()
901 {
902 }
903
904 void InputType::updatePlaceholderText()
905 {
906 }
907
908 void InputType::attributeChanged()
909 {
910 }
911
912 void InputType::multipleAttributeChanged()
913 {
914 }
915
916 void InputType::disabledAttributeChanged()
917 {
918 }
919
920 void InputType::readonlyAttributeChanged()
921 {
922 }
923
924 void InputType::requiredAttributeChanged()
925 {
926 }
927
928 void InputType::valueAttributeChanged()
929 {
930 }
931
932 void InputType::subtreeHasChanged()
933 {
934     ASSERT_NOT_REACHED();
935 }
936
937 #if ENABLE(TOUCH_EVENTS)
938 bool InputType::hasTouchEventHandler() const
939 {
940     return false;
941 }
942 #endif
943
944 String InputType::defaultToolTip() const
945 {
946     return String();
947 }
948
949 #if ENABLE(DATALIST_ELEMENT)
950 void InputType::listAttributeTargetChanged()
951 {
952 }
953
954 Decimal InputType::findClosestTickMarkValue(const Decimal&)
955 {
956     ASSERT_NOT_REACHED();
957     return Decimal::nan();
958 }
959 #endif
960
961 void InputType::updateClearButtonVisibility()
962 {
963 }
964
965 bool InputType::supportsIndeterminateAppearance() const
966 {
967     return false;
968 }
969
970 bool InputType::supportsSelectionAPI() const
971 {
972     return false;
973 }
974
975 unsigned InputType::height() const
976 {
977     return 0;
978 }
979
980 unsigned InputType::width() const
981 {
982     return 0;
983 }
984
985 void InputType::applyStep(int count, AnyStepHandling anyStepHandling, TextFieldEventBehavior eventBehavior, ExceptionCode& ec)
986 {
987     StepRange stepRange(createStepRange(anyStepHandling));
988     if (!stepRange.hasStep()) {
989         ec = INVALID_STATE_ERR;
990         return;
991     }
992
993     const Decimal current = parseToNumberOrNaN(element().value());
994     if (!current.isFinite()) {
995         ec = INVALID_STATE_ERR;
996         return;
997     }
998     Decimal newValue = current + stepRange.step() * count;
999     if (!newValue.isFinite()) {
1000         ec = INVALID_STATE_ERR;
1001         return;
1002     }
1003
1004     const Decimal acceptableErrorValue = stepRange.acceptableError();
1005     if (newValue - stepRange.minimum() < -acceptableErrorValue) {
1006         ec = INVALID_STATE_ERR;
1007         return;
1008     }
1009     if (newValue < stepRange.minimum())
1010         newValue = stepRange.minimum();
1011
1012     const AtomicString& stepString = element().fastGetAttribute(stepAttr);
1013     if (!equalIgnoringCase(stepString, "any"))
1014         newValue = stepRange.alignValueForStep(current, newValue);
1015
1016     if (newValue - stepRange.maximum() > acceptableErrorValue) {
1017         ec = INVALID_STATE_ERR;
1018         return;
1019     }
1020     if (newValue > stepRange.maximum())
1021         newValue = stepRange.maximum();
1022
1023     setValueAsDecimal(newValue, eventBehavior, ec);
1024
1025     if (AXObjectCache* cache = element().document().existingAXObjectCache())
1026         cache->postNotification(&element(), AXObjectCache::AXValueChanged);
1027 }
1028
1029 bool InputType::getAllowedValueStep(Decimal* step) const
1030 {
1031     StepRange stepRange(createStepRange(RejectAny));
1032     *step = stepRange.step();
1033     return stepRange.hasStep();
1034 }
1035
1036 StepRange InputType::createStepRange(AnyStepHandling) const
1037 {
1038     ASSERT_NOT_REACHED();
1039     return StepRange();
1040 }
1041
1042 void InputType::stepUp(int n, ExceptionCode& ec)
1043 {
1044     if (!isSteppable()) {
1045         ec = INVALID_STATE_ERR;
1046         return;
1047     }
1048     applyStep(n, RejectAny, DispatchNoEvent, ec);
1049 }
1050
1051 void InputType::stepUpFromRenderer(int n)
1052 {
1053     // The differences from stepUp()/stepDown():
1054     //
1055     // Difference 1: the current value
1056     // If the current value is not a number, including empty, the current value is assumed as 0.
1057     //   * If 0 is in-range, and matches to step value
1058     //     - The value should be the +step if n > 0
1059     //     - The value should be the -step if n < 0
1060     //     If -step or +step is out of range, new value should be 0.
1061     //   * If 0 is smaller than the minimum value
1062     //     - The value should be the minimum value for any n
1063     //   * If 0 is larger than the maximum value
1064     //     - The value should be the maximum value for any n
1065     //   * If 0 is in-range, but not matched to step value
1066     //     - The value should be the larger matched value nearest to 0 if n > 0
1067     //       e.g. <input type=number min=-100 step=3> -> 2
1068     //     - The value should be the smaler matched value nearest to 0 if n < 0
1069     //       e.g. <input type=number min=-100 step=3> -> -1
1070     //   As for date/datetime-local/month/time/week types, the current value is assumed as "the current local date/time".
1071     //   As for datetime type, the current value is assumed as "the current date/time in UTC".
1072     // If the current value is smaller than the minimum value:
1073     //  - The value should be the minimum value if n > 0
1074     //  - Nothing should happen if n < 0
1075     // If the current value is larger than the maximum value:
1076     //  - The value should be the maximum value if n < 0
1077     //  - Nothing should happen if n > 0
1078     //
1079     // Difference 2: clamping steps
1080     // If the current value is not matched to step value:
1081     // - The value should be the larger matched value nearest to 0 if n > 0
1082     //   e.g. <input type=number value=3 min=-100 step=3> -> 5
1083     // - The value should be the smaler matched value nearest to 0 if n < 0
1084     //   e.g. <input type=number value=3 min=-100 step=3> -> 2
1085     //
1086     // n is assumed as -n if step < 0.
1087
1088     ASSERT(isSteppable());
1089     if (!isSteppable())
1090         return;
1091     ASSERT(n);
1092     if (!n)
1093         return;
1094
1095     StepRange stepRange(createStepRange(AnyIsDefaultStep));
1096
1097     // FIXME: Not any changes after stepping, even if it is an invalid value, may be better.
1098     // (e.g. Stepping-up for <input type="number" value="foo" step="any" /> => "foo")
1099     if (!stepRange.hasStep())
1100       return;
1101
1102     EventQueueScope scope;
1103     const Decimal step = stepRange.step();
1104
1105     int sign;
1106     if (step > 0)
1107         sign = n;
1108     else if (step < 0)
1109         sign = -n;
1110     else
1111         sign = 0;
1112
1113     String currentStringValue = element().value();
1114     Decimal current = parseToNumberOrNaN(currentStringValue);
1115     if (!current.isFinite()) {
1116         current = defaultValueForStepUp();
1117         const Decimal nextDiff = step * n;
1118         if (current < stepRange.minimum() - nextDiff)
1119             current = stepRange.minimum() - nextDiff;
1120         if (current > stepRange.maximum() - nextDiff)
1121             current = stepRange.maximum() - nextDiff;
1122         setValueAsDecimal(current, DispatchNoEvent, IGNORE_EXCEPTION);
1123     }
1124     if ((sign > 0 && current < stepRange.minimum()) || (sign < 0 && current > stepRange.maximum()))
1125         setValueAsDecimal(sign > 0 ? stepRange.minimum() : stepRange.maximum(), DispatchInputAndChangeEvent, IGNORE_EXCEPTION);
1126     else {
1127         if (stepMismatch(element().value())) {
1128             ASSERT(!step.isZero());
1129             const Decimal base = stepRange.stepBase();
1130             Decimal newValue;
1131             if (sign < 0)
1132                 newValue = base + ((current - base) / step).floor() * step;
1133             else if (sign > 0)
1134                 newValue = base + ((current - base) / step).ceiling() * step;
1135             else
1136                 newValue = current;
1137
1138             if (newValue < stepRange.minimum())
1139                 newValue = stepRange.minimum();
1140             if (newValue > stepRange.maximum())
1141                 newValue = stepRange.maximum();
1142
1143             setValueAsDecimal(newValue, n == 1 || n == -1 ? DispatchInputAndChangeEvent : DispatchNoEvent, IGNORE_EXCEPTION);
1144             if (n > 1)
1145                 applyStep(n - 1, AnyIsDefaultStep, DispatchInputAndChangeEvent, IGNORE_EXCEPTION);
1146             else if (n < -1)
1147                 applyStep(n + 1, AnyIsDefaultStep, DispatchInputAndChangeEvent, IGNORE_EXCEPTION);
1148         } else
1149             applyStep(n, AnyIsDefaultStep, DispatchInputAndChangeEvent, IGNORE_EXCEPTION);
1150     }
1151 }
1152
1153 } // namespace WebCore