• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
4  *           (C) 2001 Dirk Mueller (mueller@kde.org)
5  * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
6  *           (C) 2006 Alexey Proskuryakov (ap@nypop.com)
7  * Copyright (C) 2007 Samuel Weinig (sam@webkit.org)
8  * Copyright (C) 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 "core/html/HTMLInputElement.h"
31 
32 #include "CSSPropertyNames.h"
33 #include "HTMLNames.h"
34 #include "RuntimeEnabledFeatures.h"
35 #include "bindings/v8/ExceptionMessages.h"
36 #include "bindings/v8/ExceptionState.h"
37 #include "bindings/v8/ScriptEventListener.h"
38 #include "core/accessibility/AXObjectCache.h"
39 #include "core/dom/Document.h"
40 #include "core/dom/ExceptionCode.h"
41 #include "core/dom/IdTargetObserver.h"
42 #include "core/dom/shadow/ElementShadow.h"
43 #include "core/dom/shadow/InsertionPoint.h"
44 #include "core/dom/shadow/ShadowRoot.h"
45 #include "core/editing/FrameSelection.h"
46 #include "core/editing/SpellChecker.h"
47 #include "core/events/BeforeTextInsertedEvent.h"
48 #include "core/events/KeyboardEvent.h"
49 #include "core/events/MouseEvent.h"
50 #include "core/events/ScopedEventQueue.h"
51 #include "core/events/ThreadLocalEventNames.h"
52 #include "core/events/TouchEvent.h"
53 #include "core/fileapi/FileList.h"
54 #include "core/frame/Frame.h"
55 #include "core/frame/FrameView.h"
56 #include "core/html/HTMLCollection.h"
57 #include "core/html/HTMLDataListElement.h"
58 #include "core/html/HTMLFormElement.h"
59 #include "core/html/HTMLImageLoader.h"
60 #include "core/html/HTMLOptionElement.h"
61 #include "core/html/forms/ColorInputType.h"
62 #include "core/html/forms/FileInputType.h"
63 #include "core/html/forms/FormController.h"
64 #include "core/html/forms/InputType.h"
65 #include "core/html/forms/SearchInputType.h"
66 #include "core/html/parser/HTMLParserIdioms.h"
67 #include "core/html/shadow/ShadowElementNames.h"
68 #include "core/frame/UseCounter.h"
69 #include "core/page/Chrome.h"
70 #include "core/page/ChromeClient.h"
71 #include "core/page/Page.h"
72 #include "core/rendering/RenderTextControlSingleLine.h"
73 #include "core/rendering/RenderTheme.h"
74 #include "platform/DateTimeChooser.h"
75 #include "platform/Language.h"
76 #include "platform/PlatformMouseEvent.h"
77 #include "platform/text/PlatformLocale.h"
78 #include "wtf/MathExtras.h"
79 
80 using namespace std;
81 
82 namespace WebCore {
83 
84 using namespace HTMLNames;
85 
86 class ListAttributeTargetObserver : IdTargetObserver {
87     WTF_MAKE_FAST_ALLOCATED;
88 public:
89     static PassOwnPtr<ListAttributeTargetObserver> create(const AtomicString& id, HTMLInputElement*);
90     virtual void idTargetChanged() OVERRIDE;
91 
92 private:
93     ListAttributeTargetObserver(const AtomicString& id, HTMLInputElement*);
94 
95     HTMLInputElement* m_element;
96 };
97 
98 // FIXME: According to HTML4, the length attribute's value can be arbitrarily
99 // large. However, due to https://bugs.webkit.org/show_bug.cgi?id=14536 things
100 // get rather sluggish when a text field has a larger number of characters than
101 // this, even when just clicking in the text field.
102 const int HTMLInputElement::maximumLength = 524288;
103 const int defaultSize = 20;
104 const int maxSavedResults = 256;
105 
HTMLInputElement(Document & document,HTMLFormElement * form,bool createdByParser)106 HTMLInputElement::HTMLInputElement(Document& document, HTMLFormElement* form, bool createdByParser)
107     : HTMLTextFormControlElement(inputTag, document, form)
108     , m_size(defaultSize)
109     , m_maxLength(maximumLength)
110     , m_maxResults(-1)
111     , m_isChecked(false)
112     , m_reflectsCheckedAttribute(true)
113     , m_isIndeterminate(false)
114     , m_hasType(false)
115     , m_isActivatedSubmit(false)
116     , m_autocomplete(Uninitialized)
117     , m_hasNonEmptyList(false)
118     , m_stateRestored(false)
119     , m_parsingInProgress(createdByParser)
120     , m_valueAttributeWasUpdatedAfterParsing(false)
121     , m_canReceiveDroppedFiles(false)
122     , m_hasTouchEventHandler(false)
123     , m_inputType(InputType::createText(*this))
124     , m_inputTypeView(m_inputType)
125 {
126 #if ENABLE(INPUT_MULTIPLE_FIELDS_UI)
127     setHasCustomStyleCallbacks();
128 #endif
129     ScriptWrappable::init(this);
130 }
131 
create(Document & document,HTMLFormElement * form,bool createdByParser)132 PassRefPtr<HTMLInputElement> HTMLInputElement::create(Document& document, HTMLFormElement* form, bool createdByParser)
133 {
134     RefPtr<HTMLInputElement> inputElement = adoptRef(new HTMLInputElement(document, form, createdByParser));
135     inputElement->ensureUserAgentShadowRoot();
136     return inputElement.release();
137 }
138 
imageLoader()139 HTMLImageLoader* HTMLInputElement::imageLoader()
140 {
141     if (!m_imageLoader)
142         m_imageLoader = adoptPtr(new HTMLImageLoader(this));
143     return m_imageLoader.get();
144 }
145 
didAddUserAgentShadowRoot(ShadowRoot &)146 void HTMLInputElement::didAddUserAgentShadowRoot(ShadowRoot&)
147 {
148     m_inputTypeView->createShadowSubtree();
149 }
150 
didAddShadowRoot(ShadowRoot & root)151 void HTMLInputElement::didAddShadowRoot(ShadowRoot& root)
152 {
153     if (!root.isOldestAuthorShadowRoot())
154         return;
155     m_inputTypeView->destroyShadowSubtree();
156     m_inputTypeView = InputTypeView::create(*this);
157     lazyReattachIfAttached();
158 }
159 
~HTMLInputElement()160 HTMLInputElement::~HTMLInputElement()
161 {
162     // Need to remove form association while this is still an HTMLInputElement
163     // so that virtual functions are called correctly.
164     setForm(0);
165     // setForm(0) may register this to a document-level radio button group.
166     // We should unregister it to avoid accessing a deleted object.
167     if (isRadioButton())
168         document().formController()->checkedRadioButtons().removeButton(this);
169     if (m_hasTouchEventHandler)
170         document().didRemoveEventTargetNode(this);
171 }
172 
name() const173 const AtomicString& HTMLInputElement::name() const
174 {
175     return m_name.isNull() ? emptyAtom : m_name;
176 }
177 
filesFromFileInputFormControlState(const FormControlState & state)178 Vector<FileChooserFileInfo> HTMLInputElement::filesFromFileInputFormControlState(const FormControlState& state)
179 {
180     return FileInputType::filesFromFormControlState(state);
181 }
182 
passwordGeneratorButtonElement() const183 HTMLElement* HTMLInputElement::passwordGeneratorButtonElement() const
184 {
185     return toHTMLElement(userAgentShadowRoot()->getElementById(ShadowElementNames::passwordGenerator()));
186 }
187 
shouldAutocomplete() const188 bool HTMLInputElement::shouldAutocomplete() const
189 {
190     if (m_autocomplete != Uninitialized)
191         return m_autocomplete == On;
192     return HTMLTextFormControlElement::shouldAutocomplete();
193 }
194 
isValidValue(const String & value) const195 bool HTMLInputElement::isValidValue(const String& value) const
196 {
197     if (!m_inputType->canSetStringValue()) {
198         ASSERT_NOT_REACHED();
199         return false;
200     }
201     return !m_inputType->typeMismatchFor(value)
202         && !m_inputType->stepMismatch(value)
203         && !m_inputType->rangeUnderflow(value)
204         && !m_inputType->rangeOverflow(value)
205         && !tooLong(value, IgnoreDirtyFlag)
206         && !m_inputType->patternMismatch(value)
207         && !m_inputType->valueMissing(value);
208 }
209 
tooLong() const210 bool HTMLInputElement::tooLong() const
211 {
212     return willValidate() && tooLong(value(), CheckDirtyFlag);
213 }
214 
typeMismatch() const215 bool HTMLInputElement::typeMismatch() const
216 {
217     return willValidate() && m_inputType->typeMismatch();
218 }
219 
valueMissing() const220 bool HTMLInputElement::valueMissing() const
221 {
222     return willValidate() && m_inputType->valueMissing(value());
223 }
224 
hasBadInput() const225 bool HTMLInputElement::hasBadInput() const
226 {
227     return willValidate() && m_inputType->hasBadInput();
228 }
229 
patternMismatch() const230 bool HTMLInputElement::patternMismatch() const
231 {
232     return willValidate() && m_inputType->patternMismatch(value());
233 }
234 
tooLong(const String & value,NeedsToCheckDirtyFlag check) const235 bool HTMLInputElement::tooLong(const String& value, NeedsToCheckDirtyFlag check) const
236 {
237     // We use isTextType() instead of supportsMaxLength() because of the
238     // 'virtual' overhead.
239     if (!isTextType())
240         return false;
241     int max = maxLength();
242     if (max < 0)
243         return false;
244     if (check == CheckDirtyFlag) {
245         // Return false for the default value or a value set by a script even if
246         // it is longer than maxLength.
247         if (!hasDirtyValue() || !lastChangeWasUserEdit())
248             return false;
249     }
250     return value.length() > static_cast<unsigned>(max);
251 }
252 
rangeUnderflow() const253 bool HTMLInputElement::rangeUnderflow() const
254 {
255     return willValidate() && m_inputType->rangeUnderflow(value());
256 }
257 
rangeOverflow() const258 bool HTMLInputElement::rangeOverflow() const
259 {
260     return willValidate() && m_inputType->rangeOverflow(value());
261 }
262 
validationMessage() const263 String HTMLInputElement::validationMessage() const
264 {
265     if (!willValidate())
266         return String();
267 
268     if (customError())
269         return customValidationMessage();
270 
271     return m_inputType->validationMessage();
272 }
273 
minimum() const274 double HTMLInputElement::minimum() const
275 {
276     return m_inputType->minimum();
277 }
278 
maximum() const279 double HTMLInputElement::maximum() const
280 {
281     return m_inputType->maximum();
282 }
283 
stepMismatch() const284 bool HTMLInputElement::stepMismatch() const
285 {
286     return willValidate() && m_inputType->stepMismatch(value());
287 }
288 
getAllowedValueStep(Decimal * step) const289 bool HTMLInputElement::getAllowedValueStep(Decimal* step) const
290 {
291     return m_inputType->getAllowedValueStep(step);
292 }
293 
createStepRange(AnyStepHandling anyStepHandling) const294 StepRange HTMLInputElement::createStepRange(AnyStepHandling anyStepHandling) const
295 {
296     return m_inputType->createStepRange(anyStepHandling);
297 }
298 
findClosestTickMarkValue(const Decimal & value)299 Decimal HTMLInputElement::findClosestTickMarkValue(const Decimal& value)
300 {
301     return m_inputType->findClosestTickMarkValue(value);
302 }
303 
stepUp(int n,ExceptionState & exceptionState)304 void HTMLInputElement::stepUp(int n, ExceptionState& exceptionState)
305 {
306     m_inputType->stepUp(n, exceptionState);
307 }
308 
stepDown(int n,ExceptionState & exceptionState)309 void HTMLInputElement::stepDown(int n, ExceptionState& exceptionState)
310 {
311     m_inputType->stepUp(-n, exceptionState);
312 }
313 
blur()314 void HTMLInputElement::blur()
315 {
316     m_inputTypeView->blur();
317 }
318 
defaultBlur()319 void HTMLInputElement::defaultBlur()
320 {
321     HTMLTextFormControlElement::blur();
322 }
323 
hasCustomFocusLogic() const324 bool HTMLInputElement::hasCustomFocusLogic() const
325 {
326     return m_inputTypeView->hasCustomFocusLogic();
327 }
328 
isKeyboardFocusable() const329 bool HTMLInputElement::isKeyboardFocusable() const
330 {
331     return m_inputType->isKeyboardFocusable();
332 }
333 
shouldShowFocusRingOnMouseFocus() const334 bool HTMLInputElement::shouldShowFocusRingOnMouseFocus() const
335 {
336     return m_inputType->shouldShowFocusRingOnMouseFocus();
337 }
338 
updateFocusAppearance(bool restorePreviousSelection)339 void HTMLInputElement::updateFocusAppearance(bool restorePreviousSelection)
340 {
341     if (isTextField()) {
342         if (!restorePreviousSelection || !hasCachedSelection())
343             select();
344         else
345             restoreCachedSelection();
346         if (document().frame())
347             document().frame()->selection().revealSelection();
348     } else
349         HTMLTextFormControlElement::updateFocusAppearance(restorePreviousSelection);
350 }
351 
beginEditing()352 void HTMLInputElement::beginEditing()
353 {
354     if (!isTextField())
355         return;
356 
357     if (Frame* frame = document().frame())
358         frame->spellChecker().didBeginEditing(this);
359 }
360 
endEditing()361 void HTMLInputElement::endEditing()
362 {
363     if (!isTextField())
364         return;
365 
366     if (Frame* frame = document().frame()) {
367         frame->spellChecker().didEndEditingOnTextField(this);
368         if (Page* page = frame->page())
369             page->chrome().client().didEndEditingOnTextField(*this);
370     }
371 }
372 
shouldUseInputMethod()373 bool HTMLInputElement::shouldUseInputMethod()
374 {
375     return m_inputType->shouldUseInputMethod();
376 }
377 
handleFocusEvent(Element * oldFocusedElement,FocusDirection direction)378 void HTMLInputElement::handleFocusEvent(Element* oldFocusedElement, FocusDirection direction)
379 {
380     m_inputTypeView->handleFocusEvent(oldFocusedElement, direction);
381     m_inputType->enableSecureTextInput();
382 }
383 
handleBlurEvent()384 void HTMLInputElement::handleBlurEvent()
385 {
386     m_inputType->disableSecureTextInput();
387     m_inputTypeView->handleBlurEvent();
388 }
389 
setType(const AtomicString & type)390 void HTMLInputElement::setType(const AtomicString& type)
391 {
392     // FIXME: This should just call setAttribute. No reason to handle the empty string specially.
393     // We should write a test case to show that setting to the empty string does not remove the
394     // attribute in other browsers and then fix this. Note that setting to null *does* remove
395     // the attribute and setAttribute implements that.
396     if (type.isEmpty())
397         removeAttribute(typeAttr);
398     else
399         setAttribute(typeAttr, type);
400 }
401 
updateType()402 void HTMLInputElement::updateType()
403 {
404     const AtomicString& newTypeName = InputType::normalizeTypeName(fastGetAttribute(typeAttr));
405     bool hadType = m_hasType;
406     m_hasType = true;
407     if (m_inputType->formControlType() == newTypeName)
408         return;
409 
410     if (hadType && !InputType::canChangeFromAnotherType(newTypeName)) {
411         // Set the attribute back to the old value.
412         // Useful in case we were called from inside parseAttribute.
413         setAttribute(typeAttr, type());
414         return;
415     }
416 
417     RefPtr<InputType> newType = InputType::create(*this, newTypeName);
418     removeFromRadioButtonGroup();
419 
420     bool didStoreValue = m_inputType->storesValueSeparateFromAttribute();
421     bool didRespectHeightAndWidth = m_inputType->shouldRespectHeightAndWidthAttributes();
422 
423     m_inputTypeView->destroyShadowSubtree();
424     lazyReattachIfAttached();
425 
426     m_inputType = newType.release();
427     if (hasAuthorShadowRoot())
428         m_inputTypeView = InputTypeView::create(*this);
429     else
430         m_inputTypeView = m_inputType;
431     m_inputTypeView->createShadowSubtree();
432 
433     bool hasTouchEventHandler = m_inputTypeView->hasTouchEventHandler();
434     if (hasTouchEventHandler != m_hasTouchEventHandler) {
435         if (hasTouchEventHandler)
436             document().didAddTouchEventHandler(this);
437         else
438             document().didRemoveTouchEventHandler(this);
439         m_hasTouchEventHandler = hasTouchEventHandler;
440     }
441 
442     setNeedsWillValidateCheck();
443 
444     bool willStoreValue = m_inputType->storesValueSeparateFromAttribute();
445 
446     if (didStoreValue && !willStoreValue && hasDirtyValue()) {
447         setAttribute(valueAttr, AtomicString(m_valueIfDirty));
448         m_valueIfDirty = String();
449     }
450     if (!didStoreValue && willStoreValue) {
451         AtomicString valueString = fastGetAttribute(valueAttr);
452         m_valueIfDirty = sanitizeValue(valueString);
453     } else
454         updateValueIfNeeded();
455 
456     setFormControlValueMatchesRenderer(false);
457     m_inputTypeView->updateView();
458 
459     if (didRespectHeightAndWidth != m_inputType->shouldRespectHeightAndWidthAttributes()) {
460         ASSERT(elementData());
461         if (const Attribute* height = getAttributeItem(heightAttr))
462             attributeChanged(heightAttr, height->value());
463         if (const Attribute* width = getAttributeItem(widthAttr))
464             attributeChanged(widthAttr, width->value());
465         if (const Attribute* align = getAttributeItem(alignAttr))
466             attributeChanged(alignAttr, align->value());
467     }
468 
469     if (document().focusedElement() == this)
470         document().updateFocusAppearanceSoon(true /* restore selection */);
471 
472     setChangedSinceLastFormControlChangeEvent(false);
473 
474     addToRadioButtonGroup();
475 
476     setNeedsValidityCheck();
477     notifyFormStateChanged();
478 }
479 
subtreeHasChanged()480 void HTMLInputElement::subtreeHasChanged()
481 {
482     m_inputTypeView->subtreeHasChanged();
483     // When typing in an input field, childrenChanged is not called, so we need to force the directionality check.
484     calculateAndAdjustDirectionality();
485 }
486 
formControlType() const487 const AtomicString& HTMLInputElement::formControlType() const
488 {
489     return m_inputType->formControlType();
490 }
491 
shouldSaveAndRestoreFormControlState() const492 bool HTMLInputElement::shouldSaveAndRestoreFormControlState() const
493 {
494     if (!m_inputType->shouldSaveAndRestoreFormControlState())
495         return false;
496     return HTMLTextFormControlElement::shouldSaveAndRestoreFormControlState();
497 }
498 
saveFormControlState() const499 FormControlState HTMLInputElement::saveFormControlState() const
500 {
501     return m_inputType->saveFormControlState();
502 }
503 
restoreFormControlState(const FormControlState & state)504 void HTMLInputElement::restoreFormControlState(const FormControlState& state)
505 {
506     m_inputType->restoreFormControlState(state);
507     m_stateRestored = true;
508 }
509 
canStartSelection() const510 bool HTMLInputElement::canStartSelection() const
511 {
512     if (!isTextField())
513         return false;
514     return HTMLTextFormControlElement::canStartSelection();
515 }
516 
canHaveSelection() const517 bool HTMLInputElement::canHaveSelection() const
518 {
519     return isTextField();
520 }
521 
selectionStartForBinding(ExceptionState & exceptionState) const522 int HTMLInputElement::selectionStartForBinding(ExceptionState& exceptionState) const
523 {
524     if (!m_inputType->supportsSelectionAPI()) {
525         exceptionState.throwDOMException(InvalidStateError, "The input element's type ('" + m_inputType->formControlType() + "') does not support selection.");
526         return 0;
527     }
528     return HTMLTextFormControlElement::selectionStart();
529 }
530 
selectionEndForBinding(ExceptionState & exceptionState) const531 int HTMLInputElement::selectionEndForBinding(ExceptionState& exceptionState) const
532 {
533     if (!m_inputType->supportsSelectionAPI()) {
534         exceptionState.throwDOMException(InvalidStateError, "The input element's type ('" + m_inputType->formControlType() + "') does not support selection.");
535         return 0;
536     }
537     return HTMLTextFormControlElement::selectionEnd();
538 }
539 
selectionDirectionForBinding(ExceptionState & exceptionState) const540 String HTMLInputElement::selectionDirectionForBinding(ExceptionState& exceptionState) const
541 {
542     if (!m_inputType->supportsSelectionAPI()) {
543         exceptionState.throwDOMException(InvalidStateError, "The input element's type ('" + m_inputType->formControlType() + "') does not support selection.");
544         return String();
545     }
546     return HTMLTextFormControlElement::selectionDirection();
547 }
548 
setSelectionStartForBinding(int start,ExceptionState & exceptionState)549 void HTMLInputElement::setSelectionStartForBinding(int start, ExceptionState& exceptionState)
550 {
551     if (!m_inputType->supportsSelectionAPI()) {
552         exceptionState.throwDOMException(InvalidStateError, "The input element's type ('" + m_inputType->formControlType() + "') does not support selection.");
553         return;
554     }
555     HTMLTextFormControlElement::setSelectionStart(start);
556 }
557 
setSelectionEndForBinding(int end,ExceptionState & exceptionState)558 void HTMLInputElement::setSelectionEndForBinding(int end, ExceptionState& exceptionState)
559 {
560     if (!m_inputType->supportsSelectionAPI()) {
561         exceptionState.throwDOMException(InvalidStateError, "The input element's type ('" + m_inputType->formControlType() + "') does not support selection.");
562         return;
563     }
564     HTMLTextFormControlElement::setSelectionEnd(end);
565 }
566 
setSelectionDirectionForBinding(const String & direction,ExceptionState & exceptionState)567 void HTMLInputElement::setSelectionDirectionForBinding(const String& direction, ExceptionState& exceptionState)
568 {
569     if (!m_inputType->supportsSelectionAPI()) {
570         exceptionState.throwDOMException(InvalidStateError, "The input element's type ('" + m_inputType->formControlType() + "') does not support selection.");
571         return;
572     }
573     HTMLTextFormControlElement::setSelectionDirection(direction);
574 }
575 
setSelectionRangeForBinding(int start,int end,ExceptionState & exceptionState)576 void HTMLInputElement::setSelectionRangeForBinding(int start, int end, ExceptionState& exceptionState)
577 {
578     if (!m_inputType->supportsSelectionAPI()) {
579         exceptionState.throwDOMException(InvalidStateError, "The input element's type ('" + m_inputType->formControlType() + "') does not support selection.");
580         return;
581     }
582     HTMLTextFormControlElement::setSelectionRange(start, end);
583 }
584 
setSelectionRangeForBinding(int start,int end,const String & direction,ExceptionState & exceptionState)585 void HTMLInputElement::setSelectionRangeForBinding(int start, int end, const String& direction, ExceptionState& exceptionState)
586 {
587     if (!m_inputType->supportsSelectionAPI()) {
588         exceptionState.throwDOMException(InvalidStateError, "The input element's type ('" + m_inputType->formControlType() + "') does not support selection.");
589         return;
590     }
591     HTMLTextFormControlElement::setSelectionRange(start, end, direction);
592 }
593 
accessKeyAction(bool sendMouseEvents)594 void HTMLInputElement::accessKeyAction(bool sendMouseEvents)
595 {
596     m_inputType->accessKeyAction(sendMouseEvents);
597 }
598 
isPresentationAttribute(const QualifiedName & name) const599 bool HTMLInputElement::isPresentationAttribute(const QualifiedName& name) const
600 {
601     if (name == vspaceAttr || name == hspaceAttr || name == alignAttr || name == widthAttr || name == heightAttr || (name == borderAttr && isImageButton()))
602         return true;
603     return HTMLTextFormControlElement::isPresentationAttribute(name);
604 }
605 
collectStyleForPresentationAttribute(const QualifiedName & name,const AtomicString & value,MutableStylePropertySet * style)606 void HTMLInputElement::collectStyleForPresentationAttribute(const QualifiedName& name, const AtomicString& value, MutableStylePropertySet* style)
607 {
608     if (name == vspaceAttr) {
609         addHTMLLengthToStyle(style, CSSPropertyMarginTop, value);
610         addHTMLLengthToStyle(style, CSSPropertyMarginBottom, value);
611     } else if (name == hspaceAttr) {
612         addHTMLLengthToStyle(style, CSSPropertyMarginLeft, value);
613         addHTMLLengthToStyle(style, CSSPropertyMarginRight, value);
614     } else if (name == alignAttr) {
615         if (m_inputType->shouldRespectAlignAttribute())
616             applyAlignmentAttributeToStyle(value, style);
617     } else if (name == widthAttr) {
618         if (m_inputType->shouldRespectHeightAndWidthAttributes())
619             addHTMLLengthToStyle(style, CSSPropertyWidth, value);
620     } else if (name == heightAttr) {
621         if (m_inputType->shouldRespectHeightAndWidthAttributes())
622             addHTMLLengthToStyle(style, CSSPropertyHeight, value);
623     } else if (name == borderAttr && isImageButton())
624         applyBorderAttributeToStyle(value, style);
625     else
626         HTMLTextFormControlElement::collectStyleForPresentationAttribute(name, value, style);
627 }
628 
parseAttribute(const QualifiedName & name,const AtomicString & value)629 void HTMLInputElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
630 {
631     if (name == nameAttr) {
632         removeFromRadioButtonGroup();
633         m_name = value;
634         addToRadioButtonGroup();
635         HTMLTextFormControlElement::parseAttribute(name, value);
636     } else if (name == autocompleteAttr) {
637         if (equalIgnoringCase(value, "off"))
638             m_autocomplete = Off;
639         else {
640             if (value.isEmpty())
641                 m_autocomplete = Uninitialized;
642             else
643                 m_autocomplete = On;
644         }
645     } else if (name == typeAttr)
646         updateType();
647     else if (name == valueAttr) {
648         // We only need to setChanged if the form is looking at the default value right now.
649         if (!hasDirtyValue()) {
650             updatePlaceholderVisibility(false);
651             setNeedsStyleRecalc();
652         }
653         setFormControlValueMatchesRenderer(false);
654         setNeedsValidityCheck();
655         m_valueAttributeWasUpdatedAfterParsing = !m_parsingInProgress;
656         m_inputTypeView->valueAttributeChanged();
657     } else if (name == checkedAttr) {
658         // Another radio button in the same group might be checked by state
659         // restore. We shouldn't call setChecked() even if this has the checked
660         // attribute. So, delay the setChecked() call until
661         // finishParsingChildren() is called if parsing is in progress.
662         if (!m_parsingInProgress && m_reflectsCheckedAttribute) {
663             setChecked(!value.isNull());
664             m_reflectsCheckedAttribute = true;
665         }
666     } else if (name == maxlengthAttr)
667         parseMaxLengthAttribute(value);
668     else if (name == sizeAttr) {
669         int oldSize = m_size;
670         int valueAsInteger = value.toInt();
671         m_size = valueAsInteger > 0 ? valueAsInteger : defaultSize;
672         if (m_size != oldSize && renderer())
673             renderer()->setNeedsLayoutAndPrefWidthsRecalc();
674     } else if (name == altAttr)
675         m_inputTypeView->altAttributeChanged();
676     else if (name == srcAttr)
677         m_inputTypeView->srcAttributeChanged();
678     else if (name == usemapAttr || name == accesskeyAttr) {
679         // FIXME: ignore for the moment
680     } else if (name == onsearchAttr) {
681         // Search field and slider attributes all just cause updateFromElement to be called through style recalcing.
682         setAttributeEventListener(EventTypeNames::search, createAttributeEventListener(this, name, value));
683     } else if (name == resultsAttr) {
684         int oldResults = m_maxResults;
685         m_maxResults = !value.isNull() ? std::min(value.toInt(), maxSavedResults) : -1;
686         // FIXME: Detaching just for maxResults change is not ideal.  We should figure out the right
687         // time to relayout for this change.
688         if (m_maxResults != oldResults && (m_maxResults <= 0 || oldResults <= 0))
689             lazyReattachIfAttached();
690         setNeedsStyleRecalc();
691         UseCounter::count(document(), UseCounter::ResultsAttribute);
692     } else if (name == incrementalAttr) {
693         setNeedsStyleRecalc();
694         UseCounter::count(document(), UseCounter::IncrementalAttribute);
695     } else if (name == minAttr) {
696         m_inputTypeView->minOrMaxAttributeChanged();
697         m_inputType->sanitizeValueInResponseToMinOrMaxAttributeChange();
698         setNeedsValidityCheck();
699         UseCounter::count(document(), UseCounter::MinAttribute);
700     } else if (name == maxAttr) {
701         m_inputTypeView->minOrMaxAttributeChanged();
702         setNeedsValidityCheck();
703         UseCounter::count(document(), UseCounter::MaxAttribute);
704     } else if (name == multipleAttr) {
705         m_inputTypeView->multipleAttributeChanged();
706         setNeedsValidityCheck();
707     } else if (name == stepAttr) {
708         m_inputTypeView->stepAttributeChanged();
709         setNeedsValidityCheck();
710         UseCounter::count(document(), UseCounter::StepAttribute);
711     } else if (name == patternAttr) {
712         setNeedsValidityCheck();
713         UseCounter::count(document(), UseCounter::PatternAttribute);
714     } else if (name == precisionAttr) {
715         setNeedsValidityCheck();
716         UseCounter::count(document(), UseCounter::PrecisionAttribute);
717     } else if (name == disabledAttr) {
718         HTMLTextFormControlElement::parseAttribute(name, value);
719         m_inputTypeView->disabledAttributeChanged();
720     } else if (name == readonlyAttr) {
721         HTMLTextFormControlElement::parseAttribute(name, value);
722         m_inputTypeView->readonlyAttributeChanged();
723     } else if (name == listAttr) {
724         m_hasNonEmptyList = !value.isEmpty();
725         if (m_hasNonEmptyList) {
726             resetListAttributeTargetObserver();
727             listAttributeTargetChanged();
728         }
729         UseCounter::count(document(), UseCounter::ListAttribute);
730     }
731 #if ENABLE(INPUT_SPEECH)
732     else if (name == webkitspeechAttr) {
733         if (RuntimeEnabledFeatures::speechInputEnabled() && m_inputType->shouldRespectSpeechAttribute()) {
734             // This renderer and its children have quite different layouts and
735             // styles depending on whether the speech button is visible or
736             // not. So we reset the whole thing and recreate to get the right
737             // styles and layout.
738             m_inputTypeView->destroyShadowSubtree();
739             lazyReattachIfAttached();
740             m_inputTypeView->createShadowSubtree();
741             setFormControlValueMatchesRenderer(false);
742         }
743         UseCounter::count(document(), UseCounter::PrefixedSpeechAttribute);
744     } else if (name == onwebkitspeechchangeAttr)
745         setAttributeEventListener(EventTypeNames::webkitspeechchange, createAttributeEventListener(this, name, value));
746 #endif
747     else if (name == webkitdirectoryAttr) {
748         HTMLTextFormControlElement::parseAttribute(name, value);
749         UseCounter::count(document(), UseCounter::PrefixedDirectoryAttribute);
750     }
751     else
752         HTMLTextFormControlElement::parseAttribute(name, value);
753     m_inputTypeView->attributeChanged();
754 }
755 
finishParsingChildren()756 void HTMLInputElement::finishParsingChildren()
757 {
758     m_parsingInProgress = false;
759     HTMLTextFormControlElement::finishParsingChildren();
760     if (!m_stateRestored) {
761         bool checked = hasAttribute(checkedAttr);
762         if (checked)
763             setChecked(checked);
764         m_reflectsCheckedAttribute = true;
765     }
766 }
767 
rendererIsNeeded(const RenderStyle & style)768 bool HTMLInputElement::rendererIsNeeded(const RenderStyle& style)
769 {
770     return m_inputType->rendererIsNeeded() && HTMLTextFormControlElement::rendererIsNeeded(style);
771 }
772 
createRenderer(RenderStyle * style)773 RenderObject* HTMLInputElement::createRenderer(RenderStyle* style)
774 {
775     return m_inputTypeView->createRenderer(style);
776 }
777 
attach(const AttachContext & context)778 void HTMLInputElement::attach(const AttachContext& context)
779 {
780     if (!m_hasType)
781         updateType();
782 
783     HTMLTextFormControlElement::attach(context);
784 
785     m_inputTypeView->startResourceLoading();
786     m_inputType->countUsage();
787 
788     if (document().focusedElement() == this)
789         document().updateFocusAppearanceSoon(true /* restore selection */);
790 }
791 
detach(const AttachContext & context)792 void HTMLInputElement::detach(const AttachContext& context)
793 {
794     HTMLTextFormControlElement::detach(context);
795     setFormControlValueMatchesRenderer(false);
796     m_inputTypeView->closePopupView();
797 }
798 
altText() const799 String HTMLInputElement::altText() const
800 {
801     // http://www.w3.org/TR/1998/REC-html40-19980424/appendix/notes.html#altgen
802     // also heavily discussed by Hixie on bugzilla
803     // note this is intentionally different to HTMLImageElement::altText()
804     String alt = fastGetAttribute(altAttr);
805     // fall back to title attribute
806     if (alt.isNull())
807         alt = getAttribute(titleAttr);
808     if (alt.isNull())
809         alt = getAttribute(valueAttr);
810     if (alt.isEmpty())
811         alt = locale().queryString(blink::WebLocalizedString::InputElementAltText);
812     return alt;
813 }
814 
canBeSuccessfulSubmitButton() const815 bool HTMLInputElement::canBeSuccessfulSubmitButton() const
816 {
817     return m_inputType->canBeSuccessfulSubmitButton();
818 }
819 
isActivatedSubmit() const820 bool HTMLInputElement::isActivatedSubmit() const
821 {
822     return m_isActivatedSubmit;
823 }
824 
setActivatedSubmit(bool flag)825 void HTMLInputElement::setActivatedSubmit(bool flag)
826 {
827     m_isActivatedSubmit = flag;
828 }
829 
appendFormData(FormDataList & encoding,bool multipart)830 bool HTMLInputElement::appendFormData(FormDataList& encoding, bool multipart)
831 {
832     return m_inputType->isFormDataAppendable() && m_inputType->appendFormData(encoding, multipart);
833 }
834 
resultForDialogSubmit()835 String HTMLInputElement::resultForDialogSubmit()
836 {
837     return m_inputType->resultForDialogSubmit();
838 }
839 
resetImpl()840 void HTMLInputElement::resetImpl()
841 {
842     if (m_inputType->storesValueSeparateFromAttribute())
843         setValue(String());
844 
845     setChecked(hasAttribute(checkedAttr));
846     m_reflectsCheckedAttribute = true;
847 }
848 
isTextField() const849 bool HTMLInputElement::isTextField() const
850 {
851     return m_inputType->isTextField();
852 }
853 
isTextType() const854 bool HTMLInputElement::isTextType() const
855 {
856     return m_inputType->isTextType();
857 }
858 
setChecked(bool nowChecked,TextFieldEventBehavior eventBehavior)859 void HTMLInputElement::setChecked(bool nowChecked, TextFieldEventBehavior eventBehavior)
860 {
861     if (checked() == nowChecked)
862         return;
863 
864     m_reflectsCheckedAttribute = false;
865     m_isChecked = nowChecked;
866     setNeedsStyleRecalc();
867 
868     if (CheckedRadioButtons* buttons = checkedRadioButtons())
869             buttons->updateCheckedState(this);
870     if (renderer() && renderer()->style()->hasAppearance())
871         RenderTheme::theme().stateChanged(renderer(), CheckedState);
872 
873     setNeedsValidityCheck();
874 
875     // Ideally we'd do this from the render tree (matching
876     // RenderTextView), but it's not possible to do it at the moment
877     // because of the way the code is structured.
878     if (renderer()) {
879         if (AXObjectCache* cache = renderer()->document().existingAXObjectCache())
880             cache->checkedStateChanged(this);
881     }
882 
883     // Only send a change event for items in the document (avoid firing during
884     // parsing) and don't send a change event for a radio button that's getting
885     // unchecked to match other browsers. DOM is not a useful standard for this
886     // because it says only to fire change events at "lose focus" time, which is
887     // definitely wrong in practice for these types of elements.
888     if (eventBehavior != DispatchNoEvent && inDocument() && m_inputType->shouldSendChangeEventAfterCheckedChanged()) {
889         setTextAsOfLastFormControlChangeEvent(String());
890         dispatchFormControlChangeEvent();
891     }
892 
893     didAffectSelector(AffectedSelectorChecked);
894 }
895 
setIndeterminate(bool newValue)896 void HTMLInputElement::setIndeterminate(bool newValue)
897 {
898     if (indeterminate() == newValue)
899         return;
900 
901     m_isIndeterminate = newValue;
902 
903     didAffectSelector(AffectedSelectorIndeterminate);
904 
905     if (renderer() && renderer()->style()->hasAppearance())
906         RenderTheme::theme().stateChanged(renderer(), CheckedState);
907 }
908 
size() const909 int HTMLInputElement::size() const
910 {
911     return m_size;
912 }
913 
sizeShouldIncludeDecoration(int & preferredSize) const914 bool HTMLInputElement::sizeShouldIncludeDecoration(int& preferredSize) const
915 {
916     return m_inputTypeView->sizeShouldIncludeDecoration(defaultSize, preferredSize);
917 }
918 
copyNonAttributePropertiesFromElement(const Element & source)919 void HTMLInputElement::copyNonAttributePropertiesFromElement(const Element& source)
920 {
921     const HTMLInputElement& sourceElement = static_cast<const HTMLInputElement&>(source);
922 
923     m_valueIfDirty = sourceElement.m_valueIfDirty;
924     setChecked(sourceElement.m_isChecked);
925     m_reflectsCheckedAttribute = sourceElement.m_reflectsCheckedAttribute;
926     m_isIndeterminate = sourceElement.m_isIndeterminate;
927 
928     HTMLTextFormControlElement::copyNonAttributePropertiesFromElement(source);
929 
930     setFormControlValueMatchesRenderer(false);
931     m_inputTypeView->updateView();
932 }
933 
value() const934 String HTMLInputElement::value() const
935 {
936     String value;
937     if (m_inputType->getTypeSpecificValue(value))
938         return value;
939 
940     value = m_valueIfDirty;
941     if (!value.isNull())
942         return value;
943 
944     AtomicString valueString = fastGetAttribute(valueAttr);
945     value = sanitizeValue(valueString);
946     if (!value.isNull())
947         return value;
948 
949     return m_inputType->fallbackValue();
950 }
951 
valueWithDefault() const952 String HTMLInputElement::valueWithDefault() const
953 {
954     String value = this->value();
955     if (!value.isNull())
956         return value;
957 
958     return m_inputType->defaultValue();
959 }
960 
setValueForUser(const String & value)961 void HTMLInputElement::setValueForUser(const String& value)
962 {
963     // Call setValue and make it send a change event.
964     setValue(value, DispatchChangeEvent);
965 }
966 
suggestedValue() const967 const String& HTMLInputElement::suggestedValue() const
968 {
969     return m_suggestedValue;
970 }
971 
setSuggestedValue(const String & value)972 void HTMLInputElement::setSuggestedValue(const String& value)
973 {
974     if (!m_inputType->canSetSuggestedValue())
975         return;
976     setFormControlValueMatchesRenderer(false);
977     m_suggestedValue = sanitizeValue(value);
978     setNeedsStyleRecalc();
979     m_inputTypeView->updateView();
980 }
981 
setEditingValue(const String & value)982 void HTMLInputElement::setEditingValue(const String& value)
983 {
984     if (!renderer() || !isTextField())
985         return;
986     setInnerTextValue(value);
987     subtreeHasChanged();
988 
989     unsigned max = value.length();
990     if (focused())
991         setSelectionRange(max, max);
992     else
993         cacheSelectionInResponseToSetValue(max);
994 
995     dispatchInputEvent();
996 }
997 
setValue(const String & value,ExceptionState & exceptionState,TextFieldEventBehavior eventBehavior)998 void HTMLInputElement::setValue(const String& value, ExceptionState& exceptionState, TextFieldEventBehavior eventBehavior)
999 {
1000     if (isFileUpload() && !value.isEmpty()) {
1001         exceptionState.throwDOMException(InvalidStateError, "This input element accepts a filename, which may only be programatically set to the empty string.");
1002         return;
1003     }
1004     setValue(value, eventBehavior);
1005 }
1006 
setValue(const String & value,TextFieldEventBehavior eventBehavior)1007 void HTMLInputElement::setValue(const String& value, TextFieldEventBehavior eventBehavior)
1008 {
1009     if (!m_inputType->canSetValue(value))
1010         return;
1011 
1012     RefPtr<HTMLInputElement> protector(this);
1013     EventQueueScope scope;
1014     String sanitizedValue = sanitizeValue(value);
1015     bool valueChanged = sanitizedValue != this->value();
1016 
1017     setLastChangeWasNotUserEdit();
1018     setFormControlValueMatchesRenderer(false);
1019     m_suggestedValue = String(); // Prevent TextFieldInputType::setValue from using the suggested value.
1020 
1021     m_inputType->setValue(sanitizedValue, valueChanged, eventBehavior);
1022 
1023     if (valueChanged && eventBehavior == DispatchNoEvent)
1024         setTextAsOfLastFormControlChangeEvent(sanitizedValue);
1025 
1026     if (!valueChanged)
1027         return;
1028 
1029     notifyFormStateChanged();
1030 }
1031 
setValueInternal(const String & sanitizedValue,TextFieldEventBehavior eventBehavior)1032 void HTMLInputElement::setValueInternal(const String& sanitizedValue, TextFieldEventBehavior eventBehavior)
1033 {
1034     m_valueIfDirty = sanitizedValue;
1035     setNeedsValidityCheck();
1036 }
1037 
valueAsDate() const1038 double HTMLInputElement::valueAsDate() const
1039 {
1040     return m_inputType->valueAsDate();
1041 }
1042 
setValueAsDate(double value,ExceptionState & exceptionState)1043 void HTMLInputElement::setValueAsDate(double value, ExceptionState& exceptionState)
1044 {
1045     m_inputType->setValueAsDate(value, exceptionState);
1046 }
1047 
valueAsNumber() const1048 double HTMLInputElement::valueAsNumber() const
1049 {
1050     return m_inputType->valueAsDouble();
1051 }
1052 
setValueAsNumber(double newValue,ExceptionState & exceptionState,TextFieldEventBehavior eventBehavior)1053 void HTMLInputElement::setValueAsNumber(double newValue, ExceptionState& exceptionState, TextFieldEventBehavior eventBehavior)
1054 {
1055     if (!std::isfinite(newValue)) {
1056         exceptionState.throwDOMException(NotSupportedError, ExceptionMessages::notAFiniteNumber(newValue));
1057         return;
1058     }
1059     m_inputType->setValueAsDouble(newValue, eventBehavior, exceptionState);
1060 }
1061 
setValueFromRenderer(const String & value)1062 void HTMLInputElement::setValueFromRenderer(const String& value)
1063 {
1064     // File upload controls will never use this.
1065     ASSERT(!isFileUpload());
1066 
1067     m_suggestedValue = String();
1068 
1069     // Renderer and our event handler are responsible for sanitizing values.
1070     ASSERT(value == sanitizeValue(value) || sanitizeValue(value).isEmpty());
1071 
1072     m_valueIfDirty = value;
1073 
1074     setFormControlValueMatchesRenderer(true);
1075 
1076     // Input event is fired by the Node::defaultEventHandler for editable controls.
1077     if (!isTextField())
1078         dispatchInputEvent();
1079     notifyFormStateChanged();
1080 
1081     setNeedsValidityCheck();
1082 
1083     // Clear autofill flag (and yellow background) on user edit.
1084     setAutofilled(false);
1085 }
1086 
preDispatchEventHandler(Event * event)1087 void* HTMLInputElement::preDispatchEventHandler(Event* event)
1088 {
1089     if (event->type() == EventTypeNames::textInput && m_inputTypeView->shouldSubmitImplicitly(event)) {
1090         event->stopPropagation();
1091         return 0;
1092     }
1093     if (event->type() != EventTypeNames::click)
1094         return 0;
1095     if (!event->isMouseEvent() || toMouseEvent(event)->button() != LeftButton)
1096         return 0;
1097     // FIXME: Check whether there are any cases where this actually ends up leaking.
1098     return m_inputTypeView->willDispatchClick().leakPtr();
1099 }
1100 
postDispatchEventHandler(Event * event,void * dataFromPreDispatch)1101 void HTMLInputElement::postDispatchEventHandler(Event* event, void* dataFromPreDispatch)
1102 {
1103     OwnPtr<ClickHandlingState> state = adoptPtr(static_cast<ClickHandlingState*>(dataFromPreDispatch));
1104     if (!state)
1105         return;
1106     m_inputTypeView->didDispatchClick(event, *state);
1107 }
1108 
defaultEventHandler(Event * evt)1109 void HTMLInputElement::defaultEventHandler(Event* evt)
1110 {
1111     if (evt->isMouseEvent() && evt->type() == EventTypeNames::click && toMouseEvent(evt)->button() == LeftButton) {
1112         m_inputTypeView->handleClickEvent(toMouseEvent(evt));
1113         if (evt->defaultHandled())
1114             return;
1115     }
1116 
1117     if (evt->isTouchEvent()) {
1118         m_inputTypeView->handleTouchEvent(toTouchEvent(evt));
1119         if (evt->defaultHandled())
1120             return;
1121     }
1122 
1123     if (evt->isKeyboardEvent() && evt->type() == EventTypeNames::keydown) {
1124         m_inputTypeView->handleKeydownEvent(toKeyboardEvent(evt));
1125         if (evt->defaultHandled())
1126             return;
1127     }
1128 
1129     // Call the base event handler before any of our own event handling for almost all events in text fields.
1130     // Makes editing keyboard handling take precedence over the keydown and keypress handling in this function.
1131     bool callBaseClassEarly = isTextField() && (evt->type() == EventTypeNames::keydown || evt->type() == EventTypeNames::keypress);
1132     if (callBaseClassEarly) {
1133         HTMLTextFormControlElement::defaultEventHandler(evt);
1134         if (evt->defaultHandled())
1135             return;
1136     }
1137 
1138     // DOMActivate events cause the input to be "activated" - in the case of image and submit inputs, this means
1139     // actually submitting the form. For reset inputs, the form is reset. These events are sent when the user clicks
1140     // on the element, or presses enter while it is the active element. JavaScript code wishing to activate the element
1141     // must dispatch a DOMActivate event - a click event will not do the job.
1142     if (evt->type() == EventTypeNames::DOMActivate) {
1143         m_inputType->handleDOMActivateEvent(evt);
1144         if (evt->defaultHandled())
1145             return;
1146     }
1147 
1148     // Use key press event here since sending simulated mouse events
1149     // on key down blocks the proper sending of the key press event.
1150     if (evt->isKeyboardEvent() && evt->type() == EventTypeNames::keypress) {
1151         m_inputTypeView->handleKeypressEvent(toKeyboardEvent(evt));
1152         if (evt->defaultHandled())
1153             return;
1154     }
1155 
1156     if (evt->isKeyboardEvent() && evt->type() == EventTypeNames::keyup) {
1157         m_inputTypeView->handleKeyupEvent(toKeyboardEvent(evt));
1158         if (evt->defaultHandled())
1159             return;
1160     }
1161 
1162     if (m_inputTypeView->shouldSubmitImplicitly(evt)) {
1163         if (isSearchField())
1164             onSearch();
1165         // Form submission finishes editing, just as loss of focus does.
1166         // If there was a change, send the event now.
1167         if (wasChangedSinceLastFormControlChangeEvent())
1168             dispatchFormControlChangeEvent();
1169 
1170         RefPtr<HTMLFormElement> formForSubmission = m_inputTypeView->formForSubmission();
1171         // Form may never have been present, or may have been destroyed by code responding to the change event.
1172         if (formForSubmission)
1173             formForSubmission->submitImplicitly(evt, canTriggerImplicitSubmission());
1174 
1175         evt->setDefaultHandled();
1176         return;
1177     }
1178 
1179     if (evt->isBeforeTextInsertedEvent())
1180         m_inputTypeView->handleBeforeTextInsertedEvent(static_cast<BeforeTextInsertedEvent*>(evt));
1181 
1182     if (evt->isMouseEvent() && evt->type() == EventTypeNames::mousedown) {
1183         m_inputTypeView->handleMouseDownEvent(toMouseEvent(evt));
1184         if (evt->defaultHandled())
1185             return;
1186     }
1187 
1188     m_inputTypeView->forwardEvent(evt);
1189 
1190     if (!callBaseClassEarly && !evt->defaultHandled())
1191         HTMLTextFormControlElement::defaultEventHandler(evt);
1192 }
1193 
willRespondToMouseClickEvents()1194 bool HTMLInputElement::willRespondToMouseClickEvents()
1195 {
1196     // FIXME: Consider implementing willRespondToMouseClickEvents() in InputType if more accurate results are necessary.
1197     if (!isDisabledFormControl())
1198         return true;
1199 
1200     return HTMLTextFormControlElement::willRespondToMouseClickEvents();
1201 }
1202 
isURLAttribute(const Attribute & attribute) const1203 bool HTMLInputElement::isURLAttribute(const Attribute& attribute) const
1204 {
1205     return attribute.name() == srcAttr || attribute.name() == formactionAttr || HTMLTextFormControlElement::isURLAttribute(attribute);
1206 }
1207 
defaultValue() const1208 const AtomicString& HTMLInputElement::defaultValue() const
1209 {
1210     return fastGetAttribute(valueAttr);
1211 }
1212 
setDefaultValue(const AtomicString & value)1213 void HTMLInputElement::setDefaultValue(const AtomicString& value)
1214 {
1215     setAttribute(valueAttr, value);
1216 }
1217 
isRFC2616TokenCharacter(UChar ch)1218 static inline bool isRFC2616TokenCharacter(UChar ch)
1219 {
1220     return isASCII(ch) && ch > ' ' && ch != '"' && ch != '(' && ch != ')' && ch != ',' && ch != '/' && (ch < ':' || ch > '@') && (ch < '[' || ch > ']') && ch != '{' && ch != '}' && ch != 0x7f;
1221 }
1222 
isValidMIMEType(const String & type)1223 static bool isValidMIMEType(const String& type)
1224 {
1225     size_t slashPosition = type.find('/');
1226     if (slashPosition == kNotFound || !slashPosition || slashPosition == type.length() - 1)
1227         return false;
1228     for (size_t i = 0; i < type.length(); ++i) {
1229         if (!isRFC2616TokenCharacter(type[i]) && i != slashPosition)
1230             return false;
1231     }
1232     return true;
1233 }
1234 
isValidFileExtension(const String & type)1235 static bool isValidFileExtension(const String& type)
1236 {
1237     if (type.length() < 2)
1238         return false;
1239     return type[0] == '.';
1240 }
1241 
parseAcceptAttribute(const String & acceptString,bool (* predicate)(const String &))1242 static Vector<String> parseAcceptAttribute(const String& acceptString, bool (*predicate)(const String&))
1243 {
1244     Vector<String> types;
1245     if (acceptString.isEmpty())
1246         return types;
1247 
1248     Vector<String> splitTypes;
1249     acceptString.split(',', false, splitTypes);
1250     for (size_t i = 0; i < splitTypes.size(); ++i) {
1251         String trimmedType = stripLeadingAndTrailingHTMLSpaces(splitTypes[i]);
1252         if (trimmedType.isEmpty())
1253             continue;
1254         if (!predicate(trimmedType))
1255             continue;
1256         types.append(trimmedType.lower());
1257     }
1258 
1259     return types;
1260 }
1261 
acceptMIMETypes()1262 Vector<String> HTMLInputElement::acceptMIMETypes()
1263 {
1264     return parseAcceptAttribute(fastGetAttribute(acceptAttr), isValidMIMEType);
1265 }
1266 
acceptFileExtensions()1267 Vector<String> HTMLInputElement::acceptFileExtensions()
1268 {
1269     return parseAcceptAttribute(fastGetAttribute(acceptAttr), isValidFileExtension);
1270 }
1271 
accept() const1272 const AtomicString& HTMLInputElement::accept() const
1273 {
1274     return fastGetAttribute(acceptAttr);
1275 }
1276 
alt() const1277 const AtomicString& HTMLInputElement::alt() const
1278 {
1279     return fastGetAttribute(altAttr);
1280 }
1281 
maxLength() const1282 int HTMLInputElement::maxLength() const
1283 {
1284     return m_maxLength;
1285 }
1286 
setMaxLength(int maxLength,ExceptionState & exceptionState)1287 void HTMLInputElement::setMaxLength(int maxLength, ExceptionState& exceptionState)
1288 {
1289     if (maxLength < 0)
1290         exceptionState.throwDOMException(IndexSizeError, "The value provided (" + String::number(maxLength) + ") is negative.");
1291     else
1292         setIntegralAttribute(maxlengthAttr, maxLength);
1293 }
1294 
multiple() const1295 bool HTMLInputElement::multiple() const
1296 {
1297     return fastHasAttribute(multipleAttr);
1298 }
1299 
setSize(unsigned size)1300 void HTMLInputElement::setSize(unsigned size)
1301 {
1302     setUnsignedIntegralAttribute(sizeAttr, size);
1303 }
1304 
setSize(unsigned size,ExceptionState & exceptionState)1305 void HTMLInputElement::setSize(unsigned size, ExceptionState& exceptionState)
1306 {
1307     if (!size)
1308         exceptionState.throwDOMException(IndexSizeError, "The value provided is 0, which is an invalid size.");
1309     else
1310         setSize(size);
1311 }
1312 
src() const1313 KURL HTMLInputElement::src() const
1314 {
1315     return document().completeURL(fastGetAttribute(srcAttr));
1316 }
1317 
files()1318 FileList* HTMLInputElement::files()
1319 {
1320     return m_inputType->files();
1321 }
1322 
setFiles(PassRefPtr<FileList> files)1323 void HTMLInputElement::setFiles(PassRefPtr<FileList> files)
1324 {
1325     m_inputType->setFiles(files);
1326 }
1327 
receiveDroppedFiles(const DragData * dragData)1328 bool HTMLInputElement::receiveDroppedFiles(const DragData* dragData)
1329 {
1330     return m_inputType->receiveDroppedFiles(dragData);
1331 }
1332 
droppedFileSystemId()1333 String HTMLInputElement::droppedFileSystemId()
1334 {
1335     return m_inputType->droppedFileSystemId();
1336 }
1337 
canReceiveDroppedFiles() const1338 bool HTMLInputElement::canReceiveDroppedFiles() const
1339 {
1340     return m_canReceiveDroppedFiles;
1341 }
1342 
setCanReceiveDroppedFiles(bool canReceiveDroppedFiles)1343 void HTMLInputElement::setCanReceiveDroppedFiles(bool canReceiveDroppedFiles)
1344 {
1345     if (m_canReceiveDroppedFiles == canReceiveDroppedFiles)
1346         return;
1347     m_canReceiveDroppedFiles = canReceiveDroppedFiles;
1348     if (renderer())
1349         renderer()->updateFromElement();
1350 }
1351 
visibleValue() const1352 String HTMLInputElement::visibleValue() const
1353 {
1354     return m_inputType->visibleValue();
1355 }
1356 
sanitizeValue(const String & proposedValue) const1357 String HTMLInputElement::sanitizeValue(const String& proposedValue) const
1358 {
1359     if (proposedValue.isNull())
1360         return proposedValue;
1361     return m_inputType->sanitizeValue(proposedValue);
1362 }
1363 
localizeValue(const String & proposedValue) const1364 String HTMLInputElement::localizeValue(const String& proposedValue) const
1365 {
1366     if (proposedValue.isNull())
1367         return proposedValue;
1368     return m_inputType->localizeValue(proposedValue);
1369 }
1370 
isInRange() const1371 bool HTMLInputElement::isInRange() const
1372 {
1373     return m_inputType->isInRange(value());
1374 }
1375 
isOutOfRange() const1376 bool HTMLInputElement::isOutOfRange() const
1377 {
1378     return m_inputType->isOutOfRange(value());
1379 }
1380 
isRequiredFormControl() const1381 bool HTMLInputElement::isRequiredFormControl() const
1382 {
1383     return m_inputType->supportsRequired() && isRequired();
1384 }
1385 
matchesReadOnlyPseudoClass() const1386 bool HTMLInputElement::matchesReadOnlyPseudoClass() const
1387 {
1388     return m_inputType->supportsReadOnly() && isReadOnly();
1389 }
1390 
matchesReadWritePseudoClass() const1391 bool HTMLInputElement::matchesReadWritePseudoClass() const
1392 {
1393     return m_inputType->supportsReadOnly() && !isReadOnly();
1394 }
1395 
onSearch()1396 void HTMLInputElement::onSearch()
1397 {
1398     ASSERT(isSearchField());
1399     if (m_inputType)
1400         static_cast<SearchInputType*>(m_inputType.get())->stopSearchEventTimer();
1401     dispatchEvent(Event::createBubble(EventTypeNames::search));
1402 }
1403 
updateClearButtonVisibility()1404 void HTMLInputElement::updateClearButtonVisibility()
1405 {
1406     m_inputTypeView->updateClearButtonVisibility();
1407 }
1408 
willChangeForm()1409 void HTMLInputElement::willChangeForm()
1410 {
1411     removeFromRadioButtonGroup();
1412     HTMLTextFormControlElement::willChangeForm();
1413 }
1414 
didChangeForm()1415 void HTMLInputElement::didChangeForm()
1416 {
1417     HTMLTextFormControlElement::didChangeForm();
1418     addToRadioButtonGroup();
1419 }
1420 
insertedInto(ContainerNode * insertionPoint)1421 Node::InsertionNotificationRequest HTMLInputElement::insertedInto(ContainerNode* insertionPoint)
1422 {
1423     HTMLTextFormControlElement::insertedInto(insertionPoint);
1424     if (insertionPoint->inDocument() && !form())
1425         addToRadioButtonGroup();
1426     resetListAttributeTargetObserver();
1427     return InsertionDone;
1428 }
1429 
removedFrom(ContainerNode * insertionPoint)1430 void HTMLInputElement::removedFrom(ContainerNode* insertionPoint)
1431 {
1432     if (insertionPoint->inDocument() && !form())
1433         removeFromRadioButtonGroup();
1434     HTMLTextFormControlElement::removedFrom(insertionPoint);
1435     ASSERT(!inDocument());
1436     resetListAttributeTargetObserver();
1437 }
1438 
didMoveToNewDocument(Document & oldDocument)1439 void HTMLInputElement::didMoveToNewDocument(Document& oldDocument)
1440 {
1441     if (hasImageLoader())
1442         imageLoader()->elementDidMoveToNewDocument();
1443 
1444     if (isRadioButton())
1445         oldDocument.formController()->checkedRadioButtons().removeButton(this);
1446     if (m_hasTouchEventHandler)
1447         oldDocument.didRemoveEventTargetNode(this);
1448 
1449     if (m_hasTouchEventHandler)
1450         document().didAddTouchEventHandler(this);
1451 
1452     HTMLTextFormControlElement::didMoveToNewDocument(oldDocument);
1453 }
1454 
addSubresourceAttributeURLs(ListHashSet<KURL> & urls) const1455 void HTMLInputElement::addSubresourceAttributeURLs(ListHashSet<KURL>& urls) const
1456 {
1457     HTMLTextFormControlElement::addSubresourceAttributeURLs(urls);
1458 
1459     addSubresourceURL(urls, src());
1460 }
1461 
recalcWillValidate() const1462 bool HTMLInputElement::recalcWillValidate() const
1463 {
1464     return m_inputType->supportsValidation() && HTMLTextFormControlElement::recalcWillValidate();
1465 }
1466 
requiredAttributeChanged()1467 void HTMLInputElement::requiredAttributeChanged()
1468 {
1469     HTMLTextFormControlElement::requiredAttributeChanged();
1470     if (CheckedRadioButtons* buttons = checkedRadioButtons())
1471         buttons->requiredAttributeChanged(this);
1472     m_inputTypeView->requiredAttributeChanged();
1473 }
1474 
selectColorInColorChooser(const Color & color)1475 void HTMLInputElement::selectColorInColorChooser(const Color& color)
1476 {
1477     if (!m_inputType->isColorControl())
1478         return;
1479     static_cast<ColorInputType*>(m_inputType.get())->didChooseColor(color);
1480 }
1481 
list() const1482 HTMLElement* HTMLInputElement::list() const
1483 {
1484     return dataList();
1485 }
1486 
dataList() const1487 HTMLDataListElement* HTMLInputElement::dataList() const
1488 {
1489     if (!m_hasNonEmptyList)
1490         return 0;
1491 
1492     if (!m_inputType->shouldRespectListAttribute())
1493         return 0;
1494 
1495     Element* element = treeScope().getElementById(fastGetAttribute(listAttr));
1496     if (!element)
1497         return 0;
1498     if (!element->hasTagName(datalistTag))
1499         return 0;
1500 
1501     return toHTMLDataListElement(element);
1502 }
1503 
hasValidDataListOptions() const1504 bool HTMLInputElement::hasValidDataListOptions() const
1505 {
1506     HTMLDataListElement* dataList = this->dataList();
1507     if (!dataList)
1508         return false;
1509     RefPtr<HTMLCollection> options = dataList->options();
1510     for (unsigned i = 0; HTMLOptionElement* option = toHTMLOptionElement(options->item(i)); ++i) {
1511         if (isValidValue(option->value()))
1512             return true;
1513     }
1514     return false;
1515 }
1516 
resetListAttributeTargetObserver()1517 void HTMLInputElement::resetListAttributeTargetObserver()
1518 {
1519     if (inDocument())
1520         m_listAttributeTargetObserver = ListAttributeTargetObserver::create(fastGetAttribute(listAttr), this);
1521     else
1522         m_listAttributeTargetObserver = nullptr;
1523 }
1524 
listAttributeTargetChanged()1525 void HTMLInputElement::listAttributeTargetChanged()
1526 {
1527     m_inputTypeView->listAttributeTargetChanged();
1528 }
1529 
isSteppable() const1530 bool HTMLInputElement::isSteppable() const
1531 {
1532     return m_inputType->isSteppable();
1533 }
1534 
1535 #if ENABLE(INPUT_SPEECH)
1536 
isSpeechEnabled() const1537 bool HTMLInputElement::isSpeechEnabled() const
1538 {
1539     // FIXME: Add support for RANGE, EMAIL, URL, COLOR and DATE/TIME input types.
1540     return m_inputType->shouldRespectSpeechAttribute() && RuntimeEnabledFeatures::speechInputEnabled() && hasAttribute(webkitspeechAttr);
1541 }
1542 
1543 #endif
1544 
isTextButton() const1545 bool HTMLInputElement::isTextButton() const
1546 {
1547     return m_inputType->isTextButton();
1548 }
1549 
isRadioButton() const1550 bool HTMLInputElement::isRadioButton() const
1551 {
1552     return m_inputType->isRadioButton();
1553 }
1554 
isSearchField() const1555 bool HTMLInputElement::isSearchField() const
1556 {
1557     return m_inputType->isSearchField();
1558 }
1559 
isInputTypeHidden() const1560 bool HTMLInputElement::isInputTypeHidden() const
1561 {
1562     return m_inputType->isHiddenType();
1563 }
1564 
isPasswordField() const1565 bool HTMLInputElement::isPasswordField() const
1566 {
1567     return m_inputType->isPasswordField();
1568 }
1569 
isCheckbox() const1570 bool HTMLInputElement::isCheckbox() const
1571 {
1572     return m_inputType->isCheckbox();
1573 }
1574 
isRangeControl() const1575 bool HTMLInputElement::isRangeControl() const
1576 {
1577     return m_inputType->isRangeControl();
1578 }
1579 
isColorControl() const1580 bool HTMLInputElement::isColorControl() const
1581 {
1582     return m_inputType->isColorControl();
1583 }
1584 
isText() const1585 bool HTMLInputElement::isText() const
1586 {
1587     return m_inputType->isTextType();
1588 }
1589 
isEmailField() const1590 bool HTMLInputElement::isEmailField() const
1591 {
1592     return m_inputType->isEmailField();
1593 }
1594 
isFileUpload() const1595 bool HTMLInputElement::isFileUpload() const
1596 {
1597     return m_inputType->isFileUpload();
1598 }
1599 
isImageButton() const1600 bool HTMLInputElement::isImageButton() const
1601 {
1602     return m_inputType->isImageButton();
1603 }
1604 
isNumberField() const1605 bool HTMLInputElement::isNumberField() const
1606 {
1607     return m_inputType->isNumberField();
1608 }
1609 
isSubmitButton() const1610 bool HTMLInputElement::isSubmitButton() const
1611 {
1612     return m_inputType->isSubmitButton();
1613 }
1614 
isTelephoneField() const1615 bool HTMLInputElement::isTelephoneField() const
1616 {
1617     return m_inputType->isTelephoneField();
1618 }
1619 
isURLField() const1620 bool HTMLInputElement::isURLField() const
1621 {
1622     return m_inputType->isURLField();
1623 }
1624 
isDateField() const1625 bool HTMLInputElement::isDateField() const
1626 {
1627     return m_inputType->isDateField();
1628 }
1629 
isDateTimeLocalField() const1630 bool HTMLInputElement::isDateTimeLocalField() const
1631 {
1632     return m_inputType->isDateTimeLocalField();
1633 }
1634 
isMonthField() const1635 bool HTMLInputElement::isMonthField() const
1636 {
1637     return m_inputType->isMonthField();
1638 }
1639 
isTimeField() const1640 bool HTMLInputElement::isTimeField() const
1641 {
1642     return m_inputType->isTimeField();
1643 }
1644 
isWeekField() const1645 bool HTMLInputElement::isWeekField() const
1646 {
1647     return m_inputType->isWeekField();
1648 }
1649 
isEnumeratable() const1650 bool HTMLInputElement::isEnumeratable() const
1651 {
1652     return m_inputType->isEnumeratable();
1653 }
1654 
supportLabels() const1655 bool HTMLInputElement::supportLabels() const
1656 {
1657     return m_inputType->isInteractiveContent();
1658 }
1659 
shouldAppearChecked() const1660 bool HTMLInputElement::shouldAppearChecked() const
1661 {
1662     return checked() && m_inputType->isCheckable();
1663 }
1664 
supportsPlaceholder() const1665 bool HTMLInputElement::supportsPlaceholder() const
1666 {
1667     return m_inputType->supportsPlaceholder();
1668 }
1669 
updatePlaceholderText()1670 void HTMLInputElement::updatePlaceholderText()
1671 {
1672     return m_inputType->updatePlaceholderText();
1673 }
1674 
parseMaxLengthAttribute(const AtomicString & value)1675 void HTMLInputElement::parseMaxLengthAttribute(const AtomicString& value)
1676 {
1677     int maxLength;
1678     if (!parseHTMLInteger(value, maxLength))
1679         maxLength = maximumLength;
1680     if (maxLength < 0 || maxLength > maximumLength)
1681         maxLength = maximumLength;
1682     int oldMaxLength = m_maxLength;
1683     m_maxLength = maxLength;
1684     if (oldMaxLength != maxLength)
1685         updateValueIfNeeded();
1686     setNeedsStyleRecalc();
1687     setNeedsValidityCheck();
1688 }
1689 
updateValueIfNeeded()1690 void HTMLInputElement::updateValueIfNeeded()
1691 {
1692     String newValue = sanitizeValue(m_valueIfDirty);
1693     ASSERT(!m_valueIfDirty.isNull() || newValue.isNull());
1694     if (newValue != m_valueIfDirty)
1695         setValue(newValue);
1696 }
1697 
defaultToolTip() const1698 String HTMLInputElement::defaultToolTip() const
1699 {
1700     return m_inputType->defaultToolTip();
1701 }
1702 
shouldAppearIndeterminate() const1703 bool HTMLInputElement::shouldAppearIndeterminate() const
1704 {
1705     return m_inputType->supportsIndeterminateAppearance() && indeterminate();
1706 }
1707 
1708 #if ENABLE(MEDIA_CAPTURE)
capture() const1709 bool HTMLInputElement::capture() const
1710 {
1711     if (!isFileUpload() || !fastHasAttribute(captureAttr))
1712         return false;
1713 
1714     // As per crbug.com/240252, emit a deprecation warning when the "capture"
1715     // attribute is used as an enum. The spec has been updated and "capture" is
1716     // supposed to be used as a boolean.
1717     bool hasDeprecatedUsage = !fastGetAttribute(captureAttr).isNull();
1718     if (hasDeprecatedUsage)
1719         UseCounter::countDeprecation(document(), UseCounter::CaptureAttributeAsEnum);
1720     else
1721         UseCounter::count(document(), UseCounter::CaptureAttributeAsEnum);
1722 
1723     return true;
1724 }
1725 #endif
1726 
isInRequiredRadioButtonGroup()1727 bool HTMLInputElement::isInRequiredRadioButtonGroup()
1728 {
1729     ASSERT(isRadioButton());
1730     if (CheckedRadioButtons* buttons = checkedRadioButtons())
1731         return buttons->isInRequiredGroup(this);
1732     return false;
1733 }
1734 
checkedRadioButtonForGroup() const1735 HTMLInputElement* HTMLInputElement::checkedRadioButtonForGroup() const
1736 {
1737     if (CheckedRadioButtons* buttons = checkedRadioButtons())
1738         return buttons->checkedButtonForGroup(name());
1739     return 0;
1740 }
1741 
checkedRadioButtons() const1742 CheckedRadioButtons* HTMLInputElement::checkedRadioButtons() const
1743 {
1744     if (!isRadioButton())
1745         return 0;
1746     if (HTMLFormElement* formElement = form())
1747         return &formElement->checkedRadioButtons();
1748     if (inDocument())
1749         return &document().formController()->checkedRadioButtons();
1750     return 0;
1751 }
1752 
addToRadioButtonGroup()1753 inline void HTMLInputElement::addToRadioButtonGroup()
1754 {
1755     if (CheckedRadioButtons* buttons = checkedRadioButtons())
1756         buttons->addButton(this);
1757 }
1758 
removeFromRadioButtonGroup()1759 inline void HTMLInputElement::removeFromRadioButtonGroup()
1760 {
1761     if (CheckedRadioButtons* buttons = checkedRadioButtons())
1762         buttons->removeButton(this);
1763 }
1764 
height() const1765 unsigned HTMLInputElement::height() const
1766 {
1767     return m_inputType->height();
1768 }
1769 
width() const1770 unsigned HTMLInputElement::width() const
1771 {
1772     return m_inputType->width();
1773 }
1774 
setHeight(unsigned height)1775 void HTMLInputElement::setHeight(unsigned height)
1776 {
1777     setUnsignedIntegralAttribute(heightAttr, height);
1778 }
1779 
setWidth(unsigned width)1780 void HTMLInputElement::setWidth(unsigned width)
1781 {
1782     setUnsignedIntegralAttribute(widthAttr, width);
1783 }
1784 
create(const AtomicString & id,HTMLInputElement * element)1785 PassOwnPtr<ListAttributeTargetObserver> ListAttributeTargetObserver::create(const AtomicString& id, HTMLInputElement* element)
1786 {
1787     return adoptPtr(new ListAttributeTargetObserver(id, element));
1788 }
1789 
ListAttributeTargetObserver(const AtomicString & id,HTMLInputElement * element)1790 ListAttributeTargetObserver::ListAttributeTargetObserver(const AtomicString& id, HTMLInputElement* element)
1791     : IdTargetObserver(element->treeScope().idTargetObserverRegistry(), id)
1792     , m_element(element)
1793 {
1794 }
1795 
idTargetChanged()1796 void ListAttributeTargetObserver::idTargetChanged()
1797 {
1798     m_element->listAttributeTargetChanged();
1799 }
1800 
setRangeText(const String & replacement,ExceptionState & exceptionState)1801 void HTMLInputElement::setRangeText(const String& replacement, ExceptionState& exceptionState)
1802 {
1803     if (!m_inputType->supportsSelectionAPI()) {
1804         exceptionState.throwDOMException(InvalidStateError, "The input element's type ('" + m_inputType->formControlType() + "') does not support selection.");
1805         return;
1806     }
1807 
1808     HTMLTextFormControlElement::setRangeText(replacement, exceptionState);
1809 }
1810 
setRangeText(const String & replacement,unsigned start,unsigned end,const String & selectionMode,ExceptionState & exceptionState)1811 void HTMLInputElement::setRangeText(const String& replacement, unsigned start, unsigned end, const String& selectionMode, ExceptionState& exceptionState)
1812 {
1813     if (!m_inputType->supportsSelectionAPI()) {
1814         exceptionState.throwDOMException(InvalidStateError, "The input element's type ('" + m_inputType->formControlType() + "') does not support selection.");
1815         return;
1816     }
1817 
1818     HTMLTextFormControlElement::setRangeText(replacement, start, end, selectionMode, exceptionState);
1819 }
1820 
setupDateTimeChooserParameters(DateTimeChooserParameters & parameters)1821 bool HTMLInputElement::setupDateTimeChooserParameters(DateTimeChooserParameters& parameters)
1822 {
1823     if (!document().view())
1824         return false;
1825 
1826     parameters.type = type();
1827     parameters.minimum = minimum();
1828     parameters.maximum = maximum();
1829     parameters.required = isRequired();
1830     if (!RuntimeEnabledFeatures::langAttributeAwareFormControlUIEnabled())
1831         parameters.locale = defaultLanguage();
1832     else {
1833         AtomicString computedLocale = computeInheritedLanguage();
1834         parameters.locale = computedLocale.isEmpty() ? AtomicString(defaultLanguage()) : computedLocale;
1835     }
1836 
1837     StepRange stepRange = createStepRange(RejectAny);
1838     if (stepRange.hasStep()) {
1839         parameters.step = stepRange.step().toDouble();
1840         parameters.stepBase = stepRange.stepBase().toDouble();
1841     } else {
1842         parameters.step = 1.0;
1843         parameters.stepBase = 0;
1844     }
1845 
1846     parameters.anchorRectInRootView = document().view()->contentsToRootView(pixelSnappedBoundingBox());
1847     parameters.currentValue = value();
1848     parameters.doubleValue = m_inputType->valueAsDouble();
1849     parameters.isAnchorElementRTL = computedStyle()->direction() == RTL;
1850     if (RuntimeEnabledFeatures::dataListElementEnabled()) {
1851         if (HTMLDataListElement* dataList = this->dataList()) {
1852             RefPtr<HTMLCollection> options = dataList->options();
1853             for (unsigned i = 0; HTMLOptionElement* option = toHTMLOptionElement(options->item(i)); ++i) {
1854                 if (!isValidValue(option->value()))
1855                     continue;
1856                 DateTimeSuggestion suggestion;
1857                 suggestion.value = m_inputType->parseToNumber(option->value(), Decimal::nan()).toDouble();
1858                 if (std::isnan(suggestion.value))
1859                     continue;
1860                 suggestion.localizedValue = localizeValue(option->value());
1861                 suggestion.label = option->value() == option->label() ? String() : option->label();
1862                 parameters.suggestions.append(suggestion);
1863             }
1864         }
1865     }
1866     return true;
1867 }
1868 
supportsInputModeAttribute() const1869 bool HTMLInputElement::supportsInputModeAttribute() const
1870 {
1871     return m_inputType->supportsInputModeAttribute();
1872 }
1873 
isInteractiveContent() const1874 bool HTMLInputElement::isInteractiveContent() const
1875 {
1876     return m_inputType->isInteractiveContent();
1877 }
1878 
1879 #if ENABLE(INPUT_MULTIPLE_FIELDS_UI)
customStyleForRenderer()1880 PassRefPtr<RenderStyle> HTMLInputElement::customStyleForRenderer()
1881 {
1882     return m_inputTypeView->customStyleForRenderer(originalStyleForRenderer());
1883 }
1884 #endif
1885 
1886 } // namespace
1887