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) 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.
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.
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.
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.
30 #include "core/html/HTMLInputElement.h"
32 #include "bindings/core/v8/ExceptionMessages.h"
33 #include "bindings/core/v8/ExceptionState.h"
34 #include "bindings/core/v8/ScriptEventListener.h"
35 #include "bindings/core/v8/V8DOMActivityLogger.h"
36 #include "core/CSSPropertyNames.h"
37 #include "core/HTMLNames.h"
38 #include "core/InputTypeNames.h"
39 #include "core/dom/AXObjectCache.h"
40 #include "core/dom/Document.h"
41 #include "core/dom/IdTargetObserver.h"
42 #include "core/dom/shadow/InsertionPoint.h"
43 #include "core/dom/shadow/ShadowRoot.h"
44 #include "core/editing/FrameSelection.h"
45 #include "core/editing/spellcheck/SpellChecker.h"
46 #include "core/events/BeforeTextInsertedEvent.h"
47 #include "core/events/KeyboardEvent.h"
48 #include "core/events/MouseEvent.h"
49 #include "core/events/ScopedEventQueue.h"
50 #include "core/events/TouchEvent.h"
51 #include "core/frame/EventHandlerRegistry.h"
52 #include "core/frame/FrameHost.h"
53 #include "core/frame/FrameView.h"
54 #include "core/frame/LocalFrame.h"
55 #include "core/frame/UseCounter.h"
56 #include "core/html/HTMLCollection.h"
57 #include "core/html/HTMLDataListElement.h"
58 #include "core/html/HTMLDataListOptionsCollection.h"
59 #include "core/html/HTMLFormElement.h"
60 #include "core/html/HTMLImageLoader.h"
61 #include "core/html/HTMLOptionElement.h"
62 #include "core/html/forms/ColorChooser.h"
63 #include "core/html/forms/DateTimeChooser.h"
64 #include "core/html/forms/FileInputType.h"
65 #include "core/html/forms/FormController.h"
66 #include "core/html/forms/InputType.h"
67 #include "core/html/forms/SearchInputType.h"
68 #include "core/html/parser/HTMLParserIdioms.h"
69 #include "core/layout/LayoutTextControlSingleLine.h"
70 #include "core/layout/LayoutTheme.h"
71 #include "core/page/ChromeClient.h"
72 #include "platform/Language.h"
73 #include "platform/PlatformMouseEvent.h"
74 #include "platform/RuntimeEnabledFeatures.h"
75 #include "platform/text/PlatformLocale.h"
76 #include "wtf/MathExtras.h"
80 using namespace HTMLNames
;
82 class ListAttributeTargetObserver
: public IdTargetObserver
{
83 WTF_MAKE_FAST_ALLOCATED_WILL_BE_REMOVED(ListAttributeTargetObserver
);
85 static PassOwnPtrWillBeRawPtr
<ListAttributeTargetObserver
> create(const AtomicString
& id
, HTMLInputElement
*);
86 DECLARE_VIRTUAL_TRACE();
87 void idTargetChanged() override
;
90 ListAttributeTargetObserver(const AtomicString
& id
, HTMLInputElement
*);
92 RawPtrWillBeMember
<HTMLInputElement
> m_element
;
95 // FIXME: According to HTML4, the length attribute's value can be arbitrarily
96 // large. However, due to https://bugs.webkit.org/show_bug.cgi?id=14536 things
97 // get rather sluggish when a text field has a larger number of characters than
98 // this, even when just clicking in the text field.
99 const int HTMLInputElement::maximumLength
= 524288;
100 const int defaultSize
= 20;
101 const int maxSavedResults
= 256;
103 HTMLInputElement::HTMLInputElement(Document
& document
, HTMLFormElement
* form
, bool createdByParser
)
104 : HTMLTextFormControlElement(inputTag
, document
, form
)
105 , m_size(defaultSize
)
106 , m_maxLength(maximumLength
)
110 , m_reflectsCheckedAttribute(true)
111 , m_isIndeterminate(false)
112 , m_isActivatedSubmit(false)
113 , m_autocomplete(Uninitialized
)
114 , m_hasNonEmptyList(false)
115 , m_stateRestored(false)
116 , m_parsingInProgress(createdByParser
)
117 , m_valueAttributeWasUpdatedAfterParsing(false)
118 , m_canReceiveDroppedFiles(false)
119 , m_hasTouchEventHandler(false)
120 , m_shouldRevealPassword(false)
121 , m_needsToUpdateViewValue(true)
122 // |m_inputType| is lazily created when constructed by the parser to avoid
123 // constructing unnecessarily a text inputType and its shadow subtree, just
124 // to destroy them when the |type| attribute gets set by the parser to
125 // something else than 'text'.
126 , m_inputType(createdByParser
? nullptr : InputType::createText(*this))
127 , m_inputTypeView(m_inputType
)
129 setHasCustomStyleCallbacks();
132 PassRefPtrWillBeRawPtr
<HTMLInputElement
> HTMLInputElement::create(Document
& document
, HTMLFormElement
* form
, bool createdByParser
)
134 RefPtrWillBeRawPtr
<HTMLInputElement
> inputElement
= adoptRefWillBeNoop(new HTMLInputElement(document
, form
, createdByParser
));
135 if (!createdByParser
)
136 inputElement
->ensureUserAgentShadowRoot();
137 return inputElement
.release();
140 DEFINE_TRACE(HTMLInputElement
)
142 visitor
->trace(m_inputType
);
143 visitor
->trace(m_inputTypeView
);
144 visitor
->trace(m_listAttributeTargetObserver
);
145 visitor
->trace(m_imageLoader
);
146 HTMLTextFormControlElement::trace(visitor
);
149 HTMLImageLoader
& HTMLInputElement::ensureImageLoader()
152 m_imageLoader
= HTMLImageLoader::create(this);
153 return *m_imageLoader
;
156 void HTMLInputElement::didAddUserAgentShadowRoot(ShadowRoot
&)
158 m_inputTypeView
->createShadowSubtree();
161 void HTMLInputElement::willAddFirstAuthorShadowRoot()
163 m_inputTypeView
->destroyShadowSubtree();
164 m_inputTypeView
= InputTypeView::create(*this);
165 lazyReattachIfAttached();
168 HTMLInputElement::~HTMLInputElement()
171 // Need to remove form association while this is still an HTMLInputElement
172 // so that virtual functions are called correctly.
174 // setForm(0) may register this to a document-level radio button group.
175 // We should unregister it to avoid accessing a deleted object.
176 if (type() == InputTypeNames::radio
)
177 document().formController().radioButtonGroupScope().removeButton(this);
178 if (m_hasTouchEventHandler
&& document().frameHost())
179 document().frameHost()->eventHandlerRegistry().didRemoveEventHandler(*this, EventHandlerRegistry::TouchEvent
);
183 const AtomicString
& HTMLInputElement::name() const
185 return m_name
.isNull() ? emptyAtom
: m_name
;
188 Vector
<FileChooserFileInfo
> HTMLInputElement::filesFromFileInputFormControlState(const FormControlState
& state
)
190 return FileInputType::filesFromFormControlState(state
);
193 bool HTMLInputElement::shouldAutocomplete() const
195 if (m_autocomplete
!= Uninitialized
)
196 return m_autocomplete
== On
;
197 return HTMLTextFormControlElement::shouldAutocomplete();
200 bool HTMLInputElement::isValidValue(const String
& value
) const
202 if (!m_inputType
->canSetStringValue()) {
203 ASSERT_NOT_REACHED();
206 return !m_inputType
->typeMismatchFor(value
)
207 && !m_inputType
->stepMismatch(value
)
208 && !m_inputType
->rangeUnderflow(value
)
209 && !m_inputType
->rangeOverflow(value
)
210 && !tooLong(value
, IgnoreDirtyFlag
)
211 && !tooShort(value
, IgnoreDirtyFlag
)
212 && !m_inputType
->patternMismatch(value
)
213 && !m_inputType
->valueMissing(value
);
216 bool HTMLInputElement::tooLong() const
218 return willValidate() && tooLong(value(), CheckDirtyFlag
);
221 bool HTMLInputElement::tooShort() const
223 return willValidate() && tooShort(value(), CheckDirtyFlag
);
226 bool HTMLInputElement::typeMismatch() const
228 return willValidate() && m_inputType
->typeMismatch();
231 bool HTMLInputElement::valueMissing() const
233 return willValidate() && m_inputType
->valueMissing(value());
236 bool HTMLInputElement::hasBadInput() const
238 return willValidate() && m_inputType
->hasBadInput();
241 bool HTMLInputElement::patternMismatch() const
243 return willValidate() && m_inputType
->patternMismatch(value());
246 bool HTMLInputElement::tooLong(const String
& value
, NeedsToCheckDirtyFlag check
) const
248 return m_inputType
->tooLong(value
, check
);
251 bool HTMLInputElement::tooShort(const String
& value
, NeedsToCheckDirtyFlag check
) const
253 return m_inputType
->tooShort(value
, check
);
256 bool HTMLInputElement::rangeUnderflow() const
258 return willValidate() && m_inputType
->rangeUnderflow(value());
261 bool HTMLInputElement::rangeOverflow() const
263 return willValidate() && m_inputType
->rangeOverflow(value());
266 String
HTMLInputElement::validationMessage() const
272 return customValidationMessage();
274 return m_inputType
->validationMessage();
277 double HTMLInputElement::minimum() const
279 return m_inputType
->minimum();
282 double HTMLInputElement::maximum() const
284 return m_inputType
->maximum();
287 bool HTMLInputElement::stepMismatch() const
289 return willValidate() && m_inputType
->stepMismatch(value());
292 bool HTMLInputElement::getAllowedValueStep(Decimal
* step
) const
294 return m_inputType
->getAllowedValueStep(step
);
297 StepRange
HTMLInputElement::createStepRange(AnyStepHandling anyStepHandling
) const
299 return m_inputType
->createStepRange(anyStepHandling
);
302 Decimal
HTMLInputElement::findClosestTickMarkValue(const Decimal
& value
)
304 return m_inputType
->findClosestTickMarkValue(value
);
307 void HTMLInputElement::stepUp(int n
, ExceptionState
& exceptionState
)
309 m_inputType
->stepUp(n
, exceptionState
);
312 void HTMLInputElement::stepDown(int n
, ExceptionState
& exceptionState
)
314 m_inputType
->stepUp(-n
, exceptionState
);
317 void HTMLInputElement::blur()
319 m_inputTypeView
->blur();
322 void HTMLInputElement::defaultBlur()
324 HTMLTextFormControlElement::blur();
327 bool HTMLInputElement::hasCustomFocusLogic() const
329 return m_inputTypeView
->hasCustomFocusLogic();
332 bool HTMLInputElement::isKeyboardFocusable() const
334 return m_inputType
->isKeyboardFocusable();
337 bool HTMLInputElement::shouldShowFocusRingOnMouseFocus() const
339 return m_inputType
->shouldShowFocusRingOnMouseFocus();
342 void HTMLInputElement::updateFocusAppearance(bool restorePreviousSelection
)
345 if (!restorePreviousSelection
)
346 select(NotDispatchSelectEvent
);
348 restoreCachedSelection();
349 if (document().frame())
350 document().frame()->selection().revealSelection();
352 HTMLTextFormControlElement::updateFocusAppearance(restorePreviousSelection
);
356 void HTMLInputElement::beginEditing()
358 ASSERT(document().isActive());
359 if (!document().isActive())
365 document().frame()->spellChecker().didBeginEditing(this);
368 void HTMLInputElement::endEditing()
370 ASSERT(document().isActive());
371 if (!document().isActive())
377 LocalFrame
* frame
= document().frame();
378 frame
->spellChecker().didEndEditingOnTextField(this);
379 frame
->host()->chromeClient().didEndEditingOnTextField(*this);
382 void HTMLInputElement::handleFocusEvent(Element
* oldFocusedElement
, WebFocusType type
)
384 m_inputTypeView
->handleFocusEvent(oldFocusedElement
, type
);
385 m_inputType
->enableSecureTextInput();
388 void HTMLInputElement::dispatchFocusInEvent(const AtomicString
& eventType
, Element
* oldFocusedElement
, WebFocusType type
, InputDeviceCapabilities
* sourceCapabilities
)
390 if (eventType
== EventTypeNames::DOMFocusIn
)
391 m_inputTypeView
->handleFocusInEvent(oldFocusedElement
, type
);
392 HTMLFormControlElementWithState::dispatchFocusInEvent(eventType
, oldFocusedElement
, type
, sourceCapabilities
);
395 void HTMLInputElement::handleBlurEvent()
397 m_inputType
->disableSecureTextInput();
398 m_inputTypeView
->handleBlurEvent();
401 void HTMLInputElement::setType(const AtomicString
& type
)
403 setAttribute(typeAttr
, type
);
406 void HTMLInputElement::updateTouchEventHandlerRegistry()
408 ASSERT(m_inputTypeView
);
410 bool hasTouchEventHandler
= m_inputTypeView
->hasTouchEventHandler();
411 if (hasTouchEventHandler
== !!m_hasTouchEventHandler
)
413 // If the Document is being or has been stopped, don't register any handlers.
414 if (document().frameHost() && document().lifecycle().state() < DocumentLifecycle::Stopping
) {
415 EventHandlerRegistry
& registry
= document().frameHost()->eventHandlerRegistry();
416 if (hasTouchEventHandler
)
417 registry
.didAddEventHandler(*this, EventHandlerRegistry::TouchEvent
);
419 registry
.didRemoveEventHandler(*this, EventHandlerRegistry::TouchEvent
);
421 m_hasTouchEventHandler
= hasTouchEventHandler
;
424 void HTMLInputElement::initializeTypeInParsing()
426 ASSERT(m_parsingInProgress
);
427 ASSERT(!m_inputType
);
428 ASSERT(!m_inputTypeView
);
430 const AtomicString
& newTypeName
= InputType::normalizeTypeName(fastGetAttribute(typeAttr
));
431 m_inputType
= InputType::create(*this, newTypeName
);
432 m_inputTypeView
= m_inputType
;
433 ensureUserAgentShadowRoot();
435 updateTouchEventHandlerRegistry();
437 setNeedsWillValidateCheck();
439 m_inputType
->warnIfValueIsInvalid(fastGetAttribute(valueAttr
).string());
441 m_inputTypeView
->updateView();
442 setTextAsOfLastFormControlChangeEvent(value());
443 setChangedSinceLastFormControlChangeEvent(false);
446 void HTMLInputElement::updateType()
449 ASSERT(m_inputTypeView
);
451 const AtomicString
& newTypeName
= InputType::normalizeTypeName(fastGetAttribute(typeAttr
));
452 if (m_inputType
->formControlType() == newTypeName
)
455 RefPtrWillBeRawPtr
<InputType
> newType
= InputType::create(*this, newTypeName
);
456 removeFromRadioButtonGroup();
458 bool didStoreValue
= m_inputType
->storesValueSeparateFromAttribute();
459 bool didRespectHeightAndWidth
= m_inputType
->shouldRespectHeightAndWidthAttributes();
461 m_inputTypeView
->destroyShadowSubtree();
462 lazyReattachIfAttached();
464 m_inputType
= newType
.release();
465 if (openShadowRoot())
466 m_inputTypeView
= InputTypeView::create(*this);
468 m_inputTypeView
= m_inputType
;
469 m_inputTypeView
->createShadowSubtree();
471 updateTouchEventHandlerRegistry();
473 setNeedsWillValidateCheck();
475 bool willStoreValue
= m_inputType
->storesValueSeparateFromAttribute();
477 if (didStoreValue
&& !willStoreValue
&& hasDirtyValue()) {
478 setAttribute(valueAttr
, AtomicString(m_valueIfDirty
));
479 m_valueIfDirty
= String();
481 if (!didStoreValue
&& willStoreValue
) {
482 AtomicString valueString
= fastGetAttribute(valueAttr
);
483 m_inputType
->warnIfValueIsInvalid(valueString
);
484 m_valueIfDirty
= sanitizeValue(valueString
);
486 if (!hasDirtyValue())
487 m_inputType
->warnIfValueIsInvalid(fastGetAttribute(valueAttr
).string());
488 updateValueIfNeeded();
491 m_needsToUpdateViewValue
= true;
492 m_inputTypeView
->updateView();
494 if (didRespectHeightAndWidth
!= m_inputType
->shouldRespectHeightAndWidthAttributes()) {
495 ASSERT(elementData());
496 AttributeCollection attributes
= attributesWithoutUpdate();
497 if (const Attribute
* height
= attributes
.find(heightAttr
))
498 attributeChanged(heightAttr
, height
->value());
499 if (const Attribute
* width
= attributes
.find(widthAttr
))
500 attributeChanged(widthAttr
, width
->value());
501 if (const Attribute
* align
= attributes
.find(alignAttr
))
502 attributeChanged(alignAttr
, align
->value());
505 if (document().focusedElement() == this)
506 document().updateFocusAppearanceSoon(true /* restore selection */);
508 setTextAsOfLastFormControlChangeEvent(value());
509 setChangedSinceLastFormControlChangeEvent(false);
511 addToRadioButtonGroup();
513 setNeedsValidityCheck();
514 notifyFormStateChanged();
517 void HTMLInputElement::subtreeHasChanged()
519 m_inputTypeView
->subtreeHasChanged();
520 // When typing in an input field, childrenChanged is not called, so we need to force the directionality check.
521 calculateAndAdjustDirectionality();
524 const AtomicString
& HTMLInputElement::formControlType() const
526 return m_inputType
->formControlType();
529 bool HTMLInputElement::shouldSaveAndRestoreFormControlState() const
531 if (!m_inputType
->shouldSaveAndRestoreFormControlState())
533 return HTMLTextFormControlElement::shouldSaveAndRestoreFormControlState();
536 FormControlState
HTMLInputElement::saveFormControlState() const
538 return m_inputType
->saveFormControlState();
541 void HTMLInputElement::restoreFormControlState(const FormControlState
& state
)
543 m_inputType
->restoreFormControlState(state
);
544 m_stateRestored
= true;
547 bool HTMLInputElement::canStartSelection() const
551 return HTMLTextFormControlElement::canStartSelection();
554 int HTMLInputElement::selectionStartForBinding(ExceptionState
& exceptionState
) const
556 if (!m_inputType
->supportsSelectionAPI()) {
557 exceptionState
.throwDOMException(InvalidStateError
, "The input element's type ('" + m_inputType
->formControlType() + "') does not support selection.");
560 return HTMLTextFormControlElement::selectionStart();
563 int HTMLInputElement::selectionEndForBinding(ExceptionState
& exceptionState
) const
565 if (!m_inputType
->supportsSelectionAPI()) {
566 exceptionState
.throwDOMException(InvalidStateError
, "The input element's type ('" + m_inputType
->formControlType() + "') does not support selection.");
569 return HTMLTextFormControlElement::selectionEnd();
572 String
HTMLInputElement::selectionDirectionForBinding(ExceptionState
& exceptionState
) const
574 if (!m_inputType
->supportsSelectionAPI()) {
575 exceptionState
.throwDOMException(InvalidStateError
, "The input element's type ('" + m_inputType
->formControlType() + "') does not support selection.");
578 return HTMLTextFormControlElement::selectionDirection();
581 void HTMLInputElement::setSelectionStartForBinding(int start
, ExceptionState
& exceptionState
)
583 if (!m_inputType
->supportsSelectionAPI()) {
584 exceptionState
.throwDOMException(InvalidStateError
, "The input element's type ('" + m_inputType
->formControlType() + "') does not support selection.");
587 HTMLTextFormControlElement::setSelectionStart(start
);
590 void HTMLInputElement::setSelectionEndForBinding(int end
, ExceptionState
& exceptionState
)
592 if (!m_inputType
->supportsSelectionAPI()) {
593 exceptionState
.throwDOMException(InvalidStateError
, "The input element's type ('" + m_inputType
->formControlType() + "') does not support selection.");
596 HTMLTextFormControlElement::setSelectionEnd(end
);
599 void HTMLInputElement::setSelectionDirectionForBinding(const String
& direction
, ExceptionState
& exceptionState
)
601 if (!m_inputType
->supportsSelectionAPI()) {
602 exceptionState
.throwDOMException(InvalidStateError
, "The input element's type ('" + m_inputType
->formControlType() + "') does not support selection.");
605 HTMLTextFormControlElement::setSelectionDirection(direction
);
608 void HTMLInputElement::setSelectionRangeForBinding(int start
, int end
, ExceptionState
& exceptionState
)
610 if (!m_inputType
->supportsSelectionAPI()) {
611 exceptionState
.throwDOMException(InvalidStateError
, "The input element's type ('" + m_inputType
->formControlType() + "') does not support selection.");
614 HTMLTextFormControlElement::setSelectionRange(start
, end
);
617 void HTMLInputElement::setSelectionRangeForBinding(int start
, int end
, const String
& direction
, ExceptionState
& exceptionState
)
619 if (!m_inputType
->supportsSelectionAPI()) {
620 exceptionState
.throwDOMException(InvalidStateError
, "The input element's type ('" + m_inputType
->formControlType() + "') does not support selection.");
623 HTMLTextFormControlElement::setSelectionRange(start
, end
, direction
);
626 void HTMLInputElement::accessKeyAction(bool sendMouseEvents
)
628 m_inputType
->accessKeyAction(sendMouseEvents
);
631 bool HTMLInputElement::isPresentationAttribute(const QualifiedName
& name
) const
633 // FIXME: Remove type check.
634 if (name
== vspaceAttr
|| name
== hspaceAttr
|| name
== alignAttr
|| name
== widthAttr
|| name
== heightAttr
|| (name
== borderAttr
&& type() == InputTypeNames::image
))
636 return HTMLTextFormControlElement::isPresentationAttribute(name
);
639 void HTMLInputElement::collectStyleForPresentationAttribute(const QualifiedName
& name
, const AtomicString
& value
, MutableStylePropertySet
* style
)
641 if (name
== vspaceAttr
) {
642 addHTMLLengthToStyle(style
, CSSPropertyMarginTop
, value
);
643 addHTMLLengthToStyle(style
, CSSPropertyMarginBottom
, value
);
644 } else if (name
== hspaceAttr
) {
645 addHTMLLengthToStyle(style
, CSSPropertyMarginLeft
, value
);
646 addHTMLLengthToStyle(style
, CSSPropertyMarginRight
, value
);
647 } else if (name
== alignAttr
) {
648 if (m_inputType
->shouldRespectAlignAttribute())
649 applyAlignmentAttributeToStyle(value
, style
);
650 } else if (name
== widthAttr
) {
651 if (m_inputType
->shouldRespectHeightAndWidthAttributes())
652 addHTMLLengthToStyle(style
, CSSPropertyWidth
, value
);
653 } else if (name
== heightAttr
) {
654 if (m_inputType
->shouldRespectHeightAndWidthAttributes())
655 addHTMLLengthToStyle(style
, CSSPropertyHeight
, value
);
656 } else if (name
== borderAttr
&& type() == InputTypeNames::image
) { // FIXME: Remove type check.
657 applyBorderAttributeToStyle(value
, style
);
659 HTMLTextFormControlElement::collectStyleForPresentationAttribute(name
, value
, style
);
663 void HTMLInputElement::attributeWillChange(const QualifiedName
& name
, const AtomicString
& oldValue
, const AtomicString
& newValue
)
665 if (name
== formactionAttr
&& inDocument()) {
666 V8DOMActivityLogger
* activityLogger
= V8DOMActivityLogger::currentActivityLoggerIfIsolatedWorld();
667 if (activityLogger
) {
669 argv
.append("input");
670 argv
.append(formactionAttr
.toString());
671 argv
.append(oldValue
);
672 argv
.append(newValue
);
673 activityLogger
->logEvent("blinkSetAttribute", argv
.size(), argv
.data());
676 HTMLTextFormControlElement::attributeWillChange(name
, oldValue
, newValue
);
679 void HTMLInputElement::parseAttribute(const QualifiedName
& name
, const AtomicString
& value
)
682 ASSERT(m_inputTypeView
);
684 if (name
== nameAttr
) {
685 removeFromRadioButtonGroup();
687 addToRadioButtonGroup();
688 HTMLTextFormControlElement::parseAttribute(name
, value
);
689 } else if (name
== autocompleteAttr
) {
690 if (equalIgnoringCase(value
, "off")) {
691 m_autocomplete
= Off
;
694 m_autocomplete
= Uninitialized
;
698 } else if (name
== typeAttr
) {
700 } else if (name
== valueAttr
) {
701 // We only need to setChanged if the form is looking at the default value right now.
702 if (!hasDirtyValue()) {
703 updatePlaceholderVisibility(false);
704 setNeedsStyleRecalc(SubtreeStyleChange
, StyleChangeReasonForTracing::fromAttribute(valueAttr
));
706 m_needsToUpdateViewValue
= true;
707 setNeedsValidityCheck();
708 m_valueAttributeWasUpdatedAfterParsing
= !m_parsingInProgress
;
709 m_inputType
->warnIfValueIsInvalidAndElementIsVisible(value
);
710 m_inputTypeView
->valueAttributeChanged();
711 } else if (name
== checkedAttr
) {
712 // Another radio button in the same group might be checked by state
713 // restore. We shouldn't call setChecked() even if this has the checked
714 // attribute. So, delay the setChecked() call until
715 // finishParsingChildren() is called if parsing is in progress.
716 if (!m_parsingInProgress
&& m_reflectsCheckedAttribute
) {
717 setChecked(!value
.isNull());
718 m_reflectsCheckedAttribute
= true;
720 } else if (name
== maxlengthAttr
) {
721 parseMaxLengthAttribute(value
);
722 } else if (name
== minlengthAttr
) {
723 parseMinLengthAttribute(value
);
724 } else if (name
== sizeAttr
) {
725 int oldSize
= m_size
;
726 m_size
= defaultSize
;
728 if (!value
.isEmpty() && parseHTMLInteger(value
, valueAsInteger
) && valueAsInteger
> 0)
729 m_size
= valueAsInteger
;
730 if (m_size
!= oldSize
&& layoutObject())
731 layoutObject()->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(LayoutInvalidationReason::AttributeChanged
);
732 } else if (name
== altAttr
) {
733 m_inputTypeView
->altAttributeChanged();
734 } else if (name
== srcAttr
) {
735 m_inputTypeView
->srcAttributeChanged();
736 } else if (name
== usemapAttr
|| name
== accesskeyAttr
) {
737 // FIXME: ignore for the moment
738 } else if (name
== onsearchAttr
) {
739 // Search field and slider attributes all just cause updateFromElement to be called through style recalcing.
740 setAttributeEventListener(EventTypeNames::search
, createAttributeEventListener(this, name
, value
, eventParameterName()));
741 } else if (name
== resultsAttr
) {
742 int oldResults
= m_maxResults
;
743 m_maxResults
= !value
.isNull() ? std::min(value
.toInt(), maxSavedResults
) : -1;
744 // FIXME: Detaching just for maxResults change is not ideal. We should figure out the right
745 // time to relayout for this change.
746 if (m_maxResults
!= oldResults
&& (m_maxResults
<= 0 || oldResults
<= 0))
747 lazyReattachIfAttached();
748 setNeedsStyleRecalc(SubtreeStyleChange
, StyleChangeReasonForTracing::fromAttribute(resultsAttr
));
749 UseCounter::count(document(), UseCounter::ResultsAttribute
);
750 } else if (name
== incrementalAttr
) {
751 setNeedsStyleRecalc(SubtreeStyleChange
, StyleChangeReasonForTracing::fromAttribute(incrementalAttr
));
752 UseCounter::count(document(), UseCounter::IncrementalAttribute
);
753 } else if (name
== minAttr
) {
754 m_inputTypeView
->minOrMaxAttributeChanged();
755 m_inputType
->sanitizeValueInResponseToMinOrMaxAttributeChange();
756 setNeedsValidityCheck();
757 UseCounter::count(document(), UseCounter::MinAttribute
);
758 } else if (name
== maxAttr
) {
759 m_inputTypeView
->minOrMaxAttributeChanged();
760 m_inputType
->sanitizeValueInResponseToMinOrMaxAttributeChange();
761 setNeedsValidityCheck();
762 UseCounter::count(document(), UseCounter::MaxAttribute
);
763 } else if (name
== multipleAttr
) {
764 m_inputTypeView
->multipleAttributeChanged();
765 setNeedsValidityCheck();
766 } else if (name
== stepAttr
) {
767 m_inputTypeView
->stepAttributeChanged();
768 setNeedsValidityCheck();
769 UseCounter::count(document(), UseCounter::StepAttribute
);
770 } else if (name
== patternAttr
) {
771 setNeedsValidityCheck();
772 UseCounter::count(document(), UseCounter::PatternAttribute
);
773 } else if (name
== disabledAttr
) {
774 HTMLTextFormControlElement::parseAttribute(name
, value
);
775 m_inputTypeView
->disabledAttributeChanged();
776 } else if (name
== readonlyAttr
) {
777 HTMLTextFormControlElement::parseAttribute(name
, value
);
778 m_inputTypeView
->readonlyAttributeChanged();
779 } else if (name
== listAttr
) {
780 m_hasNonEmptyList
= !value
.isEmpty();
781 if (m_hasNonEmptyList
) {
782 resetListAttributeTargetObserver();
783 listAttributeTargetChanged();
785 UseCounter::count(document(), UseCounter::ListAttribute
);
786 } else if (name
== webkitdirectoryAttr
) {
787 HTMLTextFormControlElement::parseAttribute(name
, value
);
788 UseCounter::count(document(), UseCounter::PrefixedDirectoryAttribute
);
790 HTMLTextFormControlElement::parseAttribute(name
, value
);
792 m_inputTypeView
->attributeChanged();
795 void HTMLInputElement::parserDidSetAttributes()
797 ASSERT(m_parsingInProgress
);
798 initializeTypeInParsing();
801 void HTMLInputElement::finishParsingChildren()
803 m_parsingInProgress
= false;
805 ASSERT(m_inputTypeView
);
806 HTMLTextFormControlElement::finishParsingChildren();
807 if (!m_stateRestored
) {
808 bool checked
= hasAttribute(checkedAttr
);
811 m_reflectsCheckedAttribute
= true;
815 bool HTMLInputElement::layoutObjectIsNeeded(const ComputedStyle
& style
)
817 return m_inputType
->layoutObjectIsNeeded() && HTMLTextFormControlElement::layoutObjectIsNeeded(style
);
820 LayoutObject
* HTMLInputElement::createLayoutObject(const ComputedStyle
& style
)
822 return m_inputTypeView
->createLayoutObject(style
);
825 void HTMLInputElement::attach(const AttachContext
& context
)
827 HTMLTextFormControlElement::attach(context
);
829 m_inputTypeView
->startResourceLoading();
830 m_inputType
->countUsage();
832 if (document().focusedElement() == this)
833 document().updateFocusAppearanceSoon(true /* restore selection */);
836 void HTMLInputElement::detach(const AttachContext
& context
)
838 HTMLTextFormControlElement::detach(context
);
839 m_needsToUpdateViewValue
= true;
840 m_inputTypeView
->closePopupView();
843 String
HTMLInputElement::altText() const
845 // http://www.w3.org/TR/1998/REC-html40-19980424/appendix/notes.html#altgen
846 // also heavily discussed by Hixie on bugzilla
847 // note this is intentionally different to HTMLImageElement::altText()
848 String alt
= fastGetAttribute(altAttr
);
849 // fall back to title attribute
851 alt
= fastGetAttribute(titleAttr
);
853 alt
= fastGetAttribute(valueAttr
);
855 alt
= locale().queryString(WebLocalizedString::InputElementAltText
);
859 bool HTMLInputElement::canBeSuccessfulSubmitButton() const
861 return m_inputType
->canBeSuccessfulSubmitButton();
864 bool HTMLInputElement::isActivatedSubmit() const
866 return m_isActivatedSubmit
;
869 void HTMLInputElement::setActivatedSubmit(bool flag
)
871 m_isActivatedSubmit
= flag
;
874 bool HTMLInputElement::appendFormData(FormDataList
& encoding
, bool multipart
)
876 return m_inputType
->isFormDataAppendable() && m_inputType
->appendFormData(encoding
, multipart
);
879 String
HTMLInputElement::resultForDialogSubmit()
881 return m_inputType
->resultForDialogSubmit();
884 void HTMLInputElement::resetImpl()
886 if (m_inputType
->storesValueSeparateFromAttribute()) {
888 setNeedsValidityCheck();
891 setChecked(hasAttribute(checkedAttr
));
892 m_reflectsCheckedAttribute
= true;
895 bool HTMLInputElement::isTextField() const
897 return m_inputType
->isTextField();
900 void HTMLInputElement::dispatchChangeEventIfNeeded()
902 if (inDocument() && m_inputType
->shouldSendChangeEventAfterCheckedChanged())
903 dispatchFormControlChangeEvent();
906 bool HTMLInputElement::checked() const
908 m_inputType
->readingChecked();
912 void HTMLInputElement::setChecked(bool nowChecked
, TextFieldEventBehavior eventBehavior
)
914 if (checked() == nowChecked
)
917 RefPtrWillBeRawPtr
<HTMLInputElement
> protector(this);
918 m_reflectsCheckedAttribute
= false;
919 m_isChecked
= nowChecked
;
921 if (RadioButtonGroupScope
* scope
= radioButtonGroupScope())
922 scope
->updateCheckedState(this);
924 LayoutTheme::theme().controlStateChanged(*layoutObject(), CheckedControlState
);
926 setNeedsValidityCheck();
928 // Ideally we'd do this from the layout tree (matching
929 // LayoutTextView), but it's not possible to do it at the moment
930 // because of the way the code is structured.
931 if (layoutObject()) {
932 if (AXObjectCache
* cache
= layoutObject()->document().existingAXObjectCache())
933 cache
->checkedStateChanged(this);
936 // Only send a change event for items in the document (avoid firing during
937 // parsing) and don't send a change event for a radio button that's getting
938 // unchecked to match other browsers. DOM is not a useful standard for this
939 // because it says only to fire change events at "lose focus" time, which is
940 // definitely wrong in practice for these types of elements.
941 if (eventBehavior
!= DispatchNoEvent
&& inDocument() && m_inputType
->shouldSendChangeEventAfterCheckedChanged()) {
942 setTextAsOfLastFormControlChangeEvent(String());
943 if (eventBehavior
== DispatchInputAndChangeEvent
)
944 dispatchFormControlInputEvent();
947 pseudoStateChanged(CSSSelector::PseudoChecked
);
950 void HTMLInputElement::setIndeterminate(bool newValue
)
952 if (indeterminate() == newValue
)
955 m_isIndeterminate
= newValue
;
957 pseudoStateChanged(CSSSelector::PseudoIndeterminate
);
960 LayoutTheme::theme().controlStateChanged(*layoutObject(), CheckedControlState
);
963 int HTMLInputElement::size() const
968 bool HTMLInputElement::sizeShouldIncludeDecoration(int& preferredSize
) const
970 return m_inputTypeView
->sizeShouldIncludeDecoration(defaultSize
, preferredSize
);
973 void HTMLInputElement::copyNonAttributePropertiesFromElement(const Element
& source
)
975 const HTMLInputElement
& sourceElement
= static_cast<const HTMLInputElement
&>(source
);
977 m_valueIfDirty
= sourceElement
.m_valueIfDirty
;
978 setChecked(sourceElement
.m_isChecked
);
979 m_reflectsCheckedAttribute
= sourceElement
.m_reflectsCheckedAttribute
;
980 m_isIndeterminate
= sourceElement
.m_isIndeterminate
;
982 HTMLTextFormControlElement::copyNonAttributePropertiesFromElement(source
);
984 m_needsToUpdateViewValue
= true;
985 m_inputTypeView
->updateView();
988 String
HTMLInputElement::value() const
991 if (m_inputType
->getTypeSpecificValue(value
))
994 value
= m_valueIfDirty
;
998 AtomicString valueString
= fastGetAttribute(valueAttr
);
999 value
= sanitizeValue(valueString
);
1000 if (!value
.isNull())
1003 return m_inputType
->fallbackValue();
1006 String
HTMLInputElement::valueWithDefault() const
1008 String value
= this->value();
1009 if (!value
.isNull())
1012 return m_inputType
->defaultValue();
1015 void HTMLInputElement::setValueForUser(const String
& value
)
1017 // Call setValue and make it send a change event.
1018 setValue(value
, DispatchChangeEvent
);
1021 const String
& HTMLInputElement::suggestedValue() const
1023 return m_suggestedValue
;
1026 void HTMLInputElement::setSuggestedValue(const String
& value
)
1028 if (!m_inputType
->canSetSuggestedValue())
1030 m_needsToUpdateViewValue
= true;
1031 m_suggestedValue
= sanitizeValue(value
);
1032 setNeedsStyleRecalc(SubtreeStyleChange
, StyleChangeReasonForTracing::create(StyleChangeReason::ControlValue
));
1033 m_inputTypeView
->updateView();
1036 void HTMLInputElement::setEditingValue(const String
& value
)
1038 if (!layoutObject() || !isTextField())
1040 setInnerEditorValue(value
);
1041 subtreeHasChanged();
1043 unsigned max
= value
.length();
1045 setSelectionRange(max
, max
, SelectionHasNoDirection
, NotDispatchSelectEvent
);
1047 cacheSelectionInResponseToSetValue(max
);
1049 dispatchInputEvent();
1052 void HTMLInputElement::setInnerEditorValue(const String
& value
)
1054 HTMLTextFormControlElement::setInnerEditorValue(value
);
1055 m_needsToUpdateViewValue
= false;
1058 void HTMLInputElement::setValue(const String
& value
, ExceptionState
& exceptionState
, TextFieldEventBehavior eventBehavior
)
1060 // FIXME: Remove type check.
1061 if (type() == InputTypeNames::file
&& !value
.isEmpty()) {
1062 exceptionState
.throwDOMException(InvalidStateError
, "This input element accepts a filename, which may only be programmatically set to the empty string.");
1065 setValue(value
, eventBehavior
);
1068 void HTMLInputElement::setValue(const String
& value
, TextFieldEventBehavior eventBehavior
)
1070 m_inputType
->warnIfValueIsInvalidAndElementIsVisible(value
);
1071 if (!m_inputType
->canSetValue(value
))
1074 RefPtrWillBeRawPtr
<HTMLInputElement
> protector(this);
1075 EventQueueScope scope
;
1076 String sanitizedValue
= sanitizeValue(value
);
1077 bool valueChanged
= sanitizedValue
!= this->value();
1079 setLastChangeWasNotUserEdit();
1080 m_needsToUpdateViewValue
= true;
1081 m_suggestedValue
= String(); // Prevent TextFieldInputType::setValue from using the suggested value.
1083 m_inputType
->setValue(sanitizedValue
, valueChanged
, eventBehavior
);
1085 if (valueChanged
&& eventBehavior
== DispatchNoEvent
)
1086 setTextAsOfLastFormControlChangeEvent(sanitizedValue
.isNull() ? defaultValue() : sanitizedValue
);
1091 notifyFormStateChanged();
1094 void HTMLInputElement::setValueInternal(const String
& sanitizedValue
, TextFieldEventBehavior eventBehavior
)
1096 m_valueIfDirty
= sanitizedValue
;
1097 setNeedsValidityCheck();
1098 if (document().focusedElement() == this)
1099 document().frameHost()->chromeClient().didUpdateTextOfFocusedElementByNonUserInput();
1102 void HTMLInputElement::updateView()
1104 m_inputTypeView
->updateView();
1107 double HTMLInputElement::valueAsDate(bool& isNull
) const
1109 double date
= m_inputType
->valueAsDate();
1110 isNull
= !std::isfinite(date
);
1114 void HTMLInputElement::setValueAsDate(double value
, ExceptionState
& exceptionState
)
1116 m_inputType
->setValueAsDate(value
, exceptionState
);
1119 double HTMLInputElement::valueAsNumber() const
1121 return m_inputType
->valueAsDouble();
1124 void HTMLInputElement::setValueAsNumber(double newValue
, ExceptionState
& exceptionState
, TextFieldEventBehavior eventBehavior
)
1126 // http://www.whatwg.org/specs/web-apps/current-work/multipage/common-input-element-attributes.html#dom-input-valueasnumber
1127 // On setting, if the new value is infinite, then throw a TypeError exception.
1128 if (std::isinf(newValue
)) {
1129 exceptionState
.throwTypeError(ExceptionMessages::notAFiniteNumber(newValue
));
1132 m_inputType
->setValueAsDouble(newValue
, eventBehavior
, exceptionState
);
1135 void HTMLInputElement::setValueFromRenderer(const String
& value
)
1137 // File upload controls will never use this.
1138 ASSERT(type() != InputTypeNames::file
);
1140 m_suggestedValue
= String();
1142 // Renderer and our event handler are responsible for sanitizing values.
1143 ASSERT(value
== sanitizeValue(value
) || sanitizeValue(value
).isEmpty());
1145 m_valueIfDirty
= value
;
1146 m_needsToUpdateViewValue
= false;
1148 // Input event is fired by the Node::defaultEventHandler for editable controls.
1150 dispatchInputEvent();
1151 notifyFormStateChanged();
1153 setNeedsValidityCheck();
1155 // Clear autofill flag (and yellow background) on user edit.
1156 setAutofilled(false);
1159 void* HTMLInputElement::preDispatchEventHandler(Event
* event
)
1161 if (event
->type() == EventTypeNames::textInput
&& m_inputTypeView
->shouldSubmitImplicitly(event
)) {
1162 event
->stopPropagation();
1165 if (event
->type() != EventTypeNames::click
)
1167 if (!event
->isMouseEvent() || toMouseEvent(event
)->button() != LeftButton
)
1170 return m_inputTypeView
->willDispatchClick();
1172 // FIXME: Check whether there are any cases where this actually ends up leaking.
1173 return m_inputTypeView
->willDispatchClick().leakPtr();
1177 void HTMLInputElement::postDispatchEventHandler(Event
* event
, void* dataFromPreDispatch
)
1179 OwnPtrWillBeRawPtr
<ClickHandlingState
> state
= adoptPtrWillBeNoop(static_cast<ClickHandlingState
*>(dataFromPreDispatch
));
1182 m_inputTypeView
->didDispatchClick(event
, *state
);
1185 void HTMLInputElement::defaultEventHandler(Event
* evt
)
1187 if (evt
->isMouseEvent() && evt
->type() == EventTypeNames::click
&& toMouseEvent(evt
)->button() == LeftButton
) {
1188 m_inputTypeView
->handleClickEvent(toMouseEvent(evt
));
1189 if (evt
->defaultHandled())
1193 if (evt
->isTouchEvent() && m_inputTypeView
->hasTouchEventHandler()) {
1194 m_inputTypeView
->handleTouchEvent(toTouchEvent(evt
));
1195 if (evt
->defaultHandled())
1199 if (evt
->isKeyboardEvent() && evt
->type() == EventTypeNames::keydown
) {
1200 m_inputTypeView
->handleKeydownEvent(toKeyboardEvent(evt
));
1201 if (evt
->defaultHandled())
1205 // Call the base event handler before any of our own event handling for almost all events in text fields.
1206 // Makes editing keyboard handling take precedence over the keydown and keypress handling in this function.
1207 bool callBaseClassEarly
= isTextField() && (evt
->type() == EventTypeNames::keydown
|| evt
->type() == EventTypeNames::keypress
);
1208 if (callBaseClassEarly
) {
1209 HTMLTextFormControlElement::defaultEventHandler(evt
);
1210 if (evt
->defaultHandled())
1214 // DOMActivate events cause the input to be "activated" - in the case of image and submit inputs, this means
1215 // actually submitting the form. For reset inputs, the form is reset. These events are sent when the user clicks
1216 // on the element, or presses enter while it is the active element. JavaScript code wishing to activate the element
1217 // must dispatch a DOMActivate event - a click event will not do the job.
1218 if (evt
->type() == EventTypeNames::DOMActivate
) {
1219 m_inputType
->handleDOMActivateEvent(evt
);
1220 if (evt
->defaultHandled())
1224 // Use key press event here since sending simulated mouse events
1225 // on key down blocks the proper sending of the key press event.
1226 if (evt
->isKeyboardEvent() && evt
->type() == EventTypeNames::keypress
) {
1227 m_inputTypeView
->handleKeypressEvent(toKeyboardEvent(evt
));
1228 if (evt
->defaultHandled())
1232 if (evt
->isKeyboardEvent() && evt
->type() == EventTypeNames::keyup
) {
1233 m_inputTypeView
->handleKeyupEvent(toKeyboardEvent(evt
));
1234 if (evt
->defaultHandled())
1238 if (m_inputTypeView
->shouldSubmitImplicitly(evt
)) {
1239 // FIXME: Remove type check.
1240 if (type() == InputTypeNames::search
)
1242 // Form submission finishes editing, just as loss of focus does.
1243 // If there was a change, send the event now.
1244 if (wasChangedSinceLastFormControlChangeEvent())
1245 dispatchFormControlChangeEvent();
1247 RefPtrWillBeRawPtr
<HTMLFormElement
> formForSubmission
= m_inputTypeView
->formForSubmission();
1248 // Form may never have been present, or may have been destroyed by code responding to the change event.
1249 if (formForSubmission
)
1250 formForSubmission
->submitImplicitly(evt
, canTriggerImplicitSubmission());
1252 evt
->setDefaultHandled();
1256 if (evt
->isBeforeTextInsertedEvent())
1257 m_inputTypeView
->handleBeforeTextInsertedEvent(static_cast<BeforeTextInsertedEvent
*>(evt
));
1259 if (evt
->isMouseEvent() && evt
->type() == EventTypeNames::mousedown
) {
1260 m_inputTypeView
->handleMouseDownEvent(toMouseEvent(evt
));
1261 if (evt
->defaultHandled())
1265 m_inputTypeView
->forwardEvent(evt
);
1267 if (!callBaseClassEarly
&& !evt
->defaultHandled())
1268 HTMLTextFormControlElement::defaultEventHandler(evt
);
1271 bool HTMLInputElement::willRespondToMouseClickEvents()
1273 // FIXME: Consider implementing willRespondToMouseClickEvents() in InputType if more accurate results are necessary.
1274 if (!isDisabledFormControl())
1277 return HTMLTextFormControlElement::willRespondToMouseClickEvents();
1280 bool HTMLInputElement::isURLAttribute(const Attribute
& attribute
) const
1282 return attribute
.name() == srcAttr
|| attribute
.name() == formactionAttr
|| HTMLTextFormControlElement::isURLAttribute(attribute
);
1285 bool HTMLInputElement::hasLegalLinkAttribute(const QualifiedName
& name
) const
1287 return m_inputType
->hasLegalLinkAttribute(name
) || HTMLTextFormControlElement::hasLegalLinkAttribute(name
);
1290 const QualifiedName
& HTMLInputElement::subResourceAttributeName() const
1292 return m_inputType
->subResourceAttributeName();
1295 const AtomicString
& HTMLInputElement::defaultValue() const
1297 return fastGetAttribute(valueAttr
);
1300 static inline bool isRFC2616TokenCharacter(UChar ch
)
1302 return isASCII(ch
) && ch
> ' ' && ch
!= '"' && ch
!= '(' && ch
!= ')' && ch
!= ',' && ch
!= '/' && (ch
< ':' || ch
> '@') && (ch
< '[' || ch
> ']') && ch
!= '{' && ch
!= '}' && ch
!= 0x7f;
1305 static bool isValidMIMEType(const String
& type
)
1307 size_t slashPosition
= type
.find('/');
1308 if (slashPosition
== kNotFound
|| !slashPosition
|| slashPosition
== type
.length() - 1)
1310 for (size_t i
= 0; i
< type
.length(); ++i
) {
1311 if (!isRFC2616TokenCharacter(type
[i
]) && i
!= slashPosition
)
1317 static bool isValidFileExtension(const String
& type
)
1319 if (type
.length() < 2)
1321 return type
[0] == '.';
1324 static Vector
<String
> parseAcceptAttribute(const String
& acceptString
, bool (*predicate
)(const String
&))
1326 Vector
<String
> types
;
1327 if (acceptString
.isEmpty())
1330 Vector
<String
> splitTypes
;
1331 acceptString
.split(',', false, splitTypes
);
1332 for (const String
& splitType
: splitTypes
) {
1333 String trimmedType
= stripLeadingAndTrailingHTMLSpaces(splitType
);
1334 if (trimmedType
.isEmpty())
1336 if (!predicate(trimmedType
))
1338 types
.append(trimmedType
.lower());
1344 Vector
<String
> HTMLInputElement::acceptMIMETypes()
1346 return parseAcceptAttribute(fastGetAttribute(acceptAttr
), isValidMIMEType
);
1349 Vector
<String
> HTMLInputElement::acceptFileExtensions()
1351 return parseAcceptAttribute(fastGetAttribute(acceptAttr
), isValidFileExtension
);
1354 const AtomicString
& HTMLInputElement::alt() const
1356 return fastGetAttribute(altAttr
);
1359 int HTMLInputElement::maxLength() const
1364 int HTMLInputElement::minLength() const
1369 void HTMLInputElement::setMaxLength(int maxLength
, ExceptionState
& exceptionState
)
1372 exceptionState
.throwDOMException(IndexSizeError
, "The value provided (" + String::number(maxLength
) + ") is negative.");
1373 else if (maxLength
< m_minLength
)
1374 exceptionState
.throwDOMException(IndexSizeError
, ExceptionMessages::indexExceedsMinimumBound("maxLength", maxLength
, m_minLength
));
1376 setIntegralAttribute(maxlengthAttr
, maxLength
);
1379 void HTMLInputElement::setMinLength(int minLength
, ExceptionState
& exceptionState
)
1382 exceptionState
.throwDOMException(IndexSizeError
, "The value provided (" + String::number(minLength
) + ") is negative.");
1383 else if (minLength
> m_maxLength
)
1384 exceptionState
.throwDOMException(IndexSizeError
, ExceptionMessages::indexExceedsMaximumBound("minLength", minLength
, m_maxLength
));
1386 setIntegralAttribute(minlengthAttr
, minLength
);
1389 bool HTMLInputElement::multiple() const
1391 return fastHasAttribute(multipleAttr
);
1394 void HTMLInputElement::setSize(unsigned size
)
1396 setUnsignedIntegralAttribute(sizeAttr
, size
);
1399 void HTMLInputElement::setSize(unsigned size
, ExceptionState
& exceptionState
)
1402 exceptionState
.throwDOMException(IndexSizeError
, "The value provided is 0, which is an invalid size.");
1407 KURL
HTMLInputElement::src() const
1409 return document().completeURL(fastGetAttribute(srcAttr
));
1412 FileList
* HTMLInputElement::files()
1414 return m_inputType
->files();
1417 void HTMLInputElement::setFiles(FileList
* files
)
1419 m_inputType
->setFiles(files
);
1422 bool HTMLInputElement::receiveDroppedFiles(const DragData
* dragData
)
1424 return m_inputType
->receiveDroppedFiles(dragData
);
1427 String
HTMLInputElement::droppedFileSystemId()
1429 return m_inputType
->droppedFileSystemId();
1432 bool HTMLInputElement::canReceiveDroppedFiles() const
1434 return m_canReceiveDroppedFiles
;
1437 void HTMLInputElement::setCanReceiveDroppedFiles(bool canReceiveDroppedFiles
)
1439 if (!!m_canReceiveDroppedFiles
== canReceiveDroppedFiles
)
1441 m_canReceiveDroppedFiles
= canReceiveDroppedFiles
;
1443 layoutObject()->updateFromElement();
1446 String
HTMLInputElement::sanitizeValue(const String
& proposedValue
) const
1448 if (proposedValue
.isNull())
1449 return proposedValue
;
1450 return m_inputType
->sanitizeValue(proposedValue
);
1453 String
HTMLInputElement::localizeValue(const String
& proposedValue
) const
1455 if (proposedValue
.isNull())
1456 return proposedValue
;
1457 return m_inputType
->localizeValue(proposedValue
);
1460 bool HTMLInputElement::isInRange() const
1462 return m_inputType
->isInRange(value());
1465 bool HTMLInputElement::isOutOfRange() const
1467 return m_inputType
->isOutOfRange(value());
1470 bool HTMLInputElement::isRequiredFormControl() const
1472 return m_inputType
->supportsRequired() && isRequired();
1475 bool HTMLInputElement::matchesReadOnlyPseudoClass() const
1477 return m_inputType
->supportsReadOnly() && isReadOnly();
1480 bool HTMLInputElement::matchesReadWritePseudoClass() const
1482 return m_inputType
->supportsReadOnly() && !isReadOnly();
1485 void HTMLInputElement::onSearch()
1487 // FIXME: Remove type check, and static_cast.
1488 ASSERT(type() == InputTypeNames::search
);
1490 static_cast<SearchInputType
*>(m_inputType
.get())->stopSearchEventTimer();
1491 dispatchEvent(Event::createBubble(EventTypeNames::search
));
1494 void HTMLInputElement::updateClearButtonVisibility()
1496 m_inputTypeView
->updateClearButtonVisibility();
1499 void HTMLInputElement::willChangeForm()
1501 removeFromRadioButtonGroup();
1502 HTMLTextFormControlElement::willChangeForm();
1505 void HTMLInputElement::didChangeForm()
1507 HTMLTextFormControlElement::didChangeForm();
1508 addToRadioButtonGroup();
1511 Node::InsertionNotificationRequest
HTMLInputElement::insertedInto(ContainerNode
* insertionPoint
)
1513 if (insertionPoint
->inDocument()) {
1514 V8DOMActivityLogger
* activityLogger
= V8DOMActivityLogger::currentActivityLoggerIfIsolatedWorld();
1515 if (activityLogger
) {
1516 Vector
<String
> argv
;
1517 argv
.append("input");
1518 argv
.append(fastGetAttribute(typeAttr
));
1519 argv
.append(fastGetAttribute(formactionAttr
));
1520 activityLogger
->logEvent("blinkAddElement", argv
.size(), argv
.data());
1523 HTMLTextFormControlElement::insertedInto(insertionPoint
);
1524 if (insertionPoint
->inDocument() && !form())
1525 addToRadioButtonGroup();
1526 resetListAttributeTargetObserver();
1527 return InsertionShouldCallDidNotifySubtreeInsertions
;
1530 void HTMLInputElement::removedFrom(ContainerNode
* insertionPoint
)
1532 m_inputTypeView
->closePopupView();
1533 if (insertionPoint
->inDocument() && !form())
1534 removeFromRadioButtonGroup();
1535 HTMLTextFormControlElement::removedFrom(insertionPoint
);
1536 ASSERT(!inDocument());
1537 resetListAttributeTargetObserver();
1540 void HTMLInputElement::didMoveToNewDocument(Document
& oldDocument
)
1543 imageLoader()->elementDidMoveToNewDocument();
1545 // FIXME: Remove type check.
1546 if (type() == InputTypeNames::radio
)
1547 oldDocument
.formController().radioButtonGroupScope().removeButton(this);
1549 HTMLTextFormControlElement::didMoveToNewDocument(oldDocument
);
1552 void HTMLInputElement::removeAllEventListeners()
1554 HTMLTextFormControlElement::removeAllEventListeners();
1555 m_hasTouchEventHandler
= false;
1558 bool HTMLInputElement::recalcWillValidate() const
1560 return m_inputType
->supportsValidation() && HTMLTextFormControlElement::recalcWillValidate();
1563 void HTMLInputElement::requiredAttributeChanged()
1565 HTMLTextFormControlElement::requiredAttributeChanged();
1566 if (RadioButtonGroupScope
* scope
= radioButtonGroupScope())
1567 scope
->requiredAttributeChanged(this);
1568 m_inputTypeView
->requiredAttributeChanged();
1571 void HTMLInputElement::selectColorInColorChooser(const Color
& color
)
1573 if (ColorChooserClient
* client
= m_inputType
->colorChooserClient())
1574 client
->didChooseColor(color
);
1577 void HTMLInputElement::endColorChooser()
1579 if (ColorChooserClient
* client
= m_inputType
->colorChooserClient())
1580 client
->didEndChooser();
1583 HTMLElement
* HTMLInputElement::list() const
1588 HTMLDataListElement
* HTMLInputElement::dataList() const
1590 if (!m_hasNonEmptyList
)
1593 if (!m_inputType
->shouldRespectListAttribute())
1596 Element
* element
= treeScope().getElementById(fastGetAttribute(listAttr
));
1599 if (!isHTMLDataListElement(*element
))
1602 return toHTMLDataListElement(element
);
1605 bool HTMLInputElement::hasValidDataListOptions() const
1607 HTMLDataListElement
* dataList
= this->dataList();
1610 RefPtrWillBeRawPtr
<HTMLDataListOptionsCollection
> options
= dataList
->options();
1611 for (unsigned i
= 0; HTMLOptionElement
* option
= options
->item(i
); ++i
) {
1612 if (isValidValue(option
->value()))
1618 void HTMLInputElement::setListAttributeTargetObserver(PassOwnPtrWillBeRawPtr
<ListAttributeTargetObserver
> newObserver
)
1620 if (m_listAttributeTargetObserver
)
1621 m_listAttributeTargetObserver
->unregister();
1622 m_listAttributeTargetObserver
= newObserver
;
1625 void HTMLInputElement::resetListAttributeTargetObserver()
1628 setListAttributeTargetObserver(ListAttributeTargetObserver::create(fastGetAttribute(listAttr
), this));
1630 setListAttributeTargetObserver(nullptr);
1633 void HTMLInputElement::listAttributeTargetChanged()
1635 m_inputTypeView
->listAttributeTargetChanged();
1638 bool HTMLInputElement::isSteppable() const
1640 return m_inputType
->isSteppable();
1643 bool HTMLInputElement::isTextButton() const
1645 return m_inputType
->isTextButton();
1648 bool HTMLInputElement::isImage() const
1650 return m_inputType
->isImage();
1653 bool HTMLInputElement::isEnumeratable() const
1655 return m_inputType
->isEnumeratable();
1658 bool HTMLInputElement::supportLabels() const
1660 return m_inputType
->isInteractiveContent();
1663 bool HTMLInputElement::shouldAppearChecked() const
1665 return checked() && m_inputType
->isCheckable();
1668 bool HTMLInputElement::supportsPlaceholder() const
1670 return m_inputType
->supportsPlaceholder();
1673 void HTMLInputElement::updatePlaceholderText()
1675 return m_inputTypeView
->updatePlaceholderText();
1678 void HTMLInputElement::parseMaxLengthAttribute(const AtomicString
& value
)
1681 if (!parseHTMLInteger(value
, maxLength
))
1682 maxLength
= maximumLength
;
1683 if (maxLength
< 0 || maxLength
> maximumLength
)
1684 maxLength
= maximumLength
;
1685 int oldMaxLength
= m_maxLength
;
1686 m_maxLength
= maxLength
;
1687 if (oldMaxLength
!= maxLength
)
1688 updateValueIfNeeded();
1689 setNeedsStyleRecalc(SubtreeStyleChange
, StyleChangeReasonForTracing::fromAttribute(maxlengthAttr
));
1690 setNeedsValidityCheck();
1693 void HTMLInputElement::parseMinLengthAttribute(const AtomicString
& value
)
1696 if (!parseHTMLInteger(value
, minLength
))
1700 m_minLength
= minLength
;
1701 setNeedsStyleRecalc(SubtreeStyleChange
, StyleChangeReasonForTracing::fromAttribute(minlengthAttr
));
1702 setNeedsValidityCheck();
1705 void HTMLInputElement::updateValueIfNeeded()
1707 String newValue
= sanitizeValue(m_valueIfDirty
);
1708 ASSERT(!m_valueIfDirty
.isNull() || newValue
.isNull());
1709 if (newValue
!= m_valueIfDirty
)
1713 bool HTMLInputElement::supportsAutocapitalize() const
1715 return m_inputType
->supportsAutocapitalize();
1718 const AtomicString
& HTMLInputElement::defaultAutocapitalize() const
1720 return m_inputType
->defaultAutocapitalize();
1723 String
HTMLInputElement::defaultToolTip() const
1725 return m_inputType
->defaultToolTip();
1728 bool HTMLInputElement::shouldAppearIndeterminate() const
1730 return m_inputType
->shouldAppearIndeterminate();
1733 bool HTMLInputElement::isInRequiredRadioButtonGroup()
1735 // FIXME: Remove type check.
1736 ASSERT(type() == InputTypeNames::radio
);
1737 if (RadioButtonGroupScope
* scope
= radioButtonGroupScope())
1738 return scope
->isInRequiredGroup(this);
1742 HTMLInputElement
* HTMLInputElement::checkedRadioButtonForGroup()
1746 if (RadioButtonGroupScope
* scope
= radioButtonGroupScope())
1747 return scope
->checkedButtonForGroup(name());
1751 RadioButtonGroupScope
* HTMLInputElement::radioButtonGroupScope() const
1753 // FIXME: Remove type check.
1754 if (type() != InputTypeNames::radio
)
1756 if (HTMLFormElement
* formElement
= form())
1757 return &formElement
->radioButtonGroupScope();
1759 return &document().formController().radioButtonGroupScope();
1763 inline void HTMLInputElement::addToRadioButtonGroup()
1765 if (RadioButtonGroupScope
* scope
= radioButtonGroupScope())
1766 scope
->addButton(this);
1769 inline void HTMLInputElement::removeFromRadioButtonGroup()
1771 if (RadioButtonGroupScope
* scope
= radioButtonGroupScope())
1772 scope
->removeButton(this);
1775 unsigned HTMLInputElement::height() const
1777 return m_inputType
->height();
1780 unsigned HTMLInputElement::width() const
1782 return m_inputType
->width();
1785 void HTMLInputElement::setHeight(unsigned height
)
1787 setUnsignedIntegralAttribute(heightAttr
, height
);
1790 void HTMLInputElement::setWidth(unsigned width
)
1792 setUnsignedIntegralAttribute(widthAttr
, width
);
1795 PassOwnPtrWillBeRawPtr
<ListAttributeTargetObserver
> ListAttributeTargetObserver::create(const AtomicString
& id
, HTMLInputElement
* element
)
1797 return adoptPtrWillBeNoop(new ListAttributeTargetObserver(id
, element
));
1800 ListAttributeTargetObserver::ListAttributeTargetObserver(const AtomicString
& id
, HTMLInputElement
* element
)
1801 : IdTargetObserver(element
->treeScope().idTargetObserverRegistry(), id
)
1802 , m_element(element
)
1806 DEFINE_TRACE(ListAttributeTargetObserver
)
1808 visitor
->trace(m_element
);
1809 IdTargetObserver::trace(visitor
);
1812 void ListAttributeTargetObserver::idTargetChanged()
1814 m_element
->listAttributeTargetChanged();
1817 void HTMLInputElement::setRangeText(const String
& replacement
, ExceptionState
& exceptionState
)
1819 if (!m_inputType
->supportsSelectionAPI()) {
1820 exceptionState
.throwDOMException(InvalidStateError
, "The input element's type ('" + m_inputType
->formControlType() + "') does not support selection.");
1824 HTMLTextFormControlElement::setRangeText(replacement
, exceptionState
);
1827 void HTMLInputElement::setRangeText(const String
& replacement
, unsigned start
, unsigned end
, const String
& selectionMode
, ExceptionState
& exceptionState
)
1829 if (!m_inputType
->supportsSelectionAPI()) {
1830 exceptionState
.throwDOMException(InvalidStateError
, "The input element's type ('" + m_inputType
->formControlType() + "') does not support selection.");
1834 HTMLTextFormControlElement::setRangeText(replacement
, start
, end
, selectionMode
, exceptionState
);
1837 bool HTMLInputElement::setupDateTimeChooserParameters(DateTimeChooserParameters
& parameters
)
1839 if (!document().view())
1842 parameters
.type
= type();
1843 parameters
.minimum
= minimum();
1844 parameters
.maximum
= maximum();
1845 parameters
.required
= isRequired();
1846 if (!RuntimeEnabledFeatures::langAttributeAwareFormControlUIEnabled()) {
1847 parameters
.locale
= defaultLanguage();
1849 AtomicString computedLocale
= computeInheritedLanguage();
1850 parameters
.locale
= computedLocale
.isEmpty() ? defaultLanguage() : computedLocale
;
1853 StepRange stepRange
= createStepRange(RejectAny
);
1854 if (stepRange
.hasStep()) {
1855 parameters
.step
= stepRange
.step().toDouble();
1856 parameters
.stepBase
= stepRange
.stepBase().toDouble();
1858 parameters
.step
= 1.0;
1859 parameters
.stepBase
= 0;
1862 parameters
.anchorRectInRootFrame
= document().view()->contentsToRootFrame(pixelSnappedBoundingBox());
1863 parameters
.anchorRectInScreen
= document().view()->contentsToScreen(pixelSnappedBoundingBox());
1864 parameters
.currentValue
= value();
1865 parameters
.doubleValue
= m_inputType
->valueAsDouble();
1866 parameters
.isAnchorElementRTL
= m_inputType
->computedTextDirection() == RTL
;
1867 if (HTMLDataListElement
* dataList
= this->dataList()) {
1868 RefPtrWillBeRawPtr
<HTMLDataListOptionsCollection
> options
= dataList
->options();
1869 for (unsigned i
= 0; HTMLOptionElement
* option
= options
->item(i
); ++i
) {
1870 if (!isValidValue(option
->value()))
1872 DateTimeSuggestion suggestion
;
1873 suggestion
.value
= m_inputType
->parseToNumber(option
->value(), Decimal::nan()).toDouble();
1874 if (std::isnan(suggestion
.value
))
1876 suggestion
.localizedValue
= localizeValue(option
->value());
1877 suggestion
.label
= option
->value() == option
->label() ? String() : option
->label();
1878 parameters
.suggestions
.append(suggestion
);
1884 bool HTMLInputElement::supportsInputModeAttribute() const
1886 return m_inputType
->supportsInputModeAttribute();
1889 void HTMLInputElement::setShouldRevealPassword(bool value
)
1891 if (!!m_shouldRevealPassword
== value
)
1893 m_shouldRevealPassword
= value
;
1894 lazyReattachIfAttached();
1897 bool HTMLInputElement::isInteractiveContent() const
1899 return m_inputType
->isInteractiveContent();
1902 bool HTMLInputElement::supportsAutofocus() const
1904 return m_inputType
->isInteractiveContent();
1907 PassRefPtr
<ComputedStyle
> HTMLInputElement::customStyleForLayoutObject()
1909 return m_inputTypeView
->customStyleForLayoutObject(originalStyleForLayoutObject());
1912 bool HTMLInputElement::shouldDispatchFormControlChangeEvent(String
& oldValue
, String
& newValue
)
1914 return m_inputType
->shouldDispatchFormControlChangeEvent(oldValue
, newValue
);
1917 void HTMLInputElement::didNotifySubtreeInsertionsToDocument()
1919 listAttributeTargetChanged();
1922 AXObject
* HTMLInputElement::popupRootAXObject()
1924 return m_inputTypeView
->popupRootAXObject();
1927 void HTMLInputElement::ensureFallbackContent()
1929 m_inputTypeView
->ensureFallbackContent();
1932 void HTMLInputElement::ensurePrimaryContent()
1934 m_inputTypeView
->ensurePrimaryContent();
1937 bool HTMLInputElement::hasFallbackContent() const
1939 return m_inputTypeView
->hasFallbackContent();