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
82namespace WebCore {
83
84using namespace HTMLNames;
85
86typedef bool (RuntimeEnabledFeatures::*InputTypeConditionalFunction)() const;
87typedef const AtomicString& (*InputTypeNameFunction)();
88typedef std::unique_ptr<InputType> (*InputTypeFactoryFunction)(HTMLInputElement&);
89typedef HashMap<AtomicString, InputTypeFactoryFunction, CaseFoldingHash> InputTypeFactoryMap;
90
91template<class T>
92static std::unique_ptr<InputType> createInputType(HTMLInputElement& element)
93{
94    return std::make_unique<T>(element);
95}
96
97static 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
150std::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
163std::unique_ptr<InputType> InputType::createText(HTMLInputElement& element)
164{
165    return std::make_unique<TextInputType>(element);
166}
167
168InputType::~InputType()
169{
170}
171
172bool 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
179bool InputType::isTextField() const
180{
181    return false;
182}
183
184bool InputType::isTextType() const
185{
186    return false;
187}
188
189bool InputType::isRangeControl() const
190{
191    return false;
192}
193
194bool InputType::shouldSaveAndRestoreFormControlState() const
195{
196    return true;
197}
198
199FormControlState InputType::saveFormControlState() const
200{
201    String currentValue = element().value();
202    if (currentValue == element().defaultValue())
203        return FormControlState();
204    return FormControlState(currentValue);
205}
206
207void InputType::restoreFormControlState(const FormControlState& state)
208{
209    element().setValue(state[0]);
210}
211
212bool 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
218bool InputType::appendFormData(FormDataList& encoding, bool) const
219{
220    // Always successful.
221    encoding.appendData(element().name(), element().value());
222    return true;
223}
224
225double InputType::valueAsDate() const
226{
227    return DateComponents::invalidMilliseconds();
228}
229
230void InputType::setValueAsDate(double, ExceptionCode& ec) const
231{
232    ec = INVALID_STATE_ERR;
233}
234
235double InputType::valueAsDouble() const
236{
237    return std::numeric_limits<double>::quiet_NaN();
238}
239
240void InputType::setValueAsDouble(double doubleValue, TextFieldEventBehavior eventBehavior, ExceptionCode& ec) const
241{
242    setValueAsDecimal(Decimal::fromDouble(doubleValue), eventBehavior, ec);
243}
244
245void InputType::setValueAsDecimal(const Decimal&, TextFieldEventBehavior, ExceptionCode& ec) const
246{
247    ec = INVALID_STATE_ERR;
248}
249
250bool InputType::supportsValidation() const
251{
252    return true;
253}
254
255bool InputType::typeMismatchFor(const String&) const
256{
257    return false;
258}
259
260bool InputType::typeMismatch() const
261{
262    return false;
263}
264
265bool InputType::supportsRequired() const
266{
267    // Almost all validatable types support @required.
268    return supportsValidation();
269}
270
271bool InputType::valueMissing(const String&) const
272{
273    return false;
274}
275
276bool InputType::hasBadInput() const
277{
278    return false;
279}
280
281bool InputType::patternMismatch(const String&) const
282{
283    return false;
284}
285
286bool 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
298bool 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
310Decimal InputType::defaultValueForStepUp() const
311{
312    return 0;
313}
314
315double InputType::minimum() const
316{
317    return createStepRange(RejectAny).minimum().toDouble();
318}
319
320double InputType::maximum() const
321{
322    return createStepRange(RejectAny).maximum().toDouble();
323}
324
325bool InputType::sizeShouldIncludeDecoration(int, int& preferredSize) const
326{
327    preferredSize = element().size();
328    return false;
329}
330
331float InputType::decorationWidth() const
332{
333    return 0;
334}
335
336bool 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
349bool 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
362bool 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
374String InputType::badInputText() const
375{
376    ASSERT_NOT_REACHED();
377    return validationMessageTypeMismatchText();
378}
379
380String InputType::typeMismatchText() const
381{
382    return validationMessageTypeMismatchText();
383}
384
385String InputType::valueMissingText() const
386{
387    return validationMessageValueMissingText();
388}
389
390String 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
434void InputType::handleClickEvent(MouseEvent*)
435{
436}
437
438void InputType::handleMouseDownEvent(MouseEvent*)
439{
440}
441
442void InputType::handleDOMActivateEvent(Event*)
443{
444}
445
446void InputType::handleKeydownEvent(KeyboardEvent*)
447{
448}
449
450void InputType::handleKeypressEvent(KeyboardEvent*)
451{
452}
453
454void InputType::handleKeyupEvent(KeyboardEvent*)
455{
456}
457
458void InputType::handleBeforeTextInsertedEvent(BeforeTextInsertedEvent*)
459{
460}
461
462#if ENABLE(TOUCH_EVENTS)
463void InputType::handleTouchEvent(TouchEvent*)
464{
465}
466#endif
467
468void InputType::forwardEvent(Event*)
469{
470}
471
472bool InputType::shouldSubmitImplicitly(Event* event)
473{
474    return event->isKeyboardEvent() && event->type() == eventNames().keypressEvent && toKeyboardEvent(event)->charCode() == '\r';
475}
476
477PassRefPtr<HTMLFormElement> InputType::formForSubmission() const
478{
479    return element().form();
480}
481
482RenderPtr<RenderElement> InputType::createInputRenderer(PassRef<RenderStyle> style)
483{
484    return RenderPtr<RenderElement>(RenderElement::createFor(element(), WTF::move(style)));
485}
486
487void InputType::blur()
488{
489    element().defaultBlur();
490}
491
492void InputType::createShadowSubtree()
493{
494}
495
496void InputType::destroyShadowSubtree()
497{
498    ShadowRoot* root = element().userAgentShadowRoot();
499    if (!root)
500        return;
501
502    root->removeChildren();
503}
504
505Decimal InputType::parseToNumber(const String&, const Decimal& defaultValue) const
506{
507    ASSERT_NOT_REACHED();
508    return defaultValue;
509}
510
511Decimal InputType::parseToNumberOrNaN(const String& string) const
512{
513    return parseToNumber(string, Decimal::nan());
514}
515
516bool InputType::parseToDateComponents(const String&, DateComponents*) const
517{
518    ASSERT_NOT_REACHED();
519    return false;
520}
521
522String InputType::serialize(const Decimal&) const
523{
524    ASSERT_NOT_REACHED();
525    return String();
526}
527
528#if PLATFORM(IOS)
529DateComponents::Type InputType::dateType() const
530{
531    return DateComponents::Invalid;
532}
533#endif
534
535void InputType::dispatchSimulatedClickIfActive(KeyboardEvent* event) const
536{
537    if (element().active())
538        element().dispatchSimulatedClick(event);
539    event->setDefaultHandled();
540}
541
542Chrome* InputType::chrome() const
543{
544    if (Page* page = element().document().page())
545        return &page->chrome();
546    return 0;
547}
548
549bool InputType::canSetStringValue() const
550{
551    return true;
552}
553
554bool InputType::hasCustomFocusLogic() const
555{
556    return true;
557}
558
559bool InputType::isKeyboardFocusable(KeyboardEvent* event) const
560{
561    return !element().isReadOnly() && element().isTextFormControlKeyboardFocusable(event);
562}
563
564bool InputType::isMouseFocusable() const
565{
566    return element().isTextFormControlMouseFocusable();
567}
568
569bool InputType::shouldUseInputMethod() const
570{
571    return false;
572}
573
574void InputType::handleFocusEvent(Node*, FocusDirection)
575{
576}
577
578void InputType::handleBlurEvent()
579{
580}
581
582void InputType::accessKeyAction(bool)
583{
584    element().focus(false);
585}
586
587void InputType::addSearchResult()
588{
589}
590
591void InputType::attach()
592{
593}
594
595void InputType::detach()
596{
597}
598
599void InputType::altAttributeChanged()
600{
601}
602
603void InputType::srcAttributeChanged()
604{
605}
606
607bool InputType::shouldRespectAlignAttribute()
608{
609    return false;
610}
611
612bool InputType::canChangeFromAnotherType() const
613{
614    return true;
615}
616
617void InputType::minOrMaxAttributeChanged()
618{
619}
620
621void InputType::stepAttributeChanged()
622{
623}
624
625bool InputType::canBeSuccessfulSubmitButton()
626{
627    return false;
628}
629
630HTMLElement* InputType::placeholderElement() const
631{
632    return 0;
633}
634
635bool InputType::rendererIsNeeded()
636{
637    return true;
638}
639
640FileList* InputType::files()
641{
642    return 0;
643}
644
645void InputType::setFiles(PassRefPtr<FileList>)
646{
647}
648
649bool InputType::getTypeSpecificValue(String&)
650{
651    return false;
652}
653
654String InputType::fallbackValue() const
655{
656    return String();
657}
658
659String InputType::defaultValue() const
660{
661    return String();
662}
663
664bool InputType::canSetSuggestedValue()
665{
666    return false;
667}
668
669bool InputType::shouldSendChangeEventAfterCheckedChanged()
670{
671    return true;
672}
673
674bool InputType::storesValueSeparateFromAttribute()
675{
676    return true;
677}
678
679void 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
698bool InputType::canSetValue(const String&)
699{
700    return true;
701}
702
703void InputType::willDispatchClick(InputElementClickState&)
704{
705}
706
707void InputType::didDispatchClick(Event*, const InputElementClickState&)
708{
709}
710
711String InputType::localizeValue(const String& proposedValue) const
712{
713    return proposedValue;
714}
715
716String InputType::visibleValue() const
717{
718    return element().value();
719}
720
721String InputType::sanitizeValue(const String& proposedValue) const
722{
723    return proposedValue;
724}
725
726#if ENABLE(DRAG_SUPPORT)
727bool InputType::receiveDroppedFiles(const DragData&)
728{
729    ASSERT_NOT_REACHED();
730    return false;
731}
732#endif
733
734Icon* InputType::icon() const
735{
736    ASSERT_NOT_REACHED();
737    return 0;
738}
739
740#if PLATFORM(IOS)
741String InputType::displayString() const
742{
743    ASSERT_NOT_REACHED();
744    return String();
745}
746#endif
747
748bool InputType::shouldResetOnDocumentActivation()
749{
750    return false;
751}
752
753bool InputType::shouldRespectListAttribute()
754{
755    return false;
756}
757
758bool InputType::shouldRespectSpeechAttribute()
759{
760    return false;
761}
762
763bool InputType::isTextButton() const
764{
765    return false;
766}
767
768bool InputType::isRadioButton() const
769{
770    return false;
771}
772
773bool InputType::isSearchField() const
774{
775    return false;
776}
777
778bool InputType::isHiddenType() const
779{
780    return false;
781}
782
783bool InputType::isPasswordField() const
784{
785    return false;
786}
787
788bool InputType::isCheckbox() const
789{
790    return false;
791}
792
793bool InputType::isEmailField() const
794{
795    return false;
796}
797
798bool InputType::isFileUpload() const
799{
800    return false;
801}
802
803bool InputType::isImageButton() const
804{
805    return false;
806}
807
808bool InputType::supportLabels() const
809{
810    return true;
811}
812
813bool InputType::isNumberField() const
814{
815    return false;
816}
817
818bool InputType::isSubmitButton() const
819{
820    return false;
821}
822
823bool InputType::isTelephoneField() const
824{
825    return false;
826}
827
828bool InputType::isURLField() const
829{
830    return false;
831}
832
833bool InputType::isDateField() const
834{
835    return false;
836}
837
838bool InputType::isDateTimeField() const
839{
840    return false;
841}
842
843bool InputType::isDateTimeLocalField() const
844{
845    return false;
846}
847
848bool InputType::isMonthField() const
849{
850    return false;
851}
852
853bool InputType::isTimeField() const
854{
855    return false;
856}
857
858bool InputType::isWeekField() const
859{
860    return false;
861}
862
863bool InputType::isEnumeratable()
864{
865    return true;
866}
867
868bool InputType::isCheckable()
869{
870    return false;
871}
872
873bool InputType::isSteppable() const
874{
875    return false;
876}
877
878#if ENABLE(INPUT_TYPE_COLOR)
879bool InputType::isColorControl() const
880{
881    return false;
882}
883#endif
884
885bool InputType::shouldRespectHeightAndWidthAttributes()
886{
887    return false;
888}
889
890bool InputType::supportsPlaceholder() const
891{
892    return false;
893}
894
895bool InputType::supportsReadOnly() const
896{
897    return false;
898}
899
900void InputType::updateInnerTextValue()
901{
902}
903
904void InputType::updatePlaceholderText()
905{
906}
907
908void InputType::attributeChanged()
909{
910}
911
912void InputType::multipleAttributeChanged()
913{
914}
915
916void InputType::disabledAttributeChanged()
917{
918}
919
920void InputType::readonlyAttributeChanged()
921{
922}
923
924void InputType::requiredAttributeChanged()
925{
926}
927
928void InputType::valueAttributeChanged()
929{
930}
931
932void InputType::subtreeHasChanged()
933{
934    ASSERT_NOT_REACHED();
935}
936
937#if ENABLE(TOUCH_EVENTS)
938bool InputType::hasTouchEventHandler() const
939{
940    return false;
941}
942#endif
943
944String InputType::defaultToolTip() const
945{
946    return String();
947}
948
949#if ENABLE(DATALIST_ELEMENT)
950void InputType::listAttributeTargetChanged()
951{
952}
953
954Decimal InputType::findClosestTickMarkValue(const Decimal&)
955{
956    ASSERT_NOT_REACHED();
957    return Decimal::nan();
958}
959#endif
960
961void InputType::updateClearButtonVisibility()
962{
963}
964
965bool InputType::supportsIndeterminateAppearance() const
966{
967    return false;
968}
969
970bool InputType::supportsSelectionAPI() const
971{
972    return false;
973}
974
975unsigned InputType::height() const
976{
977    return 0;
978}
979
980unsigned InputType::width() const
981{
982    return 0;
983}
984
985void 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
1029bool InputType::getAllowedValueStep(Decimal* step) const
1030{
1031    StepRange stepRange(createStepRange(RejectAny));
1032    *step = stepRange.step();
1033    return stepRange.hasStep();
1034}
1035
1036StepRange InputType::createStepRange(AnyStepHandling) const
1037{
1038    ASSERT_NOT_REACHED();
1039    return StepRange();
1040}
1041
1042void 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
1051void 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
1154