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