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