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) 2010 Google Inc. All rights reserved.
9 * Copyright (C) 2008 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
10 * Copyright (C) 2012 Samsung Electronics. All rights reserved.
11 *
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Library General Public
14 * License as published by the Free Software Foundation; either
15 * version 2 of the License, or (at your option) any later version.
16 *
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20 * Library General Public License for more details.
21 *
22 * You should have received a copy of the GNU Library General Public License
23 * along with this library; see the file COPYING.LIB.  If not, write to
24 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
25 * Boston, MA 02110-1301, USA.
26 *
27 */
28
29#include "config.h"
30#include "HTMLInputElement.h"
31
32#include "AXObjectCache.h"
33#include "BeforeTextInsertedEvent.h"
34#include "CSSPropertyNames.h"
35#include "DateTimeChooser.h"
36#include "Document.h"
37#include "Editor.h"
38#include "EventNames.h"
39#include "ExceptionCode.h"
40#include "FileInputType.h"
41#include "FileList.h"
42#include "FormController.h"
43#include "Frame.h"
44#include "FrameSelection.h"
45#include "FrameView.h"
46#include "HTMLDataListElement.h"
47#include "HTMLFormElement.h"
48#include "HTMLImageLoader.h"
49#include "HTMLOptionElement.h"
50#include "HTMLParserIdioms.h"
51#include "IdTargetObserver.h"
52#include "InsertionPoint.h"
53#include "KeyboardEvent.h"
54#include "Language.h"
55#include "LocalizedStrings.h"
56#include "MouseEvent.h"
57#include "PlatformMouseEvent.h"
58#include "RenderTextControlSingleLine.h"
59#include "RenderTheme.h"
60#include "RuntimeEnabledFeatures.h"
61#include "ScopedEventQueue.h"
62#include "SearchInputType.h"
63#include "StyleResolver.h"
64#include "TextBreakIterator.h"
65#include <wtf/MathExtras.h>
66#include <wtf/Ref.h>
67
68#if ENABLE(INPUT_TYPE_COLOR)
69#include "ColorInputType.h"
70#endif
71
72#if ENABLE(TOUCH_EVENTS)
73#include "TouchEvent.h"
74#endif
75
76namespace WebCore {
77
78using namespace HTMLNames;
79
80#if ENABLE(DATALIST_ELEMENT)
81class ListAttributeTargetObserver : IdTargetObserver {
82    WTF_MAKE_FAST_ALLOCATED;
83public:
84    ListAttributeTargetObserver(const AtomicString& id, HTMLInputElement*);
85
86    virtual void idTargetChanged() override;
87
88private:
89    HTMLInputElement* m_element;
90};
91#endif
92
93// FIXME: According to HTML4, the length attribute's value can be arbitrarily
94// large. However, due to https://bugs.webkit.org/show_bug.cgi?id=14536 things
95// get rather sluggish when a text field has a larger number of characters than
96// this, even when just clicking in the text field.
97const int HTMLInputElement::maximumLength = 524288;
98const int defaultSize = 20;
99const int maxSavedResults = 256;
100
101HTMLInputElement::HTMLInputElement(const QualifiedName& tagName, Document& document, HTMLFormElement* form, bool createdByParser)
102    : HTMLTextFormControlElement(tagName, document, form)
103    , m_size(defaultSize)
104    , m_maxLength(maximumLength)
105    , m_maxResults(-1)
106    , m_isChecked(false)
107    , m_reflectsCheckedAttribute(true)
108    , m_isIndeterminate(false)
109    , m_hasType(false)
110    , m_isActivatedSubmit(false)
111    , m_autocomplete(Uninitialized)
112    , m_isAutofilled(false)
113#if ENABLE(DATALIST_ELEMENT)
114    , m_hasNonEmptyList(false)
115#endif
116    , m_stateRestored(false)
117    , m_parsingInProgress(createdByParser)
118    , m_valueAttributeWasUpdatedAfterParsing(false)
119    , m_wasModifiedByUser(false)
120    , m_canReceiveDroppedFiles(false)
121#if ENABLE(TOUCH_EVENTS)
122    , m_hasTouchEventHandler(false)
123#endif
124    , m_inputType(InputType::createText(*this))
125{
126    ASSERT(hasTagName(inputTag) || hasTagName(isindexTag));
127    setHasCustomStyleResolveCallbacks();
128}
129
130PassRefPtr<HTMLInputElement> HTMLInputElement::create(const QualifiedName& tagName, Document& document, HTMLFormElement* form, bool createdByParser)
131{
132    RefPtr<HTMLInputElement> inputElement = adoptRef(new HTMLInputElement(tagName, document, form, createdByParser));
133    inputElement->ensureUserAgentShadowRoot();
134    return inputElement.release();
135}
136
137HTMLImageLoader* HTMLInputElement::imageLoader()
138{
139    if (!m_imageLoader)
140        m_imageLoader = std::make_unique<HTMLImageLoader>(*this);
141    return m_imageLoader.get();
142}
143
144void HTMLInputElement::didAddUserAgentShadowRoot(ShadowRoot*)
145{
146    m_inputType->createShadowSubtree();
147    updateInnerTextElementEditability();
148}
149
150HTMLInputElement::~HTMLInputElement()
151{
152    if (needsSuspensionCallback())
153        document().unregisterForPageCacheSuspensionCallbacks(this);
154
155    // Need to remove form association while this is still an HTMLInputElement
156    // so that virtual functions are called correctly.
157    setForm(0);
158    // setForm(0) may register this to a document-level radio button group.
159    // We should unregister it to avoid accessing a deleted object.
160    if (isRadioButton())
161        document().formController().checkedRadioButtons().removeButton(this);
162#if ENABLE(TOUCH_EVENTS)
163    if (m_hasTouchEventHandler)
164        document().didRemoveEventTargetNode(this);
165#endif
166}
167
168const AtomicString& HTMLInputElement::name() const
169{
170    return m_name.isNull() ? emptyAtom : m_name;
171}
172
173Vector<FileChooserFileInfo> HTMLInputElement::filesFromFileInputFormControlState(const FormControlState& state)
174{
175    return FileInputType::filesFromFormControlState(state);
176}
177
178HTMLElement* HTMLInputElement::containerElement() const
179{
180    return m_inputType->containerElement();
181}
182
183TextControlInnerTextElement* HTMLInputElement::innerTextElement() const
184{
185    return m_inputType->innerTextElement();
186}
187
188HTMLElement* HTMLInputElement::innerBlockElement() const
189{
190    return m_inputType->innerBlockElement();
191}
192
193HTMLElement* HTMLInputElement::innerSpinButtonElement() const
194{
195    return m_inputType->innerSpinButtonElement();
196}
197
198HTMLElement* HTMLInputElement::resultsButtonElement() const
199{
200    return m_inputType->resultsButtonElement();
201}
202
203HTMLElement* HTMLInputElement::cancelButtonElement() const
204{
205    return m_inputType->cancelButtonElement();
206}
207
208#if ENABLE(INPUT_SPEECH)
209HTMLElement* HTMLInputElement::speechButtonElement() const
210{
211    return m_inputType->speechButtonElement();
212}
213#endif
214
215HTMLElement* HTMLInputElement::sliderThumbElement() const
216{
217    return m_inputType->sliderThumbElement();
218}
219
220HTMLElement* HTMLInputElement::sliderTrackElement() const
221{
222    return m_inputType->sliderTrackElement();
223}
224
225HTMLElement* HTMLInputElement::placeholderElement() const
226{
227    return m_inputType->placeholderElement();
228}
229
230bool HTMLInputElement::shouldAutocomplete() const
231{
232    if (m_autocomplete != Uninitialized)
233        return m_autocomplete == On;
234    return HTMLTextFormControlElement::shouldAutocomplete();
235}
236
237bool HTMLInputElement::isValidValue(const String& value) const
238{
239    if (!m_inputType->canSetStringValue()) {
240        ASSERT_NOT_REACHED();
241        return false;
242    }
243    return !m_inputType->typeMismatchFor(value)
244        && !m_inputType->stepMismatch(value)
245        && !m_inputType->rangeUnderflow(value)
246        && !m_inputType->rangeOverflow(value)
247        && !tooLong(value, IgnoreDirtyFlag)
248        && !m_inputType->patternMismatch(value)
249        && !m_inputType->valueMissing(value);
250}
251
252bool HTMLInputElement::tooLong() const
253{
254    return willValidate() && tooLong(value(), CheckDirtyFlag);
255}
256
257bool HTMLInputElement::typeMismatch() const
258{
259    return willValidate() && m_inputType->typeMismatch();
260}
261
262bool HTMLInputElement::valueMissing() const
263{
264    return willValidate() && m_inputType->valueMissing(value());
265}
266
267bool HTMLInputElement::hasBadInput() const
268{
269    return willValidate() && m_inputType->hasBadInput();
270}
271
272bool HTMLInputElement::patternMismatch() const
273{
274    return willValidate() && m_inputType->patternMismatch(value());
275}
276
277bool HTMLInputElement::tooLong(const String& value, NeedsToCheckDirtyFlag check) const
278{
279    // We use isTextType() instead of supportsMaxLength() because of the
280    // 'virtual' overhead.
281    if (!isTextType())
282        return false;
283    int max = maxLength();
284    if (max < 0)
285        return false;
286    if (check == CheckDirtyFlag) {
287        // Return false for the default value or a value set by a script even if
288        // it is longer than maxLength.
289        if (!hasDirtyValue() || !m_wasModifiedByUser)
290            return false;
291    }
292    return numGraphemeClusters(value) > static_cast<unsigned>(max);
293}
294
295bool HTMLInputElement::rangeUnderflow() const
296{
297    return willValidate() && m_inputType->rangeUnderflow(value());
298}
299
300bool HTMLInputElement::rangeOverflow() const
301{
302    return willValidate() && m_inputType->rangeOverflow(value());
303}
304
305String HTMLInputElement::validationMessage() const
306{
307    if (!willValidate())
308        return String();
309
310    if (customError())
311        return customValidationMessage();
312
313    return m_inputType->validationMessage();
314}
315
316double HTMLInputElement::minimum() const
317{
318    return m_inputType->minimum();
319}
320
321double HTMLInputElement::maximum() const
322{
323    return m_inputType->maximum();
324}
325
326bool HTMLInputElement::stepMismatch() const
327{
328    return willValidate() && m_inputType->stepMismatch(value());
329}
330
331bool HTMLInputElement::getAllowedValueStep(Decimal* step) const
332{
333    return m_inputType->getAllowedValueStep(step);
334}
335
336StepRange HTMLInputElement::createStepRange(AnyStepHandling anyStepHandling) const
337{
338    return m_inputType->createStepRange(anyStepHandling);
339}
340
341#if ENABLE(DATALIST_ELEMENT)
342Decimal HTMLInputElement::findClosestTickMarkValue(const Decimal& value)
343{
344    return m_inputType->findClosestTickMarkValue(value);
345}
346#endif
347
348void HTMLInputElement::stepUp(int n, ExceptionCode& ec)
349{
350    m_inputType->stepUp(n, ec);
351}
352
353void HTMLInputElement::stepDown(int n, ExceptionCode& ec)
354{
355    m_inputType->stepUp(-n, ec);
356}
357
358void HTMLInputElement::blur()
359{
360    m_inputType->blur();
361}
362
363void HTMLInputElement::defaultBlur()
364{
365    HTMLTextFormControlElement::blur();
366}
367
368bool HTMLInputElement::hasCustomFocusLogic() const
369{
370    return m_inputType->hasCustomFocusLogic();
371}
372
373bool HTMLInputElement::isKeyboardFocusable(KeyboardEvent* event) const
374{
375    return m_inputType->isKeyboardFocusable(event);
376}
377
378bool HTMLInputElement::isMouseFocusable() const
379{
380    return m_inputType->isMouseFocusable();
381}
382
383bool HTMLInputElement::isTextFormControlFocusable() const
384{
385    return HTMLTextFormControlElement::isFocusable();
386}
387
388bool HTMLInputElement::isTextFormControlKeyboardFocusable(KeyboardEvent* event) const
389{
390    return HTMLTextFormControlElement::isKeyboardFocusable(event);
391}
392
393bool HTMLInputElement::isTextFormControlMouseFocusable() const
394{
395    return HTMLTextFormControlElement::isMouseFocusable();
396}
397
398void HTMLInputElement::updateFocusAppearance(bool restorePreviousSelection)
399{
400    if (isTextField()) {
401        if (!restorePreviousSelection || !hasCachedSelection())
402            select();
403        else
404            restoreCachedSelection();
405        if (document().frame())
406            document().frame()->selection().revealSelection();
407    } else
408        HTMLTextFormControlElement::updateFocusAppearance(restorePreviousSelection);
409}
410
411void HTMLInputElement::endEditing()
412{
413    if (!isTextField())
414        return;
415
416    if (Frame* frame = document().frame())
417        frame->editor().textFieldDidEndEditing(this);
418}
419
420bool HTMLInputElement::shouldUseInputMethod()
421{
422    return m_inputType->shouldUseInputMethod();
423}
424
425void HTMLInputElement::handleFocusEvent(Node* oldFocusedNode, FocusDirection direction)
426{
427    m_inputType->handleFocusEvent(oldFocusedNode, direction);
428}
429
430void HTMLInputElement::handleBlurEvent()
431{
432    m_inputType->handleBlurEvent();
433}
434
435void HTMLInputElement::setType(const String& type)
436{
437    // FIXME: This should just call setAttribute. No reason to handle the empty string specially.
438    // We should write a test case to show that setting to the empty string does not remove the
439    // attribute in other browsers and then fix this. Note that setting to null *does* remove
440    // the attribute and setAttribute implements that.
441    if (type.isEmpty())
442        removeAttribute(typeAttr);
443    else
444        setAttribute(typeAttr, type);
445}
446
447void HTMLInputElement::updateType()
448{
449    auto newType = InputType::create(*this, fastGetAttribute(typeAttr));
450    bool hadType = m_hasType;
451    m_hasType = true;
452    if (m_inputType->formControlType() == newType->formControlType())
453        return;
454
455    if (hadType && !newType->canChangeFromAnotherType()) {
456        // Set the attribute back to the old value.
457        // Useful in case we were called from inside parseAttribute.
458        setAttribute(typeAttr, type());
459        return;
460    }
461
462    removeFromRadioButtonGroup();
463
464    bool didStoreValue = m_inputType->storesValueSeparateFromAttribute();
465    bool neededSuspensionCallback = needsSuspensionCallback();
466    bool didRespectHeightAndWidth = m_inputType->shouldRespectHeightAndWidthAttributes();
467
468    m_inputType->destroyShadowSubtree();
469
470    m_inputType = WTF::move(newType);
471    m_inputType->createShadowSubtree();
472    updateInnerTextElementEditability();
473
474#if ENABLE(TOUCH_EVENTS)
475    bool hasTouchEventHandler = m_inputType->hasTouchEventHandler();
476    if (hasTouchEventHandler != m_hasTouchEventHandler) {
477        if (hasTouchEventHandler)
478            document().didAddTouchEventHandler(this);
479        else
480            document().didRemoveTouchEventHandler(this);
481        m_hasTouchEventHandler = hasTouchEventHandler;
482    }
483#endif
484
485    setNeedsWillValidateCheck();
486
487    bool willStoreValue = m_inputType->storesValueSeparateFromAttribute();
488
489    if (didStoreValue && !willStoreValue && hasDirtyValue()) {
490        setAttribute(valueAttr, m_valueIfDirty);
491        m_valueIfDirty = String();
492    }
493    if (!didStoreValue && willStoreValue) {
494        AtomicString valueString = fastGetAttribute(valueAttr);
495        m_valueIfDirty = sanitizeValue(valueString);
496    } else
497        updateValueIfNeeded();
498
499    setFormControlValueMatchesRenderer(false);
500    m_inputType->updateInnerTextValue();
501
502    m_wasModifiedByUser = false;
503
504    if (neededSuspensionCallback)
505        unregisterForSuspensionCallbackIfNeeded();
506    else
507        registerForSuspensionCallbackIfNeeded();
508
509    if (didRespectHeightAndWidth != m_inputType->shouldRespectHeightAndWidthAttributes()) {
510        ASSERT(elementData());
511        // FIXME: We don't have the old attribute values so we pretend that we didn't have the old values.
512        if (const Attribute* height = findAttributeByName(heightAttr))
513            attributeChanged(heightAttr, nullAtom, height->value());
514        if (const Attribute* width = findAttributeByName(widthAttr))
515            attributeChanged(widthAttr, nullAtom, width->value());
516        if (const Attribute* align = findAttributeByName(alignAttr))
517            attributeChanged(alignAttr, nullAtom, align->value());
518    }
519
520    if (renderer())
521        setNeedsStyleRecalc(ReconstructRenderTree);
522
523    if (document().focusedElement() == this)
524        updateFocusAppearance(true);
525
526    if (ShadowRoot* shadowRoot = shadowRootOfParentForDistribution(this))
527        shadowRoot->invalidateDistribution();
528
529    setChangedSinceLastFormControlChangeEvent(false);
530
531    addToRadioButtonGroup();
532
533    setNeedsValidityCheck();
534}
535
536void HTMLInputElement::subtreeHasChanged()
537{
538    m_inputType->subtreeHasChanged();
539    // When typing in an input field, childrenChanged is not called, so we need to force the directionality check.
540    calculateAndAdjustDirectionality();
541}
542
543const AtomicString& HTMLInputElement::formControlType() const
544{
545    return m_inputType->formControlType();
546}
547
548bool HTMLInputElement::shouldSaveAndRestoreFormControlState() const
549{
550    if (!m_inputType->shouldSaveAndRestoreFormControlState())
551        return false;
552    return HTMLTextFormControlElement::shouldSaveAndRestoreFormControlState();
553}
554
555FormControlState HTMLInputElement::saveFormControlState() const
556{
557    return m_inputType->saveFormControlState();
558}
559
560void HTMLInputElement::restoreFormControlState(const FormControlState& state)
561{
562    m_inputType->restoreFormControlState(state);
563    m_stateRestored = true;
564}
565
566bool HTMLInputElement::canStartSelection() const
567{
568    if (!isTextField())
569        return false;
570    return HTMLTextFormControlElement::canStartSelection();
571}
572
573bool HTMLInputElement::canHaveSelection() const
574{
575    return isTextField();
576}
577
578void HTMLInputElement::accessKeyAction(bool sendMouseEvents)
579{
580    m_inputType->accessKeyAction(sendMouseEvents);
581}
582
583bool HTMLInputElement::isPresentationAttribute(const QualifiedName& name) const
584{
585    if (name == vspaceAttr || name == hspaceAttr || name == alignAttr || name == widthAttr || name == heightAttr || (name == borderAttr && isImageButton()))
586        return true;
587    return HTMLTextFormControlElement::isPresentationAttribute(name);
588}
589
590void HTMLInputElement::collectStyleForPresentationAttribute(const QualifiedName& name, const AtomicString& value, MutableStyleProperties& style)
591{
592    if (name == vspaceAttr) {
593        addHTMLLengthToStyle(style, CSSPropertyMarginTop, value);
594        addHTMLLengthToStyle(style, CSSPropertyMarginBottom, value);
595    } else if (name == hspaceAttr) {
596        addHTMLLengthToStyle(style, CSSPropertyMarginLeft, value);
597        addHTMLLengthToStyle(style, CSSPropertyMarginRight, value);
598    } else if (name == alignAttr) {
599        if (m_inputType->shouldRespectAlignAttribute())
600            applyAlignmentAttributeToStyle(value, style);
601    } else if (name == widthAttr) {
602        if (m_inputType->shouldRespectHeightAndWidthAttributes())
603            addHTMLLengthToStyle(style, CSSPropertyWidth, value);
604    } else if (name == heightAttr) {
605        if (m_inputType->shouldRespectHeightAndWidthAttributes())
606            addHTMLLengthToStyle(style, CSSPropertyHeight, value);
607    } else if (name == borderAttr && isImageButton())
608        applyBorderAttributeToStyle(value, style);
609    else
610        HTMLTextFormControlElement::collectStyleForPresentationAttribute(name, value, style);
611}
612
613void HTMLInputElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
614{
615    if (name == nameAttr) {
616        removeFromRadioButtonGroup();
617        m_name = value;
618        addToRadioButtonGroup();
619        HTMLTextFormControlElement::parseAttribute(name, value);
620    } else if (name == autocompleteAttr) {
621        if (equalIgnoringCase(value, "off")) {
622            m_autocomplete = Off;
623            registerForSuspensionCallbackIfNeeded();
624        } else {
625            bool needsToUnregister = m_autocomplete == Off;
626
627            if (value.isEmpty())
628                m_autocomplete = Uninitialized;
629            else
630                m_autocomplete = On;
631
632            if (needsToUnregister)
633                unregisterForSuspensionCallbackIfNeeded();
634        }
635    } else if (name == typeAttr)
636        updateType();
637    else if (name == valueAttr) {
638        // Changes to the value attribute may change whether or not this element has a default value.
639        // If this field is autocomplete=off that might affect the return value of needsSuspensionCallback.
640        if (m_autocomplete == Off) {
641            unregisterForSuspensionCallbackIfNeeded();
642            registerForSuspensionCallbackIfNeeded();
643        }
644        // We only need to setChanged if the form is looking at the default value right now.
645        if (!hasDirtyValue()) {
646            updatePlaceholderVisibility(false);
647            setNeedsStyleRecalc();
648        }
649        setFormControlValueMatchesRenderer(false);
650        setNeedsValidityCheck();
651        m_valueAttributeWasUpdatedAfterParsing = !m_parsingInProgress;
652        m_inputType->valueAttributeChanged();
653    } else if (name == checkedAttr) {
654        // Another radio button in the same group might be checked by state
655        // restore. We shouldn't call setChecked() even if this has the checked
656        // attribute. So, delay the setChecked() call until
657        // finishParsingChildren() is called if parsing is in progress.
658        if (!m_parsingInProgress && m_reflectsCheckedAttribute) {
659            setChecked(!value.isNull());
660            m_reflectsCheckedAttribute = true;
661        }
662    } else if (name == maxlengthAttr)
663        parseMaxLengthAttribute(value);
664    else if (name == sizeAttr) {
665        int oldSize = m_size;
666        int valueAsInteger = value.toInt();
667        m_size = valueAsInteger > 0 ? valueAsInteger : defaultSize;
668        if (m_size != oldSize && renderer())
669            renderer()->setNeedsLayoutAndPrefWidthsRecalc();
670    } else if (name == altAttr)
671        m_inputType->altAttributeChanged();
672    else if (name == srcAttr)
673        m_inputType->srcAttributeChanged();
674    else if (name == usemapAttr || name == accesskeyAttr) {
675        // FIXME: ignore for the moment
676    } else if (name == onsearchAttr) {
677        // Search field and slider attributes all just cause updateFromElement to be called through style recalcing.
678        setAttributeEventListener(eventNames().searchEvent, name, value);
679    } else if (name == resultsAttr) {
680        int oldResults = m_maxResults;
681        m_maxResults = !value.isNull() ? std::min(value.toInt(), maxSavedResults) : -1;
682
683        if (m_maxResults != oldResults && (m_maxResults <= 0 || oldResults <= 0))
684            setNeedsStyleRecalc(ReconstructRenderTree);
685        else
686            setNeedsStyleRecalc();
687    } else if (name == autosaveAttr) {
688        setNeedsStyleRecalc();
689    } else if (name == incrementalAttr) {
690        setNeedsStyleRecalc();
691    } else if (name == minAttr) {
692        m_inputType->minOrMaxAttributeChanged();
693        setNeedsValidityCheck();
694    } else if (name == maxAttr) {
695        m_inputType->minOrMaxAttributeChanged();
696        setNeedsValidityCheck();
697    } else if (name == multipleAttr) {
698        m_inputType->multipleAttributeChanged();
699        setNeedsValidityCheck();
700    } else if (name == stepAttr) {
701        m_inputType->stepAttributeChanged();
702        setNeedsValidityCheck();
703    } else if (name == patternAttr) {
704        setNeedsValidityCheck();
705    } else if (name == precisionAttr) {
706        setNeedsValidityCheck();
707    } else if (name == disabledAttr) {
708        HTMLTextFormControlElement::parseAttribute(name, value);
709        m_inputType->disabledAttributeChanged();
710    } else if (name == readonlyAttr) {
711        HTMLTextFormControlElement::parseAttribute(name, value);
712        m_inputType->readonlyAttributeChanged();
713    }
714#if ENABLE(DATALIST_ELEMENT)
715    else if (name == listAttr) {
716        m_hasNonEmptyList = !value.isEmpty();
717        if (m_hasNonEmptyList) {
718            resetListAttributeTargetObserver();
719            listAttributeTargetChanged();
720        }
721    }
722#endif
723#if ENABLE(INPUT_SPEECH)
724    else if (name == webkitspeechAttr) {
725        m_inputType->destroyShadowSubtree();
726        m_inputType->createShadowSubtree();
727        updateInnerTextElementEditability();
728
729        // This renderer and its children have quite different layouts and styles depending on
730        // whether the speech button is visible or not. So we reset the whole thing and recreate
731        // to get the right styles and layout.
732        setNeedsStyleRecalc(ReconstructRenderTree);
733
734        setFormControlValueMatchesRenderer(false);
735    } else if (name == onwebkitspeechchangeAttr)
736        setAttributeEventListener(eventNames().webkitspeechchangeEvent, name, value);
737#endif
738    else
739        HTMLTextFormControlElement::parseAttribute(name, value);
740    m_inputType->attributeChanged();
741}
742
743void HTMLInputElement::finishParsingChildren()
744{
745    m_parsingInProgress = false;
746    HTMLTextFormControlElement::finishParsingChildren();
747    if (!m_stateRestored) {
748        bool checked = hasAttribute(checkedAttr);
749        if (checked)
750            setChecked(checked);
751        m_reflectsCheckedAttribute = true;
752    }
753}
754
755bool HTMLInputElement::rendererIsNeeded(const RenderStyle& style)
756{
757    return m_inputType->rendererIsNeeded() && HTMLTextFormControlElement::rendererIsNeeded(style);
758}
759
760RenderPtr<RenderElement> HTMLInputElement::createElementRenderer(PassRef<RenderStyle> style)
761{
762    return m_inputType->createInputRenderer(WTF::move(style));
763}
764
765void HTMLInputElement::willAttachRenderers()
766{
767    if (!m_hasType)
768        updateType();
769}
770
771void HTMLInputElement::didAttachRenderers()
772{
773    HTMLTextFormControlElement::didAttachRenderers();
774
775    m_inputType->attach();
776
777    if (document().focusedElement() == this)
778        document().updateFocusAppearanceSoon(true /* restore selection */);
779}
780
781void HTMLInputElement::didDetachRenderers()
782{
783    setFormControlValueMatchesRenderer(false);
784    m_inputType->detach();
785}
786
787String HTMLInputElement::altText() const
788{
789    // http://www.w3.org/TR/1998/REC-html40-19980424/appendix/notes.html#altgen
790    // also heavily discussed by Hixie on bugzilla
791    // note this is intentionally different to HTMLImageElement::altText()
792    String alt = fastGetAttribute(altAttr);
793    // fall back to title attribute
794    if (alt.isNull())
795        alt = getAttribute(titleAttr);
796    if (alt.isNull())
797        alt = getAttribute(valueAttr);
798    if (alt.isEmpty())
799        alt = inputElementAltText();
800    return alt;
801}
802
803bool HTMLInputElement::isSuccessfulSubmitButton() const
804{
805    // HTML spec says that buttons must have names to be considered successful.
806    // However, other browsers do not impose this constraint. So we do not.
807    return !isDisabledFormControl() && m_inputType->canBeSuccessfulSubmitButton();
808}
809
810bool HTMLInputElement::isActivatedSubmit() const
811{
812    return m_isActivatedSubmit;
813}
814
815void HTMLInputElement::setActivatedSubmit(bool flag)
816{
817    m_isActivatedSubmit = flag;
818}
819
820bool HTMLInputElement::appendFormData(FormDataList& encoding, bool multipart)
821{
822    return m_inputType->isFormDataAppendable() && m_inputType->appendFormData(encoding, multipart);
823}
824
825void HTMLInputElement::reset()
826{
827    if (m_inputType->storesValueSeparateFromAttribute())
828        setValue(String());
829
830    setAutofilled(false);
831    setChecked(hasAttribute(checkedAttr));
832    m_reflectsCheckedAttribute = true;
833}
834
835bool HTMLInputElement::isTextField() const
836{
837    return m_inputType->isTextField();
838}
839
840bool HTMLInputElement::isTextType() const
841{
842    return m_inputType->isTextType();
843}
844
845void HTMLInputElement::setChecked(bool nowChecked, TextFieldEventBehavior eventBehavior)
846{
847    if (checked() == nowChecked)
848        return;
849
850    m_reflectsCheckedAttribute = false;
851    m_isChecked = nowChecked;
852    setNeedsStyleRecalc();
853
854    if (CheckedRadioButtons* buttons = checkedRadioButtons())
855            buttons->updateCheckedState(this);
856    if (renderer() && renderer()->style().hasAppearance())
857        renderer()->theme().stateChanged(*renderer(), ControlStates::CheckedState);
858    setNeedsValidityCheck();
859
860    // Ideally we'd do this from the render tree (matching
861    // RenderTextView), but it's not possible to do it at the moment
862    // because of the way the code is structured.
863    if (renderer()) {
864        if (AXObjectCache* cache = renderer()->document().existingAXObjectCache())
865            cache->checkedStateChanged(this);
866    }
867
868    // Only send a change event for items in the document (avoid firing during
869    // parsing) and don't send a change event for a radio button that's getting
870    // unchecked to match other browsers. DOM is not a useful standard for this
871    // because it says only to fire change events at "lose focus" time, which is
872    // definitely wrong in practice for these types of elements.
873    if (eventBehavior != DispatchNoEvent && inDocument() && m_inputType->shouldSendChangeEventAfterCheckedChanged()) {
874        setTextAsOfLastFormControlChangeEvent(String());
875        dispatchFormControlChangeEvent();
876    }
877
878    didAffectSelector(AffectedSelectorChecked);
879}
880
881void HTMLInputElement::setIndeterminate(bool newValue)
882{
883    if (indeterminate() == newValue)
884        return;
885
886    m_isIndeterminate = newValue;
887
888    didAffectSelector(AffectedSelectorIndeterminate);
889
890    if (renderer() && renderer()->style().hasAppearance())
891        renderer()->theme().stateChanged(*renderer(), ControlStates::CheckedState);
892}
893
894int HTMLInputElement::size() const
895{
896    return m_size;
897}
898
899bool HTMLInputElement::sizeShouldIncludeDecoration(int& preferredSize) const
900{
901    return m_inputType->sizeShouldIncludeDecoration(defaultSize, preferredSize);
902}
903
904float HTMLInputElement::decorationWidth() const
905{
906    return m_inputType->decorationWidth();
907}
908
909void HTMLInputElement::copyNonAttributePropertiesFromElement(const Element& source)
910{
911    const HTMLInputElement& sourceElement = static_cast<const HTMLInputElement&>(source);
912
913    m_valueIfDirty = sourceElement.m_valueIfDirty;
914    m_wasModifiedByUser = false;
915    setChecked(sourceElement.m_isChecked);
916    m_reflectsCheckedAttribute = sourceElement.m_reflectsCheckedAttribute;
917    m_isIndeterminate = sourceElement.m_isIndeterminate;
918
919    HTMLTextFormControlElement::copyNonAttributePropertiesFromElement(source);
920
921    setFormControlValueMatchesRenderer(false);
922    m_inputType->updateInnerTextValue();
923}
924
925String HTMLInputElement::value() const
926{
927    String value;
928    if (m_inputType->getTypeSpecificValue(value))
929        return value;
930
931    value = m_valueIfDirty;
932    if (!value.isNull())
933        return value;
934
935    AtomicString valueString = fastGetAttribute(valueAttr);
936    value = sanitizeValue(valueString);
937    if (!value.isNull())
938        return value;
939
940    return m_inputType->fallbackValue();
941}
942
943String HTMLInputElement::valueWithDefault() const
944{
945    String value = this->value();
946    if (!value.isNull())
947        return value;
948
949    return m_inputType->defaultValue();
950}
951
952void HTMLInputElement::setValueForUser(const String& value)
953{
954    // Call setValue and make it send a change event.
955    setValue(value, DispatchChangeEvent);
956}
957
958const String& HTMLInputElement::suggestedValue() const
959{
960    return m_suggestedValue;
961}
962
963void HTMLInputElement::setSuggestedValue(const String& value)
964{
965    if (!m_inputType->canSetSuggestedValue())
966        return;
967    setFormControlValueMatchesRenderer(false);
968    m_suggestedValue = sanitizeValue(value);
969    setNeedsStyleRecalc();
970    m_inputType->updateInnerTextValue();
971}
972
973void HTMLInputElement::setEditingValue(const String& value)
974{
975    if (!renderer() || !isTextField())
976        return;
977    setInnerTextValue(value);
978    subtreeHasChanged();
979
980    unsigned max = value.length();
981    if (focused())
982        setSelectionRange(max, max);
983    else
984        cacheSelectionInResponseToSetValue(max);
985
986    dispatchInputEvent();
987}
988
989void HTMLInputElement::setValue(const String& value, ExceptionCode& ec, TextFieldEventBehavior eventBehavior)
990{
991    if (isFileUpload() && !value.isEmpty()) {
992        ec = INVALID_STATE_ERR;
993        return;
994    }
995    setValue(value, eventBehavior);
996}
997
998void HTMLInputElement::setValue(const String& value, TextFieldEventBehavior eventBehavior)
999{
1000    if (!m_inputType->canSetValue(value))
1001        return;
1002
1003    Ref<HTMLInputElement> protect(*this);
1004    EventQueueScope scope;
1005    String sanitizedValue = sanitizeValue(value);
1006    bool valueChanged = sanitizedValue != this->value();
1007
1008    setLastChangeWasNotUserEdit();
1009    setFormControlValueMatchesRenderer(false);
1010    m_suggestedValue = String(); // Prevent TextFieldInputType::setValue from using the suggested value.
1011    m_inputType->setValue(sanitizedValue, valueChanged, eventBehavior);
1012
1013    if (!valueChanged)
1014        return;
1015}
1016
1017void HTMLInputElement::setValueInternal(const String& sanitizedValue, TextFieldEventBehavior eventBehavior)
1018{
1019    m_valueIfDirty = sanitizedValue;
1020    m_wasModifiedByUser = eventBehavior != DispatchNoEvent;
1021    setNeedsValidityCheck();
1022}
1023
1024double HTMLInputElement::valueAsDate() const
1025{
1026    return m_inputType->valueAsDate();
1027}
1028
1029void HTMLInputElement::setValueAsDate(double value, ExceptionCode& ec)
1030{
1031    m_inputType->setValueAsDate(value, ec);
1032}
1033
1034double HTMLInputElement::valueAsNumber() const
1035{
1036    return m_inputType->valueAsDouble();
1037}
1038
1039void HTMLInputElement::setValueAsNumber(double newValue, ExceptionCode& ec, TextFieldEventBehavior eventBehavior)
1040{
1041    if (!std::isfinite(newValue)) {
1042        ec = NOT_SUPPORTED_ERR;
1043        return;
1044    }
1045    m_inputType->setValueAsDouble(newValue, eventBehavior, ec);
1046}
1047
1048void HTMLInputElement::setValueFromRenderer(const String& value)
1049{
1050    // File upload controls will never use this.
1051    ASSERT(!isFileUpload());
1052
1053    m_suggestedValue = String();
1054
1055    // Renderer and our event handler are responsible for sanitizing values.
1056    ASSERT(value == sanitizeValue(value) || sanitizeValue(value).isEmpty());
1057
1058    // Workaround for bug where trailing \n is included in the result of textContent.
1059    // The assert macro above may also be simplified to: value == constrainValue(value)
1060    // http://bugs.webkit.org/show_bug.cgi?id=9661
1061    m_valueIfDirty = value == "\n" ? emptyString() : value;
1062
1063    setFormControlValueMatchesRenderer(true);
1064    m_wasModifiedByUser = true;
1065
1066    // Input event is fired by the Node::defaultEventHandler for editable controls.
1067    if (!isTextField())
1068        dispatchInputEvent();
1069
1070    setNeedsValidityCheck();
1071
1072    // Clear autofill flag (and yellow background) on user edit.
1073    setAutofilled(false);
1074}
1075
1076void HTMLInputElement::willDispatchEvent(Event& event, InputElementClickState& state)
1077{
1078    if (event.type() == eventNames().textInputEvent && m_inputType->shouldSubmitImplicitly(&event))
1079        event.stopPropagation();
1080    if (event.type() == eventNames().clickEvent && event.isMouseEvent() && toMouseEvent(&event)->button() == LeftButton) {
1081        m_inputType->willDispatchClick(state);
1082        state.stateful = true;
1083    }
1084}
1085
1086void HTMLInputElement::didDispatchClickEvent(Event& event, const InputElementClickState& state)
1087{
1088    m_inputType->didDispatchClick(&event, state);
1089}
1090
1091void HTMLInputElement::defaultEventHandler(Event* evt)
1092{
1093    if (evt->isMouseEvent() && evt->type() == eventNames().clickEvent && toMouseEvent(evt)->button() == LeftButton) {
1094        m_inputType->handleClickEvent(toMouseEvent(evt));
1095        if (evt->defaultHandled())
1096            return;
1097    }
1098
1099#if ENABLE(TOUCH_EVENTS)
1100    if (evt->isTouchEvent()) {
1101        m_inputType->handleTouchEvent(toTouchEvent(evt));
1102        if (evt->defaultHandled())
1103            return;
1104    }
1105#endif
1106
1107    if (evt->isKeyboardEvent() && evt->type() == eventNames().keydownEvent) {
1108        m_inputType->handleKeydownEvent(toKeyboardEvent(evt));
1109        if (evt->defaultHandled())
1110            return;
1111    }
1112
1113    // Call the base event handler before any of our own event handling for almost all events in text fields.
1114    // Makes editing keyboard handling take precedence over the keydown and keypress handling in this function.
1115    bool callBaseClassEarly = isTextField() && (evt->type() == eventNames().keydownEvent || evt->type() == eventNames().keypressEvent);
1116    if (callBaseClassEarly) {
1117        HTMLTextFormControlElement::defaultEventHandler(evt);
1118        if (evt->defaultHandled())
1119            return;
1120    }
1121
1122    // DOMActivate events cause the input to be "activated" - in the case of image and submit inputs, this means
1123    // actually submitting the form. For reset inputs, the form is reset. These events are sent when the user clicks
1124    // on the element, or presses enter while it is the active element. JavaScript code wishing to activate the element
1125    // must dispatch a DOMActivate event - a click event will not do the job.
1126    if (evt->type() == eventNames().DOMActivateEvent) {
1127        m_inputType->handleDOMActivateEvent(evt);
1128        if (evt->defaultHandled())
1129            return;
1130    }
1131
1132    // Use key press event here since sending simulated mouse events
1133    // on key down blocks the proper sending of the key press event.
1134    if (evt->isKeyboardEvent() && evt->type() == eventNames().keypressEvent) {
1135        m_inputType->handleKeypressEvent(toKeyboardEvent(evt));
1136        if (evt->defaultHandled())
1137            return;
1138    }
1139
1140    if (evt->isKeyboardEvent() && evt->type() == eventNames().keyupEvent) {
1141        m_inputType->handleKeyupEvent(toKeyboardEvent(evt));
1142        if (evt->defaultHandled())
1143            return;
1144    }
1145
1146    if (m_inputType->shouldSubmitImplicitly(evt)) {
1147        if (isSearchField()) {
1148            addSearchResult();
1149            onSearch();
1150        }
1151        // Form submission finishes editing, just as loss of focus does.
1152        // If there was a change, send the event now.
1153        if (wasChangedSinceLastFormControlChangeEvent())
1154            dispatchFormControlChangeEvent();
1155
1156        RefPtr<HTMLFormElement> formForSubmission = m_inputType->formForSubmission();
1157        // Form may never have been present, or may have been destroyed by code responding to the change event.
1158        if (formForSubmission)
1159            formForSubmission->submitImplicitly(evt, canTriggerImplicitSubmission());
1160
1161        evt->setDefaultHandled();
1162        return;
1163    }
1164
1165    if (evt->isBeforeTextInsertedEvent())
1166        m_inputType->handleBeforeTextInsertedEvent(toBeforeTextInsertedEvent(evt));
1167
1168    if (evt->isMouseEvent() && evt->type() == eventNames().mousedownEvent) {
1169        m_inputType->handleMouseDownEvent(toMouseEvent(evt));
1170        if (evt->defaultHandled())
1171            return;
1172    }
1173
1174    m_inputType->forwardEvent(evt);
1175
1176    if (!callBaseClassEarly && !evt->defaultHandled())
1177        HTMLTextFormControlElement::defaultEventHandler(evt);
1178}
1179
1180bool HTMLInputElement::willRespondToMouseClickEvents()
1181{
1182    if (!isDisabledFormControl())
1183        return true;
1184
1185    return HTMLTextFormControlElement::willRespondToMouseClickEvents();
1186}
1187
1188bool HTMLInputElement::isURLAttribute(const Attribute& attribute) const
1189{
1190    return attribute.name() == srcAttr || attribute.name() == formactionAttr || HTMLTextFormControlElement::isURLAttribute(attribute);
1191}
1192
1193String HTMLInputElement::defaultValue() const
1194{
1195    return fastGetAttribute(valueAttr);
1196}
1197
1198void HTMLInputElement::setDefaultValue(const String &value)
1199{
1200    setAttribute(valueAttr, value);
1201}
1202
1203static inline bool isRFC2616TokenCharacter(UChar ch)
1204{
1205    return isASCII(ch) && ch > ' ' && ch != '"' && ch != '(' && ch != ')' && ch != ',' && ch != '/' && (ch < ':' || ch > '@') && (ch < '[' || ch > ']') && ch != '{' && ch != '}' && ch != 0x7f;
1206}
1207
1208static bool isValidMIMEType(const String& type)
1209{
1210    size_t slashPosition = type.find('/');
1211    if (slashPosition == notFound || !slashPosition || slashPosition == type.length() - 1)
1212        return false;
1213    for (size_t i = 0; i < type.length(); ++i) {
1214        if (!isRFC2616TokenCharacter(type[i]) && i != slashPosition)
1215            return false;
1216    }
1217    return true;
1218}
1219
1220static bool isValidFileExtension(const String& type)
1221{
1222    if (type.length() < 2)
1223        return false;
1224    return type[0] == '.';
1225}
1226
1227static Vector<String> parseAcceptAttribute(const String& acceptString, bool (*predicate)(const String&))
1228{
1229    Vector<String> types;
1230    if (acceptString.isEmpty())
1231        return types;
1232
1233    Vector<String> splitTypes;
1234    acceptString.split(',', false, splitTypes);
1235    for (size_t i = 0; i < splitTypes.size(); ++i) {
1236        String trimmedType = stripLeadingAndTrailingHTMLSpaces(splitTypes[i]);
1237        if (trimmedType.isEmpty())
1238            continue;
1239        if (!predicate(trimmedType))
1240            continue;
1241        types.append(trimmedType.lower());
1242    }
1243
1244    return types;
1245}
1246
1247Vector<String> HTMLInputElement::acceptMIMETypes()
1248{
1249    return parseAcceptAttribute(fastGetAttribute(acceptAttr), isValidMIMEType);
1250}
1251
1252Vector<String> HTMLInputElement::acceptFileExtensions()
1253{
1254    return parseAcceptAttribute(fastGetAttribute(acceptAttr), isValidFileExtension);
1255}
1256
1257String HTMLInputElement::accept() const
1258{
1259    return fastGetAttribute(acceptAttr);
1260}
1261
1262String HTMLInputElement::alt() const
1263{
1264    return fastGetAttribute(altAttr);
1265}
1266
1267int HTMLInputElement::maxLength() const
1268{
1269    return m_maxLength;
1270}
1271
1272void HTMLInputElement::setMaxLength(int maxLength, ExceptionCode& ec)
1273{
1274    if (maxLength < 0)
1275        ec = INDEX_SIZE_ERR;
1276    else
1277        setIntegralAttribute(maxlengthAttr, maxLength);
1278}
1279
1280bool HTMLInputElement::multiple() const
1281{
1282    return fastHasAttribute(multipleAttr);
1283}
1284
1285void HTMLInputElement::setSize(unsigned size)
1286{
1287    setUnsignedIntegralAttribute(sizeAttr, size);
1288}
1289
1290void HTMLInputElement::setSize(unsigned size, ExceptionCode& ec)
1291{
1292    if (!size)
1293        ec = INDEX_SIZE_ERR;
1294    else
1295        setSize(size);
1296}
1297
1298URL HTMLInputElement::src() const
1299{
1300    return document().completeURL(fastGetAttribute(srcAttr));
1301}
1302
1303void HTMLInputElement::setAutofilled(bool autofilled)
1304{
1305    if (autofilled == m_isAutofilled)
1306        return;
1307
1308    m_isAutofilled = autofilled;
1309    setNeedsStyleRecalc();
1310}
1311
1312FileList* HTMLInputElement::files()
1313{
1314    return m_inputType->files();
1315}
1316
1317void HTMLInputElement::setFiles(PassRefPtr<FileList> files)
1318{
1319    m_inputType->setFiles(files);
1320}
1321
1322#if ENABLE(DRAG_SUPPORT)
1323bool HTMLInputElement::receiveDroppedFiles(const DragData& dragData)
1324{
1325    return m_inputType->receiveDroppedFiles(dragData);
1326}
1327#endif
1328
1329Icon* HTMLInputElement::icon() const
1330{
1331    return m_inputType->icon();
1332}
1333
1334#if PLATFORM(IOS)
1335String HTMLInputElement::displayString() const
1336{
1337    return m_inputType->displayString();
1338}
1339#endif
1340
1341bool HTMLInputElement::canReceiveDroppedFiles() const
1342{
1343    return m_canReceiveDroppedFiles;
1344}
1345
1346void HTMLInputElement::setCanReceiveDroppedFiles(bool canReceiveDroppedFiles)
1347{
1348    if (m_canReceiveDroppedFiles == canReceiveDroppedFiles)
1349        return;
1350    m_canReceiveDroppedFiles = canReceiveDroppedFiles;
1351    if (renderer())
1352        renderer()->updateFromElement();
1353}
1354
1355String HTMLInputElement::visibleValue() const
1356{
1357    return m_inputType->visibleValue();
1358}
1359
1360String HTMLInputElement::sanitizeValue(const String& proposedValue) const
1361{
1362    if (proposedValue.isNull())
1363        return proposedValue;
1364    return m_inputType->sanitizeValue(proposedValue);
1365}
1366
1367String HTMLInputElement::localizeValue(const String& proposedValue) const
1368{
1369    if (proposedValue.isNull())
1370        return proposedValue;
1371    return m_inputType->localizeValue(proposedValue);
1372}
1373
1374bool HTMLInputElement::isInRange() const
1375{
1376    return m_inputType->isInRange(value());
1377}
1378
1379bool HTMLInputElement::isOutOfRange() const
1380{
1381    return m_inputType->isOutOfRange(value());
1382}
1383
1384bool HTMLInputElement::needsSuspensionCallback()
1385{
1386    if (m_inputType->shouldResetOnDocumentActivation())
1387        return true;
1388
1389    // Sensitive input elements are marked with autocomplete=off, and we want to wipe them out
1390    // when going back; returning true here arranges for us to call reset at the time
1391    // the page is restored. Non-empty textual default values indicate that the field
1392    // is not really sensitive -- there's no default value for an account number --
1393    // and we would see unexpected results if we reset to something other than blank.
1394    bool isSensitive = m_autocomplete == Off && !(m_inputType->isTextType() && !defaultValue().isEmpty());
1395
1396    return isSensitive;
1397}
1398
1399void HTMLInputElement::registerForSuspensionCallbackIfNeeded()
1400{
1401    if (needsSuspensionCallback())
1402        document().registerForPageCacheSuspensionCallbacks(this);
1403}
1404
1405void HTMLInputElement::unregisterForSuspensionCallbackIfNeeded()
1406{
1407    if (!needsSuspensionCallback())
1408        document().unregisterForPageCacheSuspensionCallbacks(this);
1409}
1410
1411bool HTMLInputElement::isRequiredFormControl() const
1412{
1413    return m_inputType->supportsRequired() && isRequired();
1414}
1415
1416bool HTMLInputElement::matchesReadOnlyPseudoClass() const
1417{
1418    return m_inputType->supportsReadOnly() && isReadOnly();
1419}
1420
1421bool HTMLInputElement::matchesReadWritePseudoClass() const
1422{
1423    return m_inputType->supportsReadOnly() && !isDisabledOrReadOnly();
1424}
1425
1426void HTMLInputElement::addSearchResult()
1427{
1428    m_inputType->addSearchResult();
1429}
1430
1431void HTMLInputElement::onSearch()
1432{
1433    ASSERT(isSearchField());
1434    if (m_inputType)
1435        static_cast<SearchInputType*>(m_inputType.get())->stopSearchEventTimer();
1436    dispatchEvent(Event::create(eventNames().searchEvent, true, false));
1437}
1438
1439void HTMLInputElement::updateClearButtonVisibility()
1440{
1441    m_inputType->updateClearButtonVisibility();
1442}
1443
1444void HTMLInputElement::documentDidResumeFromPageCache()
1445{
1446    ASSERT(needsSuspensionCallback());
1447
1448#if ENABLE(INPUT_TYPE_COLOR)
1449    // <input type=color> uses documentWillSuspendForPageCache to detach the color picker UI,
1450    // so it should not be reset when being loaded from page cache.
1451    if (isColorControl())
1452        return;
1453#endif // ENABLE(INPUT_TYPE_COLOR)
1454    reset();
1455}
1456
1457#if ENABLE(INPUT_TYPE_COLOR)
1458void HTMLInputElement::documentWillSuspendForPageCache()
1459{
1460    if (!isColorControl())
1461        return;
1462    m_inputType->detach();
1463}
1464#endif // ENABLE(INPUT_TYPE_COLOR)
1465
1466
1467void HTMLInputElement::willChangeForm()
1468{
1469    removeFromRadioButtonGroup();
1470    HTMLTextFormControlElement::willChangeForm();
1471}
1472
1473void HTMLInputElement::didChangeForm()
1474{
1475    HTMLTextFormControlElement::didChangeForm();
1476    addToRadioButtonGroup();
1477}
1478
1479Node::InsertionNotificationRequest HTMLInputElement::insertedInto(ContainerNode& insertionPoint)
1480{
1481    HTMLTextFormControlElement::insertedInto(insertionPoint);
1482    if (insertionPoint.inDocument() && !form())
1483        addToRadioButtonGroup();
1484#if ENABLE(DATALIST_ELEMENT)
1485    resetListAttributeTargetObserver();
1486#endif
1487    return InsertionDone;
1488}
1489
1490void HTMLInputElement::removedFrom(ContainerNode& insertionPoint)
1491{
1492    if (insertionPoint.inDocument() && !form())
1493        removeFromRadioButtonGroup();
1494    HTMLTextFormControlElement::removedFrom(insertionPoint);
1495    ASSERT(!inDocument());
1496#if ENABLE(DATALIST_ELEMENT)
1497    resetListAttributeTargetObserver();
1498#endif
1499}
1500
1501void HTMLInputElement::didMoveToNewDocument(Document* oldDocument)
1502{
1503    if (hasImageLoader())
1504        imageLoader()->elementDidMoveToNewDocument();
1505
1506    bool needsSuspensionCallback = this->needsSuspensionCallback();
1507    if (oldDocument) {
1508        // Always unregister for cache callbacks when leaving a document, even if we would otherwise like to be registered
1509        if (needsSuspensionCallback)
1510            oldDocument->unregisterForPageCacheSuspensionCallbacks(this);
1511        if (isRadioButton())
1512            oldDocument->formController().checkedRadioButtons().removeButton(this);
1513#if ENABLE(TOUCH_EVENTS)
1514        if (m_hasTouchEventHandler)
1515            oldDocument->didRemoveEventTargetNode(this);
1516#endif
1517    }
1518
1519    if (needsSuspensionCallback)
1520        document().registerForPageCacheSuspensionCallbacks(this);
1521
1522#if ENABLE(TOUCH_EVENTS)
1523    if (m_hasTouchEventHandler)
1524        document().didAddTouchEventHandler(this);
1525#endif
1526
1527    HTMLTextFormControlElement::didMoveToNewDocument(oldDocument);
1528}
1529
1530void HTMLInputElement::addSubresourceAttributeURLs(ListHashSet<URL>& urls) const
1531{
1532    HTMLTextFormControlElement::addSubresourceAttributeURLs(urls);
1533
1534    addSubresourceURL(urls, src());
1535}
1536
1537bool HTMLInputElement::recalcWillValidate() const
1538{
1539    return m_inputType->supportsValidation() && HTMLTextFormControlElement::recalcWillValidate();
1540}
1541
1542void HTMLInputElement::requiredAttributeChanged()
1543{
1544    HTMLTextFormControlElement::requiredAttributeChanged();
1545    if (CheckedRadioButtons* buttons = checkedRadioButtons())
1546        buttons->requiredAttributeChanged(this);
1547    m_inputType->requiredAttributeChanged();
1548}
1549
1550#if ENABLE(INPUT_TYPE_COLOR)
1551void HTMLInputElement::selectColorInColorChooser(const Color& color)
1552{
1553    if (!m_inputType->isColorControl())
1554        return;
1555    static_cast<ColorInputType*>(m_inputType.get())->didChooseColor(color);
1556}
1557#endif
1558
1559#if ENABLE(DATALIST_ELEMENT)
1560HTMLElement* HTMLInputElement::list() const
1561{
1562    return dataList();
1563}
1564
1565HTMLDataListElement* HTMLInputElement::dataList() const
1566{
1567    if (!m_hasNonEmptyList)
1568        return 0;
1569
1570    if (!m_inputType->shouldRespectListAttribute())
1571        return 0;
1572
1573    Element* element = treeScope().getElementById(fastGetAttribute(listAttr));
1574    if (!element)
1575        return 0;
1576    if (!element->hasTagName(datalistTag))
1577        return 0;
1578
1579    return toHTMLDataListElement(element);
1580}
1581
1582void HTMLInputElement::resetListAttributeTargetObserver()
1583{
1584    if (inDocument())
1585        m_listAttributeTargetObserver = std::make_unique<ListAttributeTargetObserver>(fastGetAttribute(listAttr), this);
1586    else
1587        m_listAttributeTargetObserver = nullptr;
1588}
1589
1590void HTMLInputElement::listAttributeTargetChanged()
1591{
1592    m_inputType->listAttributeTargetChanged();
1593}
1594#endif // ENABLE(DATALIST_ELEMENT)
1595
1596bool HTMLInputElement::isSteppable() const
1597{
1598    return m_inputType->isSteppable();
1599}
1600
1601#if ENABLE(INPUT_SPEECH)
1602
1603bool HTMLInputElement::isSpeechEnabled() const
1604{
1605    // FIXME: Add support for RANGE, EMAIL, URL, COLOR and DATE/TIME input types.
1606    return m_inputType->shouldRespectSpeechAttribute() && RuntimeEnabledFeatures::sharedFeatures().speechInputEnabled() && hasAttribute(webkitspeechAttr);
1607}
1608
1609#endif
1610
1611#if PLATFORM(IOS)
1612DateComponents::Type HTMLInputElement::dateType() const
1613{
1614    return m_inputType->dateType();
1615}
1616#endif
1617
1618bool HTMLInputElement::isTextButton() const
1619{
1620    return m_inputType->isTextButton();
1621}
1622
1623bool HTMLInputElement::isRadioButton() const
1624{
1625    return m_inputType->isRadioButton();
1626}
1627
1628bool HTMLInputElement::isSearchField() const
1629{
1630    return m_inputType->isSearchField();
1631}
1632
1633bool HTMLInputElement::isInputTypeHidden() const
1634{
1635    return m_inputType->isHiddenType();
1636}
1637
1638bool HTMLInputElement::isPasswordField() const
1639{
1640    return m_inputType->isPasswordField();
1641}
1642
1643bool HTMLInputElement::isCheckbox() const
1644{
1645    return m_inputType->isCheckbox();
1646}
1647
1648bool HTMLInputElement::isRangeControl() const
1649{
1650    return m_inputType->isRangeControl();
1651}
1652
1653#if ENABLE(INPUT_TYPE_COLOR)
1654bool HTMLInputElement::isColorControl() const
1655{
1656    return m_inputType->isColorControl();
1657}
1658#endif
1659
1660bool HTMLInputElement::isText() const
1661{
1662    return m_inputType->isTextType();
1663}
1664
1665bool HTMLInputElement::isEmailField() const
1666{
1667    return m_inputType->isEmailField();
1668}
1669
1670bool HTMLInputElement::isFileUpload() const
1671{
1672    return m_inputType->isFileUpload();
1673}
1674
1675bool HTMLInputElement::isImageButton() const
1676{
1677    return m_inputType->isImageButton();
1678}
1679
1680bool HTMLInputElement::isNumberField() const
1681{
1682    return m_inputType->isNumberField();
1683}
1684
1685bool HTMLInputElement::isSubmitButton() const
1686{
1687    return m_inputType->isSubmitButton();
1688}
1689
1690bool HTMLInputElement::isTelephoneField() const
1691{
1692    return m_inputType->isTelephoneField();
1693}
1694
1695bool HTMLInputElement::isURLField() const
1696{
1697    return m_inputType->isURLField();
1698}
1699
1700bool HTMLInputElement::isDateField() const
1701{
1702    return m_inputType->isDateField();
1703}
1704
1705bool HTMLInputElement::isDateTimeField() const
1706{
1707    return m_inputType->isDateTimeField();
1708}
1709
1710bool HTMLInputElement::isDateTimeLocalField() const
1711{
1712    return m_inputType->isDateTimeLocalField();
1713}
1714
1715bool HTMLInputElement::isMonthField() const
1716{
1717    return m_inputType->isMonthField();
1718}
1719
1720bool HTMLInputElement::isTimeField() const
1721{
1722    return m_inputType->isTimeField();
1723}
1724
1725bool HTMLInputElement::isWeekField() const
1726{
1727    return m_inputType->isWeekField();
1728}
1729
1730bool HTMLInputElement::isEnumeratable() const
1731{
1732    return m_inputType->isEnumeratable();
1733}
1734
1735bool HTMLInputElement::supportLabels() const
1736{
1737    return m_inputType->supportLabels();
1738}
1739
1740bool HTMLInputElement::shouldAppearChecked() const
1741{
1742    return checked() && m_inputType->isCheckable();
1743}
1744
1745bool HTMLInputElement::supportsPlaceholder() const
1746{
1747    return m_inputType->supportsPlaceholder();
1748}
1749
1750void HTMLInputElement::updatePlaceholderText()
1751{
1752    return m_inputType->updatePlaceholderText();
1753}
1754
1755void HTMLInputElement::parseMaxLengthAttribute(const AtomicString& value)
1756{
1757    int maxLength;
1758    if (!parseHTMLInteger(value, maxLength))
1759        maxLength = maximumLength;
1760    if (maxLength < 0 || maxLength > maximumLength)
1761        maxLength = maximumLength;
1762    int oldMaxLength = m_maxLength;
1763    m_maxLength = maxLength;
1764    if (oldMaxLength != maxLength)
1765        updateValueIfNeeded();
1766    setNeedsStyleRecalc();
1767    setNeedsValidityCheck();
1768}
1769
1770void HTMLInputElement::updateValueIfNeeded()
1771{
1772    String newValue = sanitizeValue(m_valueIfDirty);
1773    ASSERT(!m_valueIfDirty.isNull() || newValue.isNull());
1774    if (newValue != m_valueIfDirty)
1775        setValue(newValue);
1776}
1777
1778String HTMLInputElement::defaultToolTip() const
1779{
1780    return m_inputType->defaultToolTip();
1781}
1782
1783bool HTMLInputElement::shouldAppearIndeterminate() const
1784{
1785    return m_inputType->supportsIndeterminateAppearance() && indeterminate();
1786}
1787
1788#if ENABLE(MEDIA_CAPTURE)
1789bool HTMLInputElement::shouldUseMediaCapture() const
1790{
1791    return isFileUpload() && fastHasAttribute(captureAttr);
1792}
1793#endif
1794
1795bool HTMLInputElement::isInRequiredRadioButtonGroup()
1796{
1797    ASSERT(isRadioButton());
1798    if (CheckedRadioButtons* buttons = checkedRadioButtons())
1799        return buttons->isInRequiredGroup(this);
1800    return false;
1801}
1802
1803HTMLInputElement* HTMLInputElement::checkedRadioButtonForGroup() const
1804{
1805    if (CheckedRadioButtons* buttons = checkedRadioButtons())
1806        return buttons->checkedButtonForGroup(name());
1807    return 0;
1808}
1809
1810CheckedRadioButtons* HTMLInputElement::checkedRadioButtons() const
1811{
1812    if (!isRadioButton())
1813        return 0;
1814    if (HTMLFormElement* formElement = form())
1815        return &formElement->checkedRadioButtons();
1816    if (inDocument())
1817        return &document().formController().checkedRadioButtons();
1818    return 0;
1819}
1820
1821inline void HTMLInputElement::addToRadioButtonGroup()
1822{
1823    if (CheckedRadioButtons* buttons = checkedRadioButtons())
1824        buttons->addButton(this);
1825}
1826
1827inline void HTMLInputElement::removeFromRadioButtonGroup()
1828{
1829    if (CheckedRadioButtons* buttons = checkedRadioButtons())
1830        buttons->removeButton(this);
1831}
1832
1833unsigned HTMLInputElement::height() const
1834{
1835    return m_inputType->height();
1836}
1837
1838unsigned HTMLInputElement::width() const
1839{
1840    return m_inputType->width();
1841}
1842
1843void HTMLInputElement::setHeight(unsigned height)
1844{
1845    setUnsignedIntegralAttribute(heightAttr, height);
1846}
1847
1848void HTMLInputElement::setWidth(unsigned width)
1849{
1850    setUnsignedIntegralAttribute(widthAttr, width);
1851}
1852
1853#if ENABLE(DATALIST_ELEMENT)
1854ListAttributeTargetObserver::ListAttributeTargetObserver(const AtomicString& id, HTMLInputElement* element)
1855    : IdTargetObserver(element->treeScope().idTargetObserverRegistry(), id)
1856    , m_element(element)
1857{
1858}
1859
1860void ListAttributeTargetObserver::idTargetChanged()
1861{
1862    m_element->listAttributeTargetChanged();
1863}
1864#endif
1865
1866void HTMLInputElement::setRangeText(const String& replacement, ExceptionCode& ec)
1867{
1868    if (!m_inputType->supportsSelectionAPI()) {
1869        ec = INVALID_STATE_ERR;
1870        return;
1871    }
1872
1873    HTMLTextFormControlElement::setRangeText(replacement, ec);
1874}
1875
1876void HTMLInputElement::setRangeText(const String& replacement, unsigned start, unsigned end, const String& selectionMode, ExceptionCode& ec)
1877{
1878    if (!m_inputType->supportsSelectionAPI()) {
1879        ec = INVALID_STATE_ERR;
1880        return;
1881    }
1882
1883    HTMLTextFormControlElement::setRangeText(replacement, start, end, selectionMode, ec);
1884}
1885
1886#if ENABLE(DATE_AND_TIME_INPUT_TYPES)
1887bool HTMLInputElement::setupDateTimeChooserParameters(DateTimeChooserParameters& parameters)
1888{
1889    if (!document().view())
1890        return false;
1891
1892    parameters.type = type();
1893    parameters.minimum = minimum();
1894    parameters.maximum = maximum();
1895    parameters.required = isRequired();
1896    if (!RuntimeEnabledFeatures::sharedFeatures().langAttributeAwareFormControlUIEnabled())
1897        parameters.locale = defaultLanguage();
1898    else {
1899        AtomicString computedLocale = computeInheritedLanguage();
1900        parameters.locale = computedLocale.isEmpty() ? AtomicString(defaultLanguage()) : computedLocale;
1901    }
1902
1903    StepRange stepRange = createStepRange(RejectAny);
1904    if (stepRange.hasStep()) {
1905        parameters.step = stepRange.step().toDouble();
1906        parameters.stepBase = stepRange.stepBase().toDouble();
1907    } else {
1908        parameters.step = 1.0;
1909        parameters.stepBase = 0;
1910    }
1911
1912    parameters.anchorRectInRootView = document().view()->contentsToRootView(pixelSnappedBoundingBox());
1913    parameters.currentValue = value();
1914    parameters.isAnchorElementRTL = computedStyle()->direction() == RTL;
1915#if ENABLE(DATALIST_ELEMENT)
1916    if (HTMLDataListElement* dataList = this->dataList()) {
1917        RefPtr<HTMLCollection> options = dataList->options();
1918        for (unsigned i = 0; HTMLOptionElement* option = toHTMLOptionElement(options->item(i)); ++i) {
1919            if (!isValidValue(option->value()))
1920                continue;
1921            parameters.suggestionValues.append(sanitizeValue(option->value()));
1922            parameters.localizedSuggestionValues.append(localizeValue(option->value()));
1923            parameters.suggestionLabels.append(option->value() == option->label() ? String() : option->label());
1924        }
1925    }
1926#endif
1927    return true;
1928}
1929#endif
1930
1931} // namespace
1932