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-2018 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 "CSSGradientValue.h"
35#include "CSSPropertyNames.h"
36#include "CSSValuePool.h"
37#include "Chrome.h"
38#include "ChromeClient.h"
39#include "DateTimeChooser.h"
40#include "Document.h"
41#include "Editor.h"
42#include "EventNames.h"
43#include "FileInputType.h"
44#include "FileList.h"
45#include "FormController.h"
46#include "Frame.h"
47#include "FrameSelection.h"
48#include "FrameView.h"
49#include "HTMLDataListElement.h"
50#include "HTMLFormElement.h"
51#include "HTMLImageLoader.h"
52#include "HTMLOptionElement.h"
53#include "HTMLParserIdioms.h"
54#include "IdTargetObserver.h"
55#include "KeyboardEvent.h"
56#include "LocalizedStrings.h"
57#include "MouseEvent.h"
58#include "Page.h"
59#include "PlatformMouseEvent.h"
60#include "RenderTextControlSingleLine.h"
61#include "RenderTheme.h"
62#include "ScopedEventQueue.h"
63#include "SearchInputType.h"
64#include "Settings.h"
65#include "StyleResolver.h"
66#include "TextControlInnerElements.h"
67#include <wtf/IsoMallocInlines.h>
68#include <wtf/Language.h>
69#include <wtf/MathExtras.h>
70#include <wtf/Ref.h>
71
72#if ENABLE(TOUCH_EVENTS)
73#include "TouchEvent.h"
74#endif
75
76namespace WebCore {
77
78WTF_MAKE_ISO_ALLOCATED_IMPL(HTMLInputElement);
79
80using namespace HTMLNames;
81
82#if ENABLE(DATALIST_ELEMENT)
83class ListAttributeTargetObserver : IdTargetObserver {
84 WTF_MAKE_FAST_ALLOCATED;
85public:
86 ListAttributeTargetObserver(const AtomicString& id, HTMLInputElement*);
87
88 void idTargetChanged() override;
89
90private:
91 HTMLInputElement* m_element;
92};
93#endif
94
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.
99const unsigned HTMLInputElement::maxEffectiveLength = 524288;
100const int defaultSize = 20;
101const int maxSavedResults = 256;
102
103HTMLInputElement::HTMLInputElement(const QualifiedName& tagName, Document& document, HTMLFormElement* form, bool createdByParser)
104 : HTMLTextFormControlElement(tagName, document, form)
105 , m_size(defaultSize)
106 , m_isChecked(false)
107 , m_dirtyCheckednessFlag(false)
108 , m_isIndeterminate(false)
109 , m_hasType(false)
110 , m_isActivatedSubmit(false)
111 , m_autocomplete(Uninitialized)
112 , m_isAutoFilled(false)
113 , m_autoFillButtonType(static_cast<uint8_t>(AutoFillButtonType::None))
114 , m_lastAutoFillButtonType(static_cast<uint8_t>(AutoFillButtonType::None))
115 , m_isAutoFillAvailable(false)
116#if ENABLE(DATALIST_ELEMENT)
117 , m_hasNonEmptyList(false)
118#endif
119 , m_stateRestored(false)
120 , m_parsingInProgress(createdByParser)
121 , m_valueAttributeWasUpdatedAfterParsing(false)
122 , m_wasModifiedByUser(false)
123 , m_canReceiveDroppedFiles(false)
124#if ENABLE(TOUCH_EVENTS)
125 , m_hasTouchEventHandler(false)
126#endif
127 , m_isSpellcheckDisabledExceptTextReplacement(false)
128{
129 // m_inputType is lazily created when constructed by the parser to avoid constructing unnecessarily a text inputType and
130 // its shadow subtree, just to destroy them when the |type| attribute gets set by the parser to something else than 'text'.
131 if (!createdByParser)
132 m_inputType = InputType::createText(*this);
133
134 ASSERT(hasTagName(inputTag));
135 setHasCustomStyleResolveCallbacks();
136}
137
138Ref<HTMLInputElement> HTMLInputElement::create(const QualifiedName& tagName, Document& document, HTMLFormElement* form, bool createdByParser)
139{
140 bool shouldCreateShadowRootLazily = createdByParser;
141 Ref<HTMLInputElement> inputElement = adoptRef(*new HTMLInputElement(tagName, document, form, createdByParser));
142 if (!shouldCreateShadowRootLazily)
143 inputElement->ensureUserAgentShadowRoot();
144 return inputElement;
145}
146
147HTMLImageLoader& HTMLInputElement::ensureImageLoader()
148{
149 if (!m_imageLoader)
150 m_imageLoader = std::make_unique<HTMLImageLoader>(*this);
151 return *m_imageLoader;
152}
153
154void HTMLInputElement::didAddUserAgentShadowRoot(ShadowRoot&)
155{
156 Ref<InputType> protectedInputType(*m_inputType);
157 protectedInputType->createShadowSubtree();
158 updateInnerTextElementEditability();
159}
160
161HTMLInputElement::~HTMLInputElement()
162{
163 if (needsSuspensionCallback())
164 document().unregisterForDocumentSuspensionCallbacks(*this);
165
166 // Need to remove form association while this is still an HTMLInputElement
167 // so that virtual functions are called correctly.
168 setForm(nullptr);
169
170 // This is needed for a radio button that was not in a form, and also for
171 // a radio button that was in a form. The call to setForm(nullptr) above
172 // actually adds the button to the document groups in the latter case.
173 // That is inelegant, but harmless since we remove it here.
174 if (isRadioButton())
175 document().formController().radioButtonGroups().removeButton(*this);
176
177#if ENABLE(TOUCH_EVENTS)
178 if (m_hasTouchEventHandler)
179 document().didRemoveEventTargetNode(*this);
180#endif
181}
182
183const AtomicString& HTMLInputElement::name() const
184{
185 return m_name.isNull() ? emptyAtom() : m_name;
186}
187
188Vector<FileChooserFileInfo> HTMLInputElement::filesFromFileInputFormControlState(const FormControlState& state)
189{
190 return FileInputType::filesFromFormControlState(state);
191}
192
193HTMLElement* HTMLInputElement::containerElement() const
194{
195 return m_inputType->containerElement();
196}
197
198RefPtr<TextControlInnerTextElement> HTMLInputElement::innerTextElement() const
199{
200 return m_inputType->innerTextElement();
201}
202
203HTMLElement* HTMLInputElement::innerBlockElement() const
204{
205 return m_inputType->innerBlockElement();
206}
207
208HTMLElement* HTMLInputElement::innerSpinButtonElement() const
209{
210 return m_inputType->innerSpinButtonElement();
211}
212
213HTMLElement* HTMLInputElement::capsLockIndicatorElement() const
214{
215 return m_inputType->capsLockIndicatorElement();
216}
217
218HTMLElement* HTMLInputElement::autoFillButtonElement() const
219{
220 return m_inputType->autoFillButtonElement();
221}
222
223HTMLElement* HTMLInputElement::resultsButtonElement() const
224{
225 return m_inputType->resultsButtonElement();
226}
227
228HTMLElement* HTMLInputElement::cancelButtonElement() const
229{
230 return m_inputType->cancelButtonElement();
231}
232
233HTMLElement* HTMLInputElement::sliderThumbElement() const
234{
235 return m_inputType->sliderThumbElement();
236}
237
238HTMLElement* HTMLInputElement::sliderTrackElement() const
239{
240 return m_inputType->sliderTrackElement();
241}
242
243HTMLElement* HTMLInputElement::placeholderElement() const
244{
245 return m_inputType->placeholderElement();
246}
247
248#if ENABLE(DATALIST_ELEMENT)
249HTMLElement* HTMLInputElement::dataListButtonElement() const
250{
251 return m_inputType->dataListButtonElement();
252}
253#endif
254
255bool HTMLInputElement::shouldAutocomplete() const
256{
257 if (m_autocomplete != Uninitialized)
258 return m_autocomplete == On;
259 return HTMLTextFormControlElement::shouldAutocomplete();
260}
261
262bool HTMLInputElement::isValidValue(const String& value) const
263{
264 if (!m_inputType->canSetStringValue()) {
265 ASSERT_NOT_REACHED();
266 return false;
267 }
268 return !m_inputType->typeMismatchFor(value)
269 && !m_inputType->stepMismatch(value)
270 && !m_inputType->rangeUnderflow(value)
271 && !m_inputType->rangeOverflow(value)
272 && !tooShort(value, IgnoreDirtyFlag)
273 && !tooLong(value, IgnoreDirtyFlag)
274 && !m_inputType->patternMismatch(value)
275 && !m_inputType->valueMissing(value);
276}
277
278bool HTMLInputElement::tooShort() const
279{
280 return willValidate() && tooShort(value(), CheckDirtyFlag);
281}
282
283bool HTMLInputElement::tooLong() const
284{
285 return willValidate() && tooLong(value(), CheckDirtyFlag);
286}
287
288bool HTMLInputElement::typeMismatch() const
289{
290 return willValidate() && m_inputType->typeMismatch();
291}
292
293bool HTMLInputElement::valueMissing() const
294{
295 return willValidate() && m_inputType->valueMissing(value());
296}
297
298bool HTMLInputElement::hasBadInput() const
299{
300 return willValidate() && m_inputType->hasBadInput();
301}
302
303bool HTMLInputElement::patternMismatch() const
304{
305 return willValidate() && m_inputType->patternMismatch(value());
306}
307
308bool HTMLInputElement::tooShort(StringView value, NeedsToCheckDirtyFlag check) const
309{
310 if (!supportsMinLength())
311 return false;
312
313 int min = minLength();
314 if (min <= 0)
315 return false;
316
317 if (check == CheckDirtyFlag) {
318 // Return false for the default value or a value set by a script even if
319 // it is shorter than minLength.
320 if (!hasDirtyValue() || !m_wasModifiedByUser)
321 return false;
322 }
323
324 // The empty string is excluded from tooShort validation.
325 if (value.isEmpty())
326 return false;
327
328 // FIXME: The HTML specification says that the "number of characters" is measured using code-unit length.
329 return numGraphemeClusters(value) < static_cast<unsigned>(min);
330}
331
332bool HTMLInputElement::tooLong(StringView value, NeedsToCheckDirtyFlag check) const
333{
334 if (!supportsMaxLength())
335 return false;
336 unsigned max = effectiveMaxLength();
337 if (check == CheckDirtyFlag) {
338 // Return false for the default value or a value set by a script even if
339 // it is longer than maxLength.
340 if (!hasDirtyValue() || !m_wasModifiedByUser)
341 return false;
342 }
343 // FIXME: The HTML specification says that the "number of characters" is measured using code-unit length.
344 return numGraphemeClusters(value) > max;
345}
346
347bool HTMLInputElement::rangeUnderflow() const
348{
349 return willValidate() && m_inputType->rangeUnderflow(value());
350}
351
352bool HTMLInputElement::rangeOverflow() const
353{
354 return willValidate() && m_inputType->rangeOverflow(value());
355}
356
357String HTMLInputElement::validationMessage() const
358{
359 if (!willValidate())
360 return String();
361
362 if (customError())
363 return customValidationMessage();
364
365 return m_inputType->validationMessage();
366}
367
368double HTMLInputElement::minimum() const
369{
370 return m_inputType->minimum();
371}
372
373double HTMLInputElement::maximum() const
374{
375 return m_inputType->maximum();
376}
377
378bool HTMLInputElement::stepMismatch() const
379{
380 return willValidate() && m_inputType->stepMismatch(value());
381}
382
383bool HTMLInputElement::isValid() const
384{
385 if (!willValidate())
386 return true;
387
388 String value = this->value();
389 bool someError = m_inputType->typeMismatch() || m_inputType->stepMismatch(value) || m_inputType->rangeUnderflow(value) || m_inputType->rangeOverflow(value)
390 || tooShort(value, CheckDirtyFlag) || tooLong(value, CheckDirtyFlag) || m_inputType->patternMismatch(value) || m_inputType->valueMissing(value)
391 || m_inputType->hasBadInput() || customError();
392 return !someError;
393}
394
395bool HTMLInputElement::getAllowedValueStep(Decimal* step) const
396{
397 return m_inputType->getAllowedValueStep(step);
398}
399
400StepRange HTMLInputElement::createStepRange(AnyStepHandling anyStepHandling) const
401{
402 return m_inputType->createStepRange(anyStepHandling);
403}
404
405#if ENABLE(DATALIST_ELEMENT)
406Optional<Decimal> HTMLInputElement::findClosestTickMarkValue(const Decimal& value)
407{
408 return m_inputType->findClosestTickMarkValue(value);
409}
410#endif
411
412ExceptionOr<void> HTMLInputElement::stepUp(int n)
413{
414 return m_inputType->stepUp(n);
415}
416
417ExceptionOr<void> HTMLInputElement::stepDown(int n)
418{
419 return m_inputType->stepUp(-n);
420}
421
422void HTMLInputElement::blur()
423{
424 m_inputType->blur();
425}
426
427void HTMLInputElement::defaultBlur()
428{
429 HTMLTextFormControlElement::blur();
430}
431
432bool HTMLInputElement::hasCustomFocusLogic() const
433{
434 return m_inputType->hasCustomFocusLogic();
435}
436
437bool HTMLInputElement::isKeyboardFocusable(KeyboardEvent* event) const
438{
439 return m_inputType->isKeyboardFocusable(event);
440}
441
442bool HTMLInputElement::isMouseFocusable() const
443{
444 return m_inputType->isMouseFocusable();
445}
446
447bool HTMLInputElement::isTextFormControlFocusable() const
448{
449 return HTMLTextFormControlElement::isFocusable();
450}
451
452bool HTMLInputElement::isTextFormControlKeyboardFocusable(KeyboardEvent* event) const
453{
454 return HTMLTextFormControlElement::isKeyboardFocusable(event);
455}
456
457bool HTMLInputElement::isTextFormControlMouseFocusable() const
458{
459 return HTMLTextFormControlElement::isMouseFocusable();
460}
461
462void HTMLInputElement::updateFocusAppearance(SelectionRestorationMode restorationMode, SelectionRevealMode revealMode)
463{
464 if (isTextField()) {
465 if (restorationMode == SelectionRestorationMode::SetDefault || !hasCachedSelection())
466 setDefaultSelectionAfterFocus(revealMode);
467 else
468 restoreCachedSelection(revealMode);
469 } else
470 HTMLTextFormControlElement::updateFocusAppearance(restorationMode, revealMode);
471}
472
473void HTMLInputElement::setDefaultSelectionAfterFocus(SelectionRevealMode revealMode)
474{
475 ASSERT(isTextField());
476 int start = 0;
477 auto direction = SelectionHasNoDirection;
478 auto* frame = document().frame();
479 if (frame && frame->editor().behavior().shouldMoveSelectionToEndWhenFocusingTextInput()) {
480 start = std::numeric_limits<int>::max();
481 direction = SelectionHasForwardDirection;
482 }
483 setSelectionRange(start, std::numeric_limits<int>::max(), direction, revealMode, Element::defaultFocusTextStateChangeIntent());
484}
485
486void HTMLInputElement::endEditing()
487{
488 if (!isTextField())
489 return;
490
491 if (RefPtr<Frame> frame = document().frame())
492 frame->editor().textFieldDidEndEditing(this);
493}
494
495bool HTMLInputElement::shouldUseInputMethod()
496{
497 return m_inputType->shouldUseInputMethod();
498}
499
500void HTMLInputElement::handleFocusEvent(Node* oldFocusedNode, FocusDirection direction)
501{
502 m_inputType->handleFocusEvent(oldFocusedNode, direction);
503}
504
505void HTMLInputElement::handleBlurEvent()
506{
507 m_inputType->handleBlurEvent();
508}
509
510void HTMLInputElement::setType(const AtomicString& type)
511{
512 setAttributeWithoutSynchronization(typeAttr, type);
513}
514
515void HTMLInputElement::resignStrongPasswordAppearance()
516{
517 if (!hasAutoFillStrongPasswordButton())
518 return;
519 setAutoFilled(false);
520 setShowAutoFillButton(AutoFillButtonType::None);
521 if (auto* page = document().page())
522 page->chrome().client().inputElementDidResignStrongPasswordAppearance(*this);
523}
524
525void HTMLInputElement::updateType()
526{
527 ASSERT(m_inputType);
528 auto newType = InputType::create(*this, attributeWithoutSynchronization(typeAttr));
529 m_hasType = true;
530 if (m_inputType->formControlType() == newType->formControlType())
531 return;
532
533 removeFromRadioButtonGroup();
534 resignStrongPasswordAppearance();
535
536 bool didStoreValue = m_inputType->storesValueSeparateFromAttribute();
537 bool willStoreValue = newType->storesValueSeparateFromAttribute();
538 bool neededSuspensionCallback = needsSuspensionCallback();
539 bool didRespectHeightAndWidth = m_inputType->shouldRespectHeightAndWidthAttributes();
540 bool wasSuccessfulSubmitButtonCandidate = m_inputType->canBeSuccessfulSubmitButton();
541
542 if (didStoreValue && !willStoreValue && hasDirtyValue()) {
543 setAttributeWithoutSynchronization(valueAttr, m_valueIfDirty);
544 m_valueIfDirty = String();
545 }
546
547 m_inputType->destroyShadowSubtree();
548 m_inputType->detachFromElement();
549
550 m_inputType = WTFMove(newType);
551 m_inputType->createShadowSubtree();
552 updateInnerTextElementEditability();
553
554 setNeedsWillValidateCheck();
555
556 if (!didStoreValue && willStoreValue)
557 m_valueIfDirty = sanitizeValue(attributeWithoutSynchronization(valueAttr));
558 else
559 updateValueIfNeeded();
560
561 setFormControlValueMatchesRenderer(false);
562 m_inputType->updateInnerTextValue();
563
564 m_wasModifiedByUser = false;
565
566 if (neededSuspensionCallback)
567 unregisterForSuspensionCallbackIfNeeded();
568 else
569 registerForSuspensionCallbackIfNeeded();
570
571 if (didRespectHeightAndWidth != m_inputType->shouldRespectHeightAndWidthAttributes()) {
572 ASSERT(elementData());
573 // FIXME: We don't have the old attribute values so we pretend that we didn't have the old values.
574 if (const Attribute* height = findAttributeByName(heightAttr))
575 attributeChanged(heightAttr, nullAtom(), height->value());
576 if (const Attribute* width = findAttributeByName(widthAttr))
577 attributeChanged(widthAttr, nullAtom(), width->value());
578 if (const Attribute* align = findAttributeByName(alignAttr))
579 attributeChanged(alignAttr, nullAtom(), align->value());
580 }
581
582 if (form() && wasSuccessfulSubmitButtonCandidate != m_inputType->canBeSuccessfulSubmitButton())
583 form()->resetDefaultButton();
584
585 runPostTypeUpdateTasks();
586}
587
588inline void HTMLInputElement::runPostTypeUpdateTasks()
589{
590 ASSERT(m_inputType);
591#if ENABLE(TOUCH_EVENTS)
592 bool hasTouchEventHandler = m_inputType->hasTouchEventHandler();
593 if (hasTouchEventHandler != m_hasTouchEventHandler) {
594 if (hasTouchEventHandler)
595 document().didAddTouchEventHandler(*this);
596 else
597 document().didRemoveTouchEventHandler(*this);
598 m_hasTouchEventHandler = hasTouchEventHandler;
599 }
600#endif
601
602 if (renderer())
603 invalidateStyleAndRenderersForSubtree();
604
605 if (document().focusedElement() == this)
606 updateFocusAppearance(SelectionRestorationMode::Restore, SelectionRevealMode::Reveal);
607
608 setChangedSinceLastFormControlChangeEvent(false);
609
610 addToRadioButtonGroup();
611
612 updateValidity();
613}
614
615void HTMLInputElement::subtreeHasChanged()
616{
617 m_inputType->subtreeHasChanged();
618 // When typing in an input field, childrenChanged is not called, so we need to force the directionality check.
619 calculateAndAdjustDirectionality();
620}
621
622const AtomicString& HTMLInputElement::formControlType() const
623{
624 return m_inputType->formControlType();
625}
626
627bool HTMLInputElement::shouldSaveAndRestoreFormControlState() const
628{
629 if (!m_inputType->shouldSaveAndRestoreFormControlState())
630 return false;
631 return HTMLTextFormControlElement::shouldSaveAndRestoreFormControlState();
632}
633
634FormControlState HTMLInputElement::saveFormControlState() const
635{
636 return m_inputType->saveFormControlState();
637}
638
639void HTMLInputElement::restoreFormControlState(const FormControlState& state)
640{
641 m_inputType->restoreFormControlState(state);
642 m_stateRestored = true;
643}
644
645bool HTMLInputElement::canStartSelection() const
646{
647 if (!isTextField())
648 return false;
649 return HTMLTextFormControlElement::canStartSelection();
650}
651
652bool HTMLInputElement::canHaveSelection() const
653{
654 return isTextField();
655}
656
657void HTMLInputElement::accessKeyAction(bool sendMouseEvents)
658{
659 Ref<InputType> protectedInputType(*m_inputType);
660 protectedInputType->accessKeyAction(sendMouseEvents);
661}
662
663bool HTMLInputElement::isPresentationAttribute(const QualifiedName& name) const
664{
665 if (name == vspaceAttr || name == hspaceAttr || name == widthAttr || name == heightAttr || (name == borderAttr && isImageButton()))
666 return true;
667 return HTMLTextFormControlElement::isPresentationAttribute(name);
668}
669
670void HTMLInputElement::collectStyleForPresentationAttribute(const QualifiedName& name, const AtomicString& value, MutableStyleProperties& style)
671{
672 if (name == vspaceAttr) {
673 addHTMLLengthToStyle(style, CSSPropertyMarginTop, value);
674 addHTMLLengthToStyle(style, CSSPropertyMarginBottom, value);
675 } else if (name == hspaceAttr) {
676 addHTMLLengthToStyle(style, CSSPropertyMarginLeft, value);
677 addHTMLLengthToStyle(style, CSSPropertyMarginRight, value);
678 } else if (name == alignAttr) {
679 if (m_inputType->shouldRespectAlignAttribute())
680 applyAlignmentAttributeToStyle(value, style);
681 } else if (name == widthAttr) {
682 if (m_inputType->shouldRespectHeightAndWidthAttributes())
683 addHTMLLengthToStyle(style, CSSPropertyWidth, value);
684 } else if (name == heightAttr) {
685 if (m_inputType->shouldRespectHeightAndWidthAttributes())
686 addHTMLLengthToStyle(style, CSSPropertyHeight, value);
687 } else if (name == borderAttr && isImageButton())
688 applyBorderAttributeToStyle(value, style);
689 else
690 HTMLTextFormControlElement::collectStyleForPresentationAttribute(name, value, style);
691}
692
693inline void HTMLInputElement::initializeInputType()
694{
695 ASSERT(m_parsingInProgress);
696 ASSERT(!m_inputType);
697
698 const AtomicString& type = attributeWithoutSynchronization(typeAttr);
699 if (type.isNull()) {
700 m_inputType = InputType::createText(*this);
701 ensureUserAgentShadowRoot();
702 setNeedsWillValidateCheck();
703 return;
704 }
705
706 m_hasType = true;
707 m_inputType = InputType::create(*this, type);
708 ensureUserAgentShadowRoot();
709 setNeedsWillValidateCheck();
710 registerForSuspensionCallbackIfNeeded();
711 runPostTypeUpdateTasks();
712}
713
714void HTMLInputElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
715{
716 ASSERT(m_inputType);
717 Ref<InputType> protectedInputType(*m_inputType);
718
719 if (name == nameAttr) {
720 removeFromRadioButtonGroup();
721 m_name = value;
722 addToRadioButtonGroup();
723 HTMLTextFormControlElement::parseAttribute(name, value);
724 } else if (name == autocompleteAttr) {
725 if (equalLettersIgnoringASCIICase(value, "off")) {
726 m_autocomplete = Off;
727 registerForSuspensionCallbackIfNeeded();
728 } else {
729 bool needsToUnregister = m_autocomplete == Off;
730
731 if (value.isEmpty())
732 m_autocomplete = Uninitialized;
733 else
734 m_autocomplete = On;
735
736 if (needsToUnregister)
737 unregisterForSuspensionCallbackIfNeeded();
738 }
739 } else if (name == typeAttr)
740 updateType();
741 else if (name == valueAttr) {
742 // Changes to the value attribute may change whether or not this element has a default value.
743 // If this field is autocomplete=off that might affect the return value of needsSuspensionCallback.
744 if (m_autocomplete == Off) {
745 unregisterForSuspensionCallbackIfNeeded();
746 registerForSuspensionCallbackIfNeeded();
747 }
748 // We only need to setChanged if the form is looking at the default value right now.
749 if (!hasDirtyValue()) {
750 updatePlaceholderVisibility();
751 invalidateStyleForSubtree();
752 }
753 setFormControlValueMatchesRenderer(false);
754 updateValidity();
755 m_valueAttributeWasUpdatedAfterParsing = !m_parsingInProgress;
756 } else if (name == checkedAttr) {
757 if (m_inputType->isCheckable())
758 invalidateStyleForSubtree();
759
760 // Another radio button in the same group might be checked by state
761 // restore. We shouldn't call setChecked() even if this has the checked
762 // attribute. So, delay the setChecked() call until
763 // finishParsingChildren() is called if parsing is in progress.
764 if ((!m_parsingInProgress || !document().formController().hasFormStateToRestore()) && !m_dirtyCheckednessFlag) {
765 setChecked(!value.isNull());
766 // setChecked() above sets the dirty checkedness flag so we need to reset it.
767 m_dirtyCheckednessFlag = false;
768 }
769 } else if (name == maxlengthAttr)
770 maxLengthAttributeChanged(value);
771 else if (name == minlengthAttr)
772 minLengthAttributeChanged(value);
773 else if (name == sizeAttr) {
774 unsigned oldSize = m_size;
775 m_size = limitToOnlyHTMLNonNegativeNumbersGreaterThanZero(value, defaultSize);
776 if (m_size != oldSize && renderer())
777 renderer()->setNeedsLayoutAndPrefWidthsRecalc();
778 } else if (name == resultsAttr)
779 m_maxResults = !value.isNull() ? std::min(value.toInt(), maxSavedResults) : -1;
780 else if (name == autosaveAttr || name == incrementalAttr)
781 invalidateStyleForSubtree();
782 else if (name == maxAttr || name == minAttr || name == multipleAttr || name == patternAttr || name == precisionAttr || name == stepAttr)
783 updateValidity();
784#if ENABLE(DATALIST_ELEMENT)
785 else if (name == listAttr) {
786 m_hasNonEmptyList = !value.isEmpty();
787 if (m_hasNonEmptyList) {
788 resetListAttributeTargetObserver();
789 listAttributeTargetChanged();
790 }
791 }
792#endif
793 else
794 HTMLTextFormControlElement::parseAttribute(name, value);
795
796 m_inputType->attributeChanged(name);
797}
798
799void HTMLInputElement::disabledStateChanged()
800{
801 HTMLTextFormControlElement::disabledStateChanged();
802 m_inputType->disabledStateChanged();
803}
804
805void HTMLInputElement::readOnlyStateChanged()
806{
807 HTMLTextFormControlElement::readOnlyStateChanged();
808 m_inputType->readOnlyStateChanged();
809}
810
811void HTMLInputElement::parserDidSetAttributes()
812{
813 ASSERT(m_parsingInProgress);
814 initializeInputType();
815}
816
817void HTMLInputElement::finishParsingChildren()
818{
819 m_parsingInProgress = false;
820 ASSERT(m_inputType);
821 HTMLTextFormControlElement::finishParsingChildren();
822 if (!m_stateRestored) {
823 bool checked = hasAttributeWithoutSynchronization(checkedAttr);
824 if (checked)
825 setChecked(checked);
826 m_dirtyCheckednessFlag = false;
827 }
828}
829
830bool HTMLInputElement::rendererIsNeeded(const RenderStyle& style)
831{
832 return m_inputType->rendererIsNeeded() && HTMLTextFormControlElement::rendererIsNeeded(style);
833}
834
835RenderPtr<RenderElement> HTMLInputElement::createElementRenderer(RenderStyle&& style, const RenderTreePosition&)
836{
837 return m_inputType->createInputRenderer(WTFMove(style));
838}
839
840void HTMLInputElement::willAttachRenderers()
841{
842 if (!m_hasType)
843 updateType();
844}
845
846void HTMLInputElement::didAttachRenderers()
847{
848 HTMLTextFormControlElement::didAttachRenderers();
849
850 m_inputType->attach();
851
852 if (document().focusedElement() == this) {
853 document().view()->queuePostLayoutCallback([protectedThis = makeRef(*this)] {
854 protectedThis->updateFocusAppearance(SelectionRestorationMode::Restore, SelectionRevealMode::Reveal);
855 });
856 }
857}
858
859void HTMLInputElement::didDetachRenderers()
860{
861 setFormControlValueMatchesRenderer(false);
862 m_inputType->detach();
863}
864
865String HTMLInputElement::altText() const
866{
867 // http://www.w3.org/TR/1998/REC-html40-19980424/appendix/notes.html#altgen
868 // also heavily discussed by Hixie on bugzilla
869 // note this is intentionally different to HTMLImageElement::altText()
870 String alt = attributeWithoutSynchronization(altAttr);
871 // fall back to title attribute
872 if (alt.isNull())
873 alt = attributeWithoutSynchronization(titleAttr);
874 if (alt.isNull())
875 alt = attributeWithoutSynchronization(valueAttr);
876 if (alt.isEmpty())
877 alt = inputElementAltText();
878 return alt;
879}
880
881bool HTMLInputElement::isSuccessfulSubmitButton() const
882{
883 // HTML spec says that buttons must have names to be considered successful.
884 // However, other browsers do not impose this constraint. So we do not.
885 return !isDisabledFormControl() && m_inputType->canBeSuccessfulSubmitButton();
886}
887
888bool HTMLInputElement::matchesDefaultPseudoClass() const
889{
890 ASSERT(m_inputType);
891 if (m_inputType->canBeSuccessfulSubmitButton())
892 return !isDisabledFormControl() && form() && form()->defaultButton() == this;
893 return m_inputType->isCheckable() && hasAttributeWithoutSynchronization(checkedAttr);
894}
895
896bool HTMLInputElement::isActivatedSubmit() const
897{
898 return m_isActivatedSubmit;
899}
900
901void HTMLInputElement::setActivatedSubmit(bool flag)
902{
903 m_isActivatedSubmit = flag;
904}
905
906bool HTMLInputElement::appendFormData(DOMFormData& formData, bool multipart)
907{
908 Ref<InputType> protectedInputType(*m_inputType);
909 return m_inputType->isFormDataAppendable() && m_inputType->appendFormData(formData, multipart);
910}
911
912void HTMLInputElement::reset()
913{
914 if (m_inputType->storesValueSeparateFromAttribute())
915 setValue(String());
916
917 setAutoFilled(false);
918 setShowAutoFillButton(AutoFillButtonType::None);
919 setChecked(hasAttributeWithoutSynchronization(checkedAttr));
920 m_dirtyCheckednessFlag = false;
921}
922
923bool HTMLInputElement::isTextField() const
924{
925 return m_inputType->isTextField();
926}
927
928bool HTMLInputElement::isTextType() const
929{
930 return m_inputType->isTextType();
931}
932
933void HTMLInputElement::setChecked(bool nowChecked)
934{
935 if (checked() == nowChecked)
936 return;
937
938 m_dirtyCheckednessFlag = true;
939 m_isChecked = nowChecked;
940 invalidateStyleForSubtree();
941
942 if (RadioButtonGroups* buttons = radioButtonGroups())
943 buttons->updateCheckedState(*this);
944 if (renderer() && renderer()->style().hasAppearance())
945 renderer()->theme().stateChanged(*renderer(), ControlStates::CheckedState);
946 updateValidity();
947
948 // Ideally we'd do this from the render tree (matching
949 // RenderTextView), but it's not possible to do it at the moment
950 // because of the way the code is structured.
951 if (renderer()) {
952 if (AXObjectCache* cache = renderer()->document().existingAXObjectCache())
953 cache->checkedStateChanged(this);
954 }
955
956 invalidateStyleForSubtree();
957}
958
959void HTMLInputElement::setIndeterminate(bool newValue)
960{
961 if (indeterminate() == newValue)
962 return;
963
964 m_isIndeterminate = newValue;
965
966 invalidateStyleForSubtree();
967
968 if (renderer() && renderer()->style().hasAppearance())
969 renderer()->theme().stateChanged(*renderer(), ControlStates::CheckedState);
970}
971
972unsigned HTMLInputElement::size() const
973{
974 return m_size;
975}
976
977bool HTMLInputElement::sizeShouldIncludeDecoration(int& preferredSize) const
978{
979 return m_inputType->sizeShouldIncludeDecoration(defaultSize, preferredSize);
980}
981
982float HTMLInputElement::decorationWidth() const
983{
984 return m_inputType->decorationWidth();
985}
986
987void HTMLInputElement::copyNonAttributePropertiesFromElement(const Element& source)
988{
989 auto& sourceElement = downcast<HTMLInputElement>(source);
990
991 m_valueIfDirty = sourceElement.m_valueIfDirty;
992 m_wasModifiedByUser = false;
993 setChecked(sourceElement.m_isChecked);
994 m_dirtyCheckednessFlag = sourceElement.m_dirtyCheckednessFlag;
995 m_isIndeterminate = sourceElement.m_isIndeterminate;
996
997 HTMLTextFormControlElement::copyNonAttributePropertiesFromElement(source);
998
999 updateValidity();
1000 setFormControlValueMatchesRenderer(false);
1001 m_inputType->updateInnerTextValue();
1002}
1003
1004String HTMLInputElement::value() const
1005{
1006 String value;
1007 if (m_inputType->getTypeSpecificValue(value))
1008 return value;
1009
1010 value = m_valueIfDirty;
1011 if (!value.isNull())
1012 return value;
1013
1014 auto& valueString = attributeWithoutSynchronization(valueAttr);
1015 value = sanitizeValue(valueString);
1016 if (!value.isNull())
1017 return value;
1018
1019 return m_inputType->fallbackValue();
1020}
1021
1022String HTMLInputElement::valueWithDefault() const
1023{
1024 String value = this->value();
1025 if (!value.isNull())
1026 return value;
1027
1028 return m_inputType->defaultValue();
1029}
1030
1031void HTMLInputElement::setValueForUser(const String& value)
1032{
1033 // Call setValue and make it send a change event.
1034 setValue(value, DispatchChangeEvent);
1035}
1036
1037ExceptionOr<void> HTMLInputElement::setValue(const String& value, TextFieldEventBehavior eventBehavior)
1038{
1039 if (isFileUpload() && !value.isEmpty())
1040 return Exception { InvalidStateError };
1041
1042 if (!m_inputType->canSetValue(value))
1043 return { };
1044
1045 Ref<HTMLInputElement> protectedThis(*this);
1046 EventQueueScope scope;
1047 String sanitizedValue = sanitizeValue(value);
1048 bool valueChanged = sanitizedValue != this->value();
1049
1050 setLastChangeWasNotUserEdit();
1051 setFormControlValueMatchesRenderer(false);
1052 m_inputType->setValue(sanitizedValue, valueChanged, eventBehavior);
1053
1054 bool wasModifiedProgrammatically = eventBehavior == DispatchNoEvent;
1055 if (wasModifiedProgrammatically)
1056 resignStrongPasswordAppearance();
1057 return { };
1058}
1059
1060void HTMLInputElement::setValueInternal(const String& sanitizedValue, TextFieldEventBehavior eventBehavior)
1061{
1062 m_valueIfDirty = sanitizedValue;
1063 m_wasModifiedByUser = eventBehavior != DispatchNoEvent;
1064 updateValidity();
1065}
1066
1067double HTMLInputElement::valueAsDate() const
1068{
1069 return m_inputType->valueAsDate();
1070}
1071
1072ExceptionOr<void> HTMLInputElement::setValueAsDate(double value)
1073{
1074 return m_inputType->setValueAsDate(value);
1075}
1076
1077double HTMLInputElement::valueAsNumber() const
1078{
1079 return m_inputType->valueAsDouble();
1080}
1081
1082ExceptionOr<void> HTMLInputElement::setValueAsNumber(double newValue, TextFieldEventBehavior eventBehavior)
1083{
1084 if (!std::isfinite(newValue))
1085 return Exception { NotSupportedError };
1086 return m_inputType->setValueAsDouble(newValue, eventBehavior);
1087}
1088
1089void HTMLInputElement::setValueFromRenderer(const String& value)
1090{
1091 // File upload controls will never use this.
1092 ASSERT(!isFileUpload());
1093
1094 // Renderer and our event handler are responsible for sanitizing values.
1095 // Input types that support the selection API do *not* sanitize their
1096 // user input in order to retain parity between what's in the model and
1097 // what's on the screen.
1098 ASSERT(m_inputType->supportsSelectionAPI() || value == sanitizeValue(value) || sanitizeValue(value).isEmpty());
1099
1100 // Workaround for bug where trailing \n is included in the result of textContent.
1101 // The assert macro above may also be simplified by removing the expression
1102 // that calls isEmpty.
1103 // http://bugs.webkit.org/show_bug.cgi?id=9661
1104 m_valueIfDirty = value == "\n" ? emptyString() : value;
1105
1106 setFormControlValueMatchesRenderer(true);
1107 m_wasModifiedByUser = true;
1108
1109 // Input event is fired by the Node::defaultEventHandler for editable controls.
1110 if (!isTextField())
1111 dispatchInputEvent();
1112
1113 updateValidity();
1114
1115 // Clear auto fill flag (and yellow background) on user edit.
1116 setAutoFilled(false);
1117}
1118
1119void HTMLInputElement::willDispatchEvent(Event& event, InputElementClickState& state)
1120{
1121 if (event.type() == eventNames().textInputEvent && m_inputType->shouldSubmitImplicitly(event))
1122 event.stopPropagation();
1123 if (event.type() == eventNames().clickEvent && is<MouseEvent>(event) && downcast<MouseEvent>(event).button() == LeftButton) {
1124 m_inputType->willDispatchClick(state);
1125 state.stateful = true;
1126 }
1127}
1128
1129void HTMLInputElement::didDispatchClickEvent(Event& event, const InputElementClickState& state)
1130{
1131 m_inputType->didDispatchClick(event, state);
1132}
1133
1134void HTMLInputElement::didBlur()
1135{
1136 m_inputType->elementDidBlur();
1137}
1138
1139void HTMLInputElement::defaultEventHandler(Event& event)
1140{
1141 if (is<MouseEvent>(event) && event.type() == eventNames().clickEvent && downcast<MouseEvent>(event).button() == LeftButton) {
1142 m_inputType->handleClickEvent(downcast<MouseEvent>(event));
1143 if (event.defaultHandled())
1144 return;
1145 }
1146
1147#if ENABLE(TOUCH_EVENTS)
1148 if (is<TouchEvent>(event)) {
1149 m_inputType->handleTouchEvent(downcast<TouchEvent>(event));
1150 if (event.defaultHandled())
1151 return;
1152 }
1153#endif
1154
1155 if (is<KeyboardEvent>(event) && event.type() == eventNames().keydownEvent) {
1156 auto shouldCallBaseEventHandler = m_inputType->handleKeydownEvent(downcast<KeyboardEvent>(event));
1157 if (event.defaultHandled() || shouldCallBaseEventHandler == InputType::ShouldCallBaseEventHandler::No)
1158 return;
1159 }
1160
1161 // Call the base event handler before any of our own event handling for almost all events in text fields.
1162 // Makes editing keyboard handling take precedence over the keydown and keypress handling in this function.
1163 bool callBaseClassEarly = isTextField() && (event.type() == eventNames().keydownEvent || event.type() == eventNames().keypressEvent);
1164 if (callBaseClassEarly) {
1165 HTMLTextFormControlElement::defaultEventHandler(event);
1166 if (event.defaultHandled())
1167 return;
1168 }
1169
1170 // DOMActivate events cause the input to be "activated" - in the case of image and submit inputs, this means
1171 // actually submitting the form. For reset inputs, the form is reset. These events are sent when the user clicks
1172 // on the element, or presses enter while it is the active element. JavaScript code wishing to activate the element
1173 // must dispatch a DOMActivate event - a click event will not do the job.
1174 if (event.type() == eventNames().DOMActivateEvent) {
1175 m_inputType->handleDOMActivateEvent(event);
1176 if (event.defaultHandled())
1177 return;
1178 }
1179
1180 // Use key press event here since sending simulated mouse events
1181 // on key down blocks the proper sending of the key press event.
1182 if (is<KeyboardEvent>(event)) {
1183 KeyboardEvent& keyboardEvent = downcast<KeyboardEvent>(event);
1184 if (keyboardEvent.type() == eventNames().keypressEvent) {
1185 m_inputType->handleKeypressEvent(keyboardEvent);
1186 if (keyboardEvent.defaultHandled())
1187 return;
1188 } else if (keyboardEvent.type() == eventNames().keyupEvent) {
1189 m_inputType->handleKeyupEvent(keyboardEvent);
1190 if (keyboardEvent.defaultHandled())
1191 return;
1192 }
1193 }
1194
1195 if (m_inputType->shouldSubmitImplicitly(event)) {
1196 if (isSearchField()) {
1197 addSearchResult();
1198 onSearch();
1199 }
1200 // Form submission finishes editing, just as loss of focus does.
1201 // If there was a change, send the event now.
1202 if (wasChangedSinceLastFormControlChangeEvent())
1203 dispatchFormControlChangeEvent();
1204
1205 // Form may never have been present, or may have been destroyed by code responding to the change event.
1206 if (auto formElement = makeRefPtr(form()))
1207 formElement->submitImplicitly(event, canTriggerImplicitSubmission());
1208
1209 event.setDefaultHandled();
1210 return;
1211 }
1212
1213 if (is<BeforeTextInsertedEvent>(event))
1214 m_inputType->handleBeforeTextInsertedEvent(downcast<BeforeTextInsertedEvent>(event));
1215
1216 if (is<MouseEvent>(event) && event.type() == eventNames().mousedownEvent) {
1217 m_inputType->handleMouseDownEvent(downcast<MouseEvent>(event));
1218 if (event.defaultHandled())
1219 return;
1220 }
1221
1222 m_inputType->forwardEvent(event);
1223
1224 if (!callBaseClassEarly && !event.defaultHandled())
1225 HTMLTextFormControlElement::defaultEventHandler(event);
1226}
1227
1228bool HTMLInputElement::willRespondToMouseClickEvents()
1229{
1230 if (!isDisabledFormControl())
1231 return true;
1232
1233 return HTMLTextFormControlElement::willRespondToMouseClickEvents();
1234}
1235
1236bool HTMLInputElement::isURLAttribute(const Attribute& attribute) const
1237{
1238 return attribute.name() == srcAttr || attribute.name() == formactionAttr || HTMLTextFormControlElement::isURLAttribute(attribute);
1239}
1240
1241String HTMLInputElement::defaultValue() const
1242{
1243 return attributeWithoutSynchronization(valueAttr);
1244}
1245
1246void HTMLInputElement::setDefaultValue(const String &value)
1247{
1248 setAttributeWithoutSynchronization(valueAttr, value);
1249}
1250
1251static inline bool isRFC2616TokenCharacter(UChar ch)
1252{
1253 return isASCII(ch) && ch > ' ' && ch != '"' && ch != '(' && ch != ')' && ch != ',' && ch != '/' && (ch < ':' || ch > '@') && (ch < '[' || ch > ']') && ch != '{' && ch != '}' && ch != 0x7f;
1254}
1255
1256static bool isValidMIMEType(const String& type)
1257{
1258 size_t slashPosition = type.find('/');
1259 if (slashPosition == notFound || !slashPosition || slashPosition == type.length() - 1)
1260 return false;
1261 for (size_t i = 0; i < type.length(); ++i) {
1262 if (!isRFC2616TokenCharacter(type[i]) && i != slashPosition)
1263 return false;
1264 }
1265 return true;
1266}
1267
1268static bool isValidFileExtension(const String& type)
1269{
1270 if (type.length() < 2)
1271 return false;
1272 return type[0] == '.';
1273}
1274
1275static Vector<String> parseAcceptAttribute(const String& acceptString, bool (*predicate)(const String&))
1276{
1277 Vector<String> types;
1278 if (acceptString.isEmpty())
1279 return types;
1280
1281 for (auto& splitType : acceptString.split(',')) {
1282 String trimmedType = stripLeadingAndTrailingHTMLSpaces(splitType);
1283 if (trimmedType.isEmpty())
1284 continue;
1285 if (!predicate(trimmedType))
1286 continue;
1287 types.append(trimmedType.convertToASCIILowercase());
1288 }
1289
1290 return types;
1291}
1292
1293Vector<String> HTMLInputElement::acceptMIMETypes()
1294{
1295 return parseAcceptAttribute(attributeWithoutSynchronization(acceptAttr), isValidMIMEType);
1296}
1297
1298Vector<String> HTMLInputElement::acceptFileExtensions()
1299{
1300 return parseAcceptAttribute(attributeWithoutSynchronization(acceptAttr), isValidFileExtension);
1301}
1302
1303String HTMLInputElement::accept() const
1304{
1305 return attributeWithoutSynchronization(acceptAttr);
1306}
1307
1308String HTMLInputElement::alt() const
1309{
1310 return attributeWithoutSynchronization(altAttr);
1311}
1312
1313unsigned HTMLInputElement::effectiveMaxLength() const
1314{
1315 // The number -1 represents no maximum at all; conveniently it becomes a super-large value when converted to unsigned.
1316 return std::min<unsigned>(maxLength(), maxEffectiveLength);
1317}
1318
1319bool HTMLInputElement::multiple() const
1320{
1321 return hasAttributeWithoutSynchronization(multipleAttr);
1322}
1323
1324ExceptionOr<void> HTMLInputElement::setSize(unsigned size)
1325{
1326 if (!size)
1327 return Exception { IndexSizeError };
1328 setUnsignedIntegralAttribute(sizeAttr, limitToOnlyHTMLNonNegativeNumbersGreaterThanZero(size, defaultSize));
1329 return { };
1330}
1331
1332URL HTMLInputElement::src() const
1333{
1334 return document().completeURL(attributeWithoutSynchronization(srcAttr));
1335}
1336
1337void HTMLInputElement::setAutoFilled(bool autoFilled)
1338{
1339 if (autoFilled == m_isAutoFilled)
1340 return;
1341
1342 m_isAutoFilled = autoFilled;
1343 invalidateStyleForSubtree();
1344}
1345
1346void HTMLInputElement::setShowAutoFillButton(AutoFillButtonType autoFillButtonType)
1347{
1348 if (static_cast<uint8_t>(autoFillButtonType) == m_autoFillButtonType)
1349 return;
1350
1351 m_lastAutoFillButtonType = m_autoFillButtonType;
1352 m_autoFillButtonType = static_cast<uint8_t>(autoFillButtonType);
1353 m_inputType->updateAutoFillButton();
1354 updateInnerTextElementEditability();
1355 invalidateStyleForSubtree();
1356}
1357
1358FileList* HTMLInputElement::files()
1359{
1360 return m_inputType->files();
1361}
1362
1363void HTMLInputElement::setFiles(RefPtr<FileList>&& files)
1364{
1365 m_inputType->setFiles(WTFMove(files));
1366}
1367
1368#if ENABLE(DRAG_SUPPORT)
1369bool HTMLInputElement::receiveDroppedFiles(const DragData& dragData)
1370{
1371 return m_inputType->receiveDroppedFiles(dragData);
1372}
1373#endif
1374
1375Icon* HTMLInputElement::icon() const
1376{
1377 return m_inputType->icon();
1378}
1379
1380String HTMLInputElement::displayString() const
1381{
1382 return m_inputType->displayString();
1383}
1384
1385bool HTMLInputElement::canReceiveDroppedFiles() const
1386{
1387 return m_canReceiveDroppedFiles;
1388}
1389
1390void HTMLInputElement::setCanReceiveDroppedFiles(bool canReceiveDroppedFiles)
1391{
1392 if (m_canReceiveDroppedFiles == canReceiveDroppedFiles)
1393 return;
1394 m_canReceiveDroppedFiles = canReceiveDroppedFiles;
1395 if (renderer())
1396 renderer()->updateFromElement();
1397}
1398
1399String HTMLInputElement::visibleValue() const
1400{
1401 return m_inputType->visibleValue();
1402}
1403
1404String HTMLInputElement::sanitizeValue(const String& proposedValue) const
1405{
1406 if (proposedValue.isNull())
1407 return proposedValue;
1408 return m_inputType->sanitizeValue(proposedValue);
1409}
1410
1411String HTMLInputElement::localizeValue(const String& proposedValue) const
1412{
1413 if (proposedValue.isNull())
1414 return proposedValue;
1415 return m_inputType->localizeValue(proposedValue);
1416}
1417
1418bool HTMLInputElement::isInRange() const
1419{
1420 return willValidate() && m_inputType->isInRange(value());
1421}
1422
1423bool HTMLInputElement::isOutOfRange() const
1424{
1425 return willValidate() && m_inputType->isOutOfRange(value());
1426}
1427
1428bool HTMLInputElement::needsSuspensionCallback()
1429{
1430 if (m_inputType->shouldResetOnDocumentActivation())
1431 return true;
1432
1433 // Sensitive input elements are marked with autocomplete=off, and we want to wipe them out
1434 // when going back; returning true here arranges for us to call reset at the time
1435 // the page is restored. Non-empty textual default values indicate that the field
1436 // is not really sensitive -- there's no default value for an account number --
1437 // and we would see unexpected results if we reset to something other than blank.
1438 bool isSensitive = m_autocomplete == Off && !(m_inputType->isTextType() && !defaultValue().isEmpty());
1439
1440 return isSensitive;
1441}
1442
1443void HTMLInputElement::registerForSuspensionCallbackIfNeeded()
1444{
1445 if (needsSuspensionCallback())
1446 document().registerForDocumentSuspensionCallbacks(*this);
1447}
1448
1449void HTMLInputElement::unregisterForSuspensionCallbackIfNeeded()
1450{
1451 if (!needsSuspensionCallback())
1452 document().unregisterForDocumentSuspensionCallbacks(*this);
1453}
1454
1455bool HTMLInputElement::isRequiredFormControl() const
1456{
1457 return m_inputType->supportsRequired() && isRequired();
1458}
1459
1460bool HTMLInputElement::matchesReadWritePseudoClass() const
1461{
1462 return m_inputType->supportsReadOnly() && !isDisabledOrReadOnly();
1463}
1464
1465void HTMLInputElement::addSearchResult()
1466{
1467 m_inputType->addSearchResult();
1468}
1469
1470void HTMLInputElement::onSearch()
1471{
1472 // The type of the input element could have changed during event handling. If we are no longer
1473 // a search field, don't try to do search things.
1474 if (!isSearchField())
1475 return;
1476
1477 if (m_inputType)
1478 downcast<SearchInputType>(*m_inputType.get()).stopSearchEventTimer();
1479 dispatchEvent(Event::create(eventNames().searchEvent, Event::CanBubble::Yes, Event::IsCancelable::No));
1480}
1481
1482void HTMLInputElement::resumeFromDocumentSuspension()
1483{
1484 ASSERT(needsSuspensionCallback());
1485
1486#if ENABLE(INPUT_TYPE_COLOR)
1487 // <input type=color> uses prepareForDocumentSuspension to detach the color picker UI,
1488 // so it should not be reset when being loaded from page cache.
1489 if (isColorControl())
1490 return;
1491#endif // ENABLE(INPUT_TYPE_COLOR)
1492 reset();
1493}
1494
1495#if ENABLE(INPUT_TYPE_COLOR)
1496void HTMLInputElement::prepareForDocumentSuspension()
1497{
1498 if (!isColorControl())
1499 return;
1500 m_inputType->detach();
1501}
1502#endif // ENABLE(INPUT_TYPE_COLOR)
1503
1504
1505void HTMLInputElement::willChangeForm()
1506{
1507 removeFromRadioButtonGroup();
1508 HTMLTextFormControlElement::willChangeForm();
1509}
1510
1511void HTMLInputElement::didChangeForm()
1512{
1513 HTMLTextFormControlElement::didChangeForm();
1514 addToRadioButtonGroup();
1515}
1516
1517Node::InsertedIntoAncestorResult HTMLInputElement::insertedIntoAncestor(InsertionType insertionType, ContainerNode& parentOfInsertedTree)
1518{
1519 HTMLTextFormControlElement::insertedIntoAncestor(insertionType, parentOfInsertedTree);
1520#if ENABLE(DATALIST_ELEMENT)
1521 resetListAttributeTargetObserver();
1522#endif
1523 return InsertedIntoAncestorResult::NeedsPostInsertionCallback;
1524}
1525
1526void HTMLInputElement::didFinishInsertingNode()
1527{
1528 HTMLTextFormControlElement::didFinishInsertingNode();
1529 if (isConnected() && !form())
1530 addToRadioButtonGroup();
1531}
1532
1533void HTMLInputElement::removedFromAncestor(RemovalType removalType, ContainerNode& oldParentOfRemovedTree)
1534{
1535 if (removalType.disconnectedFromDocument && !form())
1536 removeFromRadioButtonGroup();
1537 HTMLTextFormControlElement::removedFromAncestor(removalType, oldParentOfRemovedTree);
1538 ASSERT(!isConnected());
1539#if ENABLE(DATALIST_ELEMENT)
1540 resetListAttributeTargetObserver();
1541#endif
1542}
1543
1544void HTMLInputElement::didMoveToNewDocument(Document& oldDocument, Document& newDocument)
1545{
1546 if (imageLoader())
1547 imageLoader()->elementDidMoveToNewDocument();
1548
1549 // Always unregister for cache callbacks when leaving a document, even if we would otherwise like to be registered
1550 if (needsSuspensionCallback()) {
1551 oldDocument.unregisterForDocumentSuspensionCallbacks(*this);
1552 newDocument.registerForDocumentSuspensionCallbacks(*this);
1553 }
1554
1555 // We call this even for radio buttons in forms; it's harmless because the
1556 // removeButton function is written to be safe for buttons not in any group.
1557 if (isRadioButton())
1558 oldDocument.formController().radioButtonGroups().removeButton(*this);
1559
1560#if ENABLE(TOUCH_EVENTS)
1561 if (m_hasTouchEventHandler) {
1562 oldDocument.didRemoveEventTargetNode(*this);
1563 newDocument.didAddTouchEventHandler(*this);
1564 }
1565#endif
1566
1567 HTMLTextFormControlElement::didMoveToNewDocument(oldDocument, newDocument);
1568}
1569
1570void HTMLInputElement::addSubresourceAttributeURLs(ListHashSet<URL>& urls) const
1571{
1572 HTMLTextFormControlElement::addSubresourceAttributeURLs(urls);
1573
1574 addSubresourceURL(urls, src());
1575}
1576
1577bool HTMLInputElement::computeWillValidate() const
1578{
1579 return m_inputType->supportsValidation() && HTMLTextFormControlElement::computeWillValidate();
1580}
1581
1582void HTMLInputElement::requiredStateChanged()
1583{
1584 HTMLTextFormControlElement::requiredStateChanged();
1585 if (auto* buttons = radioButtonGroups())
1586 buttons->requiredStateChanged(*this);
1587 m_inputType->requiredStateChanged();
1588}
1589
1590Color HTMLInputElement::valueAsColor() const
1591{
1592 return m_inputType->valueAsColor();
1593}
1594
1595void HTMLInputElement::selectColor(StringView color)
1596{
1597 m_inputType->selectColor(color);
1598}
1599
1600Vector<Color> HTMLInputElement::suggestedColors() const
1601{
1602 return m_inputType->suggestedColors();
1603}
1604
1605#if ENABLE(DATALIST_ELEMENT)
1606
1607RefPtr<HTMLElement> HTMLInputElement::list() const
1608{
1609 return dataList();
1610}
1611
1612RefPtr<HTMLDataListElement> HTMLInputElement::dataList() const
1613{
1614 if (!m_hasNonEmptyList)
1615 return nullptr;
1616
1617 if (!m_inputType->shouldRespectListAttribute())
1618 return nullptr;
1619
1620 RefPtr<Element> element = treeScope().getElementById(attributeWithoutSynchronization(listAttr));
1621 if (!is<HTMLDataListElement>(element))
1622 return nullptr;
1623
1624 return downcast<HTMLDataListElement>(element.get());
1625}
1626
1627void HTMLInputElement::resetListAttributeTargetObserver()
1628{
1629 if (isConnected())
1630 m_listAttributeTargetObserver = std::make_unique<ListAttributeTargetObserver>(attributeWithoutSynchronization(listAttr), this);
1631 else
1632 m_listAttributeTargetObserver = nullptr;
1633}
1634
1635void HTMLInputElement::listAttributeTargetChanged()
1636{
1637 m_inputType->listAttributeTargetChanged();
1638}
1639
1640#endif // ENABLE(DATALIST_ELEMENT)
1641
1642bool HTMLInputElement::isPresentingAttachedView() const
1643{
1644 return m_inputType->isPresentingAttachedView();
1645}
1646
1647bool HTMLInputElement::isSteppable() const
1648{
1649 return m_inputType->isSteppable();
1650}
1651
1652#if PLATFORM(IOS_FAMILY)
1653DateComponents::Type HTMLInputElement::dateType() const
1654{
1655 return m_inputType->dateType();
1656}
1657#endif
1658
1659bool HTMLInputElement::isTextButton() const
1660{
1661 return m_inputType->isTextButton();
1662}
1663
1664bool HTMLInputElement::isRadioButton() const
1665{
1666 return m_inputType->isRadioButton();
1667}
1668
1669bool HTMLInputElement::isSearchField() const
1670{
1671 return m_inputType->isSearchField();
1672}
1673
1674bool HTMLInputElement::isInputTypeHidden() const
1675{
1676 return m_inputType->isHiddenType();
1677}
1678
1679bool HTMLInputElement::isPasswordField() const
1680{
1681 return m_inputType->isPasswordField();
1682}
1683
1684bool HTMLInputElement::isCheckbox() const
1685{
1686 return m_inputType->isCheckbox();
1687}
1688
1689bool HTMLInputElement::isRangeControl() const
1690{
1691 return m_inputType->isRangeControl();
1692}
1693
1694#if ENABLE(INPUT_TYPE_COLOR)
1695bool HTMLInputElement::isColorControl() const
1696{
1697 return m_inputType->isColorControl();
1698}
1699#endif
1700
1701bool HTMLInputElement::isText() const
1702{
1703 return m_inputType->isTextType();
1704}
1705
1706bool HTMLInputElement::isEmailField() const
1707{
1708 return m_inputType->isEmailField();
1709}
1710
1711bool HTMLInputElement::isFileUpload() const
1712{
1713 return m_inputType->isFileUpload();
1714}
1715
1716bool HTMLInputElement::isImageButton() const
1717{
1718 return m_inputType->isImageButton();
1719}
1720
1721bool HTMLInputElement::isNumberField() const
1722{
1723 return m_inputType->isNumberField();
1724}
1725
1726bool HTMLInputElement::isSubmitButton() const
1727{
1728 return m_inputType->isSubmitButton();
1729}
1730
1731bool HTMLInputElement::isTelephoneField() const
1732{
1733 return m_inputType->isTelephoneField();
1734}
1735
1736bool HTMLInputElement::isURLField() const
1737{
1738 return m_inputType->isURLField();
1739}
1740
1741bool HTMLInputElement::isDateField() const
1742{
1743 return m_inputType->isDateField();
1744}
1745
1746bool HTMLInputElement::isDateTimeField() const
1747{
1748 return m_inputType->isDateTimeField();
1749}
1750
1751bool HTMLInputElement::isDateTimeLocalField() const
1752{
1753 return m_inputType->isDateTimeLocalField();
1754}
1755
1756bool HTMLInputElement::isMonthField() const
1757{
1758 return m_inputType->isMonthField();
1759}
1760
1761bool HTMLInputElement::isTimeField() const
1762{
1763 return m_inputType->isTimeField();
1764}
1765
1766bool HTMLInputElement::isWeekField() const
1767{
1768 return m_inputType->isWeekField();
1769}
1770
1771bool HTMLInputElement::isEnumeratable() const
1772{
1773 return m_inputType->isEnumeratable();
1774}
1775
1776bool HTMLInputElement::supportLabels() const
1777{
1778 return m_inputType->supportLabels();
1779}
1780
1781bool HTMLInputElement::shouldAppearChecked() const
1782{
1783 return checked() && m_inputType->isCheckable();
1784}
1785
1786bool HTMLInputElement::supportsPlaceholder() const
1787{
1788 return m_inputType->supportsPlaceholder();
1789}
1790
1791void HTMLInputElement::updatePlaceholderText()
1792{
1793 return m_inputType->updatePlaceholderText();
1794}
1795
1796bool HTMLInputElement::isEmptyValue() const
1797{
1798 return m_inputType->isEmptyValue();
1799}
1800
1801void HTMLInputElement::maxLengthAttributeChanged(const AtomicString& newValue)
1802{
1803 unsigned oldEffectiveMaxLength = effectiveMaxLength();
1804 internalSetMaxLength(parseHTMLNonNegativeInteger(newValue).value_or(-1));
1805 if (oldEffectiveMaxLength != effectiveMaxLength())
1806 updateValueIfNeeded();
1807
1808 // FIXME: Do we really need to do this if the effective maxLength has not changed?
1809 invalidateStyleForSubtree();
1810 updateValidity();
1811}
1812
1813void HTMLInputElement::minLengthAttributeChanged(const AtomicString& newValue)
1814{
1815 int oldMinLength = minLength();
1816 internalSetMinLength(parseHTMLNonNegativeInteger(newValue).value_or(-1));
1817 if (oldMinLength != minLength())
1818 updateValueIfNeeded();
1819
1820 // FIXME: Do we really need to do this if the effective minLength has not changed?
1821 invalidateStyleForSubtree();
1822 updateValidity();
1823}
1824
1825void HTMLInputElement::updateValueIfNeeded()
1826{
1827 String newValue = sanitizeValue(m_valueIfDirty);
1828 ASSERT(!m_valueIfDirty.isNull() || newValue.isNull());
1829 if (newValue != m_valueIfDirty)
1830 setValue(newValue);
1831}
1832
1833String HTMLInputElement::defaultToolTip() const
1834{
1835 return m_inputType->defaultToolTip();
1836}
1837
1838bool HTMLInputElement::matchesIndeterminatePseudoClass() const
1839{
1840 // For input elements, matchesIndeterminatePseudoClass()
1841 // is not equivalent to shouldAppearIndeterminate() because of radio button.
1842 //
1843 // A group of radio button without any checked button is indeterminate
1844 // for the :indeterminate selector. On the other hand, RenderTheme
1845 // currently only supports single element being indeterminate.
1846 // Because of this, radio is indetermindate for CSS but not for render theme.
1847 return m_inputType->matchesIndeterminatePseudoClass();
1848}
1849
1850bool HTMLInputElement::shouldAppearIndeterminate() const
1851{
1852 return m_inputType->shouldAppearIndeterminate();
1853}
1854
1855#if ENABLE(MEDIA_CAPTURE)
1856MediaCaptureType HTMLInputElement::mediaCaptureType() const
1857{
1858 if (!isFileUpload())
1859 return MediaCaptureTypeNone;
1860
1861 auto& captureAttribute = attributeWithoutSynchronization(captureAttr);
1862 if (captureAttribute.isNull())
1863 return MediaCaptureTypeNone;
1864
1865 if (equalLettersIgnoringASCIICase(captureAttribute, "user"))
1866 return MediaCaptureTypeUser;
1867
1868 return MediaCaptureTypeEnvironment;
1869}
1870#endif
1871
1872bool HTMLInputElement::isInRequiredRadioButtonGroup()
1873{
1874 ASSERT(isRadioButton());
1875 if (RadioButtonGroups* buttons = radioButtonGroups())
1876 return buttons->isInRequiredGroup(*this);
1877 return false;
1878}
1879
1880Vector<HTMLInputElement*> HTMLInputElement::radioButtonGroup() const
1881{
1882 RadioButtonGroups* buttons = radioButtonGroups();
1883 if (!buttons)
1884 return { };
1885 return buttons->groupMembers(*this);
1886}
1887
1888HTMLInputElement* HTMLInputElement::checkedRadioButtonForGroup() const
1889{
1890 if (RadioButtonGroups* buttons = radioButtonGroups())
1891 return buttons->checkedButtonForGroup(name());
1892 return nullptr;
1893}
1894
1895RadioButtonGroups* HTMLInputElement::radioButtonGroups() const
1896{
1897 if (!isRadioButton())
1898 return nullptr;
1899 if (auto* formElement = form())
1900 return &formElement->radioButtonGroups();
1901 if (isConnected())
1902 return &document().formController().radioButtonGroups();
1903 return nullptr;
1904}
1905
1906inline void HTMLInputElement::addToRadioButtonGroup()
1907{
1908 if (auto* buttons = radioButtonGroups())
1909 buttons->addButton(*this);
1910}
1911
1912inline void HTMLInputElement::removeFromRadioButtonGroup()
1913{
1914 if (auto* buttons = radioButtonGroups())
1915 buttons->removeButton(*this);
1916}
1917
1918unsigned HTMLInputElement::height() const
1919{
1920 return m_inputType->height();
1921}
1922
1923unsigned HTMLInputElement::width() const
1924{
1925 return m_inputType->width();
1926}
1927
1928void HTMLInputElement::setHeight(unsigned height)
1929{
1930 setUnsignedIntegralAttribute(heightAttr, height);
1931}
1932
1933void HTMLInputElement::setWidth(unsigned width)
1934{
1935 setUnsignedIntegralAttribute(widthAttr, width);
1936}
1937
1938#if ENABLE(DATALIST_ELEMENT)
1939ListAttributeTargetObserver::ListAttributeTargetObserver(const AtomicString& id, HTMLInputElement* element)
1940 : IdTargetObserver(element->treeScope().idTargetObserverRegistry(), id)
1941 , m_element(element)
1942{
1943}
1944
1945void ListAttributeTargetObserver::idTargetChanged()
1946{
1947 m_element->listAttributeTargetChanged();
1948}
1949#endif
1950
1951ExceptionOr<void> HTMLInputElement::setRangeText(const String& replacement)
1952{
1953 if (!m_inputType->supportsSelectionAPI())
1954 return Exception { InvalidStateError };
1955
1956 return HTMLTextFormControlElement::setRangeText(replacement);
1957}
1958
1959ExceptionOr<void> HTMLInputElement::setRangeText(const String& replacement, unsigned start, unsigned end, const String& selectionMode)
1960{
1961 if (!m_inputType->supportsSelectionAPI())
1962 return Exception { InvalidStateError };
1963
1964 return HTMLTextFormControlElement::setRangeText(replacement, start, end, selectionMode);
1965}
1966
1967bool HTMLInputElement::shouldTruncateText(const RenderStyle& style) const
1968{
1969 if (!isTextField())
1970 return false;
1971 return document().focusedElement() != this && style.textOverflow() == TextOverflow::Ellipsis;
1972}
1973
1974ExceptionOr<int> HTMLInputElement::selectionStartForBindings() const
1975{
1976 if (!canHaveSelection())
1977 return Exception { TypeError };
1978
1979 return selectionStart();
1980}
1981
1982ExceptionOr<void> HTMLInputElement::setSelectionStartForBindings(int start)
1983{
1984 if (!canHaveSelection())
1985 return Exception { TypeError };
1986
1987 setSelectionStart(start);
1988 return { };
1989}
1990
1991ExceptionOr<int> HTMLInputElement::selectionEndForBindings() const
1992{
1993 if (!canHaveSelection())
1994 return Exception { TypeError };
1995
1996 return selectionEnd();
1997}
1998
1999ExceptionOr<void> HTMLInputElement::setSelectionEndForBindings(int end)
2000{
2001 if (!canHaveSelection())
2002 return Exception { TypeError };
2003
2004 setSelectionEnd(end);
2005 return { };
2006}
2007
2008ExceptionOr<String> HTMLInputElement::selectionDirectionForBindings() const
2009{
2010 if (!canHaveSelection())
2011 return Exception { TypeError };
2012
2013 return String { selectionDirection() };
2014}
2015
2016ExceptionOr<void> HTMLInputElement::setSelectionDirectionForBindings(const String& direction)
2017{
2018 if (!canHaveSelection())
2019 return Exception { TypeError };
2020
2021 setSelectionDirection(direction);
2022 return { };
2023}
2024
2025ExceptionOr<void> HTMLInputElement::setSelectionRangeForBindings(int start, int end, const String& direction)
2026{
2027 if (!canHaveSelection())
2028 return Exception { TypeError };
2029
2030 setSelectionRange(start, end, direction);
2031 return { };
2032}
2033
2034static Ref<CSSLinearGradientValue> autoFillStrongPasswordMaskImage()
2035{
2036 CSSGradientColorStop firstStop;
2037 firstStop.m_color = CSSValuePool::singleton().createColorValue(Color::black);
2038 firstStop.m_position = CSSValuePool::singleton().createValue(50, CSSPrimitiveValue::UnitType::CSS_PERCENTAGE);
2039
2040 CSSGradientColorStop secondStop;
2041 secondStop.m_color = CSSValuePool::singleton().createColorValue(Color::transparent);
2042 secondStop.m_position = CSSValuePool::singleton().createValue(100, CSSPrimitiveValue::UnitType::CSS_PERCENTAGE);
2043
2044 auto gradient = CSSLinearGradientValue::create(CSSGradientRepeat::NonRepeating, CSSGradientType::CSSLinearGradient);
2045 gradient->setAngle(CSSValuePool::singleton().createValue(90, CSSPrimitiveValue::UnitType::CSS_DEG));
2046 gradient->addStop(firstStop);
2047 gradient->addStop(secondStop);
2048 return gradient;
2049}
2050
2051RenderStyle HTMLInputElement::createInnerTextStyle(const RenderStyle& style)
2052{
2053 auto textBlockStyle = RenderStyle::create();
2054 textBlockStyle.inheritFrom(style);
2055 adjustInnerTextStyle(style, textBlockStyle);
2056
2057 textBlockStyle.setWhiteSpace(WhiteSpace::Pre);
2058 textBlockStyle.setOverflowWrap(OverflowWrap::Normal);
2059 textBlockStyle.setOverflowX(Overflow::Hidden);
2060 textBlockStyle.setOverflowY(Overflow::Hidden);
2061 textBlockStyle.setTextOverflow(shouldTruncateText(style) ? TextOverflow::Ellipsis : TextOverflow::Clip);
2062
2063 textBlockStyle.setDisplay(DisplayType::Block);
2064
2065 if (hasAutoFillStrongPasswordButton() && !isDisabledOrReadOnly()) {
2066 textBlockStyle.setDisplay(DisplayType::InlineBlock);
2067 textBlockStyle.setMaxWidth(Length { 100, Percent });
2068 textBlockStyle.setColor({ 0.0f, 0.0f, 0.0f, 0.6f });
2069 textBlockStyle.setTextOverflow(TextOverflow::Clip);
2070 textBlockStyle.setMaskImage(styleResolver().styleImage(autoFillStrongPasswordMaskImage()));
2071 // A stacking context is needed for the mask.
2072 if (textBlockStyle.hasAutoZIndex())
2073 textBlockStyle.setZIndex(0);
2074 }
2075
2076 // Do not allow line-height to be smaller than our default.
2077 if (textBlockStyle.fontMetrics().lineSpacing() > style.computedLineHeight())
2078 textBlockStyle.setLineHeight(RenderStyle::initialLineHeight());
2079
2080 return textBlockStyle;
2081}
2082
2083#if ENABLE(DATE_AND_TIME_INPUT_TYPES)
2084bool HTMLInputElement::setupDateTimeChooserParameters(DateTimeChooserParameters& parameters)
2085{
2086 if (!document().view())
2087 return false;
2088
2089 parameters.type = type();
2090 parameters.minimum = minimum();
2091 parameters.maximum = maximum();
2092 parameters.required = isRequired();
2093
2094 if (!document().settings().langAttributeAwareFormControlUIEnabled())
2095 parameters.locale = defaultLanguage();
2096 else {
2097 AtomicString computedLocale = computeInheritedLanguage();
2098 parameters.locale = computedLocale.isEmpty() ? AtomicString(defaultLanguage()) : computedLocale;
2099 }
2100
2101 StepRange stepRange = createStepRange(RejectAny);
2102 if (stepRange.hasStep()) {
2103 parameters.step = stepRange.step().toDouble();
2104 parameters.stepBase = stepRange.stepBase().toDouble();
2105 } else {
2106 parameters.step = 1.0;
2107 parameters.stepBase = 0;
2108 }
2109
2110 if (RenderElement* renderer = this->renderer())
2111 parameters.anchorRectInRootView = document().view()->contentsToRootView(renderer->absoluteBoundingBoxRect());
2112 else
2113 parameters.anchorRectInRootView = IntRect();
2114 parameters.currentValue = value();
2115 parameters.isAnchorElementRTL = computedStyle()->direction() == TextDirection::RTL;
2116#if ENABLE(DATALIST_ELEMENT)
2117 if (auto dataList = this->dataList()) {
2118 Ref<HTMLCollection> options = dataList->options();
2119 for (unsigned i = 0; RefPtr<HTMLOptionElement> option = downcast<HTMLOptionElement>(options->item(i)); ++i) {
2120 if (!isValidValue(option->value()))
2121 continue;
2122 parameters.suggestionValues.append(sanitizeValue(option->value()));
2123 parameters.localizedSuggestionValues.append(localizeValue(option->value()));
2124 parameters.suggestionLabels.append(option->value() == option->label() ? String() : option->label());
2125 }
2126 }
2127#endif
2128 return true;
2129}
2130#endif
2131
2132void HTMLInputElement::capsLockStateMayHaveChanged()
2133{
2134 m_inputType->capsLockStateMayHaveChanged();
2135}
2136
2137} // namespace
2138