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 *
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Library General Public
12 * License as published by the Free Software Foundation; either
13 * version 2 of the License, or (at your option) any later version.
14 *
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public License
21 * along with this library; see the file COPYING.LIB. If not, write to
22 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
23 * Boston, MA 02110-1301, USA.
24 *
25 */
26
27 #include "config.h"
28 #include "HTMLInputElement.h"
29
30 #include "AXObjectCache.h"
31 #include "Attribute.h"
32 #include "BeforeTextInsertedEvent.h"
33 #include "CSSPropertyNames.h"
34 #include "Document.h"
35 #include "EventNames.h"
36 #include "ExceptionCode.h"
37 #include "FileList.h"
38 #include "HTMLCollection.h"
39 #include "HTMLDataListElement.h"
40 #include "HTMLFormElement.h"
41 #include "HTMLNames.h"
42 #include "HTMLOptionElement.h"
43 #include "HTMLParserIdioms.h"
44 #include "InputType.h"
45 #include "KeyboardEvent.h"
46 #include "LocalizedStrings.h"
47 #include "MouseEvent.h"
48 #include "PlatformMouseEvent.h"
49 #include "RenderTextControlSingleLine.h"
50 #include "RenderTheme.h"
51 #include "RuntimeEnabledFeatures.h"
52 #include "ScriptEventListener.h"
53 #include "WheelEvent.h"
54 #include <wtf/MathExtras.h>
55 #include <wtf/StdLibExtras.h>
56
57 #ifdef ANDROID_ACCEPT_CHANGES_TO_FOCUSED_TEXTFIELDS
58 #include "PlatformBridge.h"
59 #endif
60
61 #if PLATFORM(ANDROID) && ENABLE(TOUCH_EVENTS)
62 #include "TouchEvent.h"
63 #endif
64
65 using namespace std;
66
67 namespace WebCore {
68
69 using namespace HTMLNames;
70
71 const int maxSavedResults = 256;
72
HTMLInputElement(const QualifiedName & tagName,Document * document,HTMLFormElement * form,bool createdByParser)73 HTMLInputElement::HTMLInputElement(const QualifiedName& tagName, Document* document, HTMLFormElement* form, bool createdByParser)
74 : HTMLTextFormControlElement(tagName, document, form)
75 , m_maxResults(-1)
76 , m_isChecked(false)
77 , m_reflectsCheckedAttribute(true)
78 , m_isIndeterminate(false)
79 , m_hasType(false)
80 , m_isActivatedSubmit(false)
81 , m_autocomplete(Uninitialized)
82 , m_isAutofilled(false)
83 , m_stateRestored(false)
84 , m_parsingInProgress(createdByParser)
85 , m_inputType(InputType::createText(this))
86 {
87 ASSERT(hasTagName(inputTag) || hasTagName(isindexTag));
88 }
89
create(const QualifiedName & tagName,Document * document,HTMLFormElement * form,bool createdByParser)90 PassRefPtr<HTMLInputElement> HTMLInputElement::create(const QualifiedName& tagName, Document* document, HTMLFormElement* form, bool createdByParser)
91 {
92 return adoptRef(new HTMLInputElement(tagName, document, form, createdByParser));
93 }
94
~HTMLInputElement()95 HTMLInputElement::~HTMLInputElement()
96 {
97 if (needsActivationCallback())
98 document()->unregisterForDocumentActivationCallbacks(this);
99
100 document()->checkedRadioButtons().removeButton(this);
101
102 // Need to remove this from the form while it is still an HTMLInputElement,
103 // so can't wait for the base class's destructor to do it.
104 removeFromForm();
105 }
106
formControlName() const107 const AtomicString& HTMLInputElement::formControlName() const
108 {
109 return m_data.name();
110 }
111
autoComplete() const112 bool HTMLInputElement::autoComplete() const
113 {
114 if (m_autocomplete != Uninitialized)
115 return m_autocomplete == On;
116 return HTMLTextFormControlElement::autoComplete();
117 }
118
updateCheckedRadioButtons()119 void HTMLInputElement::updateCheckedRadioButtons()
120 {
121 if (attached() && checked())
122 checkedRadioButtons().addButton(this);
123
124 if (form()) {
125 const Vector<FormAssociatedElement*>& controls = form()->associatedElements();
126 for (unsigned i = 0; i < controls.size(); ++i) {
127 if (!controls[i]->isFormControlElement())
128 continue;
129 HTMLFormControlElement* control = static_cast<HTMLFormControlElement*>(controls[i]);
130 if (control->name() != name())
131 continue;
132 if (control->type() != type())
133 continue;
134 control->setNeedsValidityCheck();
135 }
136 } else {
137 // FIXME: Traversing the document is inefficient.
138 for (Node* node = document()->body(); node; node = node->traverseNextNode()) {
139 if (!node->isElementNode())
140 continue;
141 Element* element = static_cast<Element*>(node);
142 if (element->formControlName() != name())
143 continue;
144 if (element->formControlType() != type())
145 continue;
146 HTMLFormControlElement* control = static_cast<HTMLFormControlElement*>(element);
147 if (control->form())
148 continue;
149 control->setNeedsValidityCheck();
150 }
151 }
152
153 if (renderer() && renderer()->style()->hasAppearance())
154 renderer()->theme()->stateChanged(renderer(), CheckedState);
155 }
156
lastChangeWasUserEdit() const157 bool HTMLInputElement::lastChangeWasUserEdit() const
158 {
159 if (!isTextField())
160 return false;
161
162 if (!renderer())
163 return false;
164
165 return toRenderTextControl(renderer())->lastChangeWasUserEdit();
166 }
167
isValidValue(const String & value) const168 bool HTMLInputElement::isValidValue(const String& value) const
169 {
170 if (!m_inputType->canSetStringValue()) {
171 ASSERT_NOT_REACHED();
172 return false;
173 }
174 return !m_inputType->typeMismatchFor(value)
175 && !stepMismatch(value)
176 && !rangeUnderflow(value)
177 && !rangeOverflow(value)
178 && !tooLong(value, IgnoreDirtyFlag)
179 && !patternMismatch(value)
180 && !valueMissing(value);
181 }
182
typeMismatch() const183 bool HTMLInputElement::typeMismatch() const
184 {
185 return m_inputType->typeMismatch();
186 }
187
valueMissing(const String & value) const188 bool HTMLInputElement::valueMissing(const String& value) const
189 {
190 if (!isRequiredFormControl() || readOnly() || disabled())
191 return false;
192 return m_inputType->valueMissing(value);
193 }
194
patternMismatch(const String & value) const195 bool HTMLInputElement::patternMismatch(const String& value) const
196 {
197 return m_inputType->patternMismatch(value);
198 }
199
tooLong(const String & value,NeedsToCheckDirtyFlag check) const200 bool HTMLInputElement::tooLong(const String& value, NeedsToCheckDirtyFlag check) const
201 {
202 // We use isTextType() instead of supportsMaxLength() because of the
203 // 'virtual' overhead.
204 if (!isTextType())
205 return false;
206 int max = maxLength();
207 if (max < 0)
208 return false;
209 if (check == CheckDirtyFlag) {
210 // Return false for the default value even if it is longer than maxLength.
211 bool userEdited = !m_data.value().isNull();
212 if (!userEdited)
213 return false;
214 }
215 return numGraphemeClusters(value) > static_cast<unsigned>(max);
216 }
217
rangeUnderflow(const String & value) const218 bool HTMLInputElement::rangeUnderflow(const String& value) const
219 {
220 return m_inputType->rangeUnderflow(value);
221 }
222
rangeOverflow(const String & value) const223 bool HTMLInputElement::rangeOverflow(const String& value) const
224 {
225 return m_inputType->rangeOverflow(value);
226 }
227
minimum() const228 double HTMLInputElement::minimum() const
229 {
230 return m_inputType->minimum();
231 }
232
maximum() const233 double HTMLInputElement::maximum() const
234 {
235 return m_inputType->maximum();
236 }
237
stepMismatch(const String & value) const238 bool HTMLInputElement::stepMismatch(const String& value) const
239 {
240 double step;
241 if (!getAllowedValueStep(&step))
242 return false;
243 return m_inputType->stepMismatch(value, step);
244 }
245
minimumString() const246 String HTMLInputElement::minimumString() const
247 {
248 return m_inputType->serialize(minimum());
249 }
250
maximumString() const251 String HTMLInputElement::maximumString() const
252 {
253 return m_inputType->serialize(maximum());
254 }
255
stepBaseString() const256 String HTMLInputElement::stepBaseString() const
257 {
258 return m_inputType->serialize(m_inputType->stepBase());
259 }
260
stepString() const261 String HTMLInputElement::stepString() const
262 {
263 double step;
264 if (!getAllowedValueStep(&step)) {
265 // stepString() should be called only if stepMismatch() can be true.
266 ASSERT_NOT_REACHED();
267 return String();
268 }
269 return serializeForNumberType(step / m_inputType->stepScaleFactor());
270 }
271
typeMismatchText() const272 String HTMLInputElement::typeMismatchText() const
273 {
274 return m_inputType->typeMismatchText();
275 }
276
valueMissingText() const277 String HTMLInputElement::valueMissingText() const
278 {
279 return m_inputType->valueMissingText();
280 }
281
getAllowedValueStep(double * step) const282 bool HTMLInputElement::getAllowedValueStep(double* step) const
283 {
284 return getAllowedValueStepWithDecimalPlaces(step, 0);
285 }
286
getAllowedValueStepWithDecimalPlaces(double * step,unsigned * decimalPlaces) const287 bool HTMLInputElement::getAllowedValueStepWithDecimalPlaces(double* step, unsigned* decimalPlaces) const
288 {
289 ASSERT(step);
290 double defaultStep = m_inputType->defaultStep();
291 double stepScaleFactor = m_inputType->stepScaleFactor();
292 if (!isfinite(defaultStep) || !isfinite(stepScaleFactor))
293 return false;
294 const AtomicString& stepString = fastGetAttribute(stepAttr);
295 if (stepString.isEmpty()) {
296 *step = defaultStep * stepScaleFactor;
297 if (decimalPlaces)
298 *decimalPlaces = 0;
299 return true;
300 }
301 if (equalIgnoringCase(stepString, "any"))
302 return false;
303 double parsed;
304 if (!decimalPlaces) {
305 if (!parseToDoubleForNumberType(stepString, &parsed) || parsed <= 0.0) {
306 *step = defaultStep * stepScaleFactor;
307 return true;
308 }
309 } else {
310 if (!parseToDoubleForNumberTypeWithDecimalPlaces(stepString, &parsed, decimalPlaces) || parsed <= 0.0) {
311 *step = defaultStep * stepScaleFactor;
312 *decimalPlaces = 0;
313 return true;
314 }
315 }
316 // For date, month, week, the parsed value should be an integer for some types.
317 if (m_inputType->parsedStepValueShouldBeInteger())
318 parsed = max(round(parsed), 1.0);
319 double result = parsed * stepScaleFactor;
320 // For datetime, datetime-local, time, the result should be an integer.
321 if (m_inputType->scaledStepValueShouldBeInteger())
322 result = max(round(result), 1.0);
323 ASSERT(result > 0);
324 *step = result;
325 return true;
326 }
327
applyStep(double count,ExceptionCode & ec)328 void HTMLInputElement::applyStep(double count, ExceptionCode& ec)
329 {
330 double step;
331 unsigned stepDecimalPlaces, currentDecimalPlaces;
332 if (!getAllowedValueStepWithDecimalPlaces(&step, &stepDecimalPlaces)) {
333 ec = INVALID_STATE_ERR;
334 return;
335 }
336 const double nan = numeric_limits<double>::quiet_NaN();
337 double current = m_inputType->parseToDoubleWithDecimalPlaces(value(), nan, ¤tDecimalPlaces);
338 if (!isfinite(current)) {
339 ec = INVALID_STATE_ERR;
340 return;
341 }
342 double newValue = current + step * count;
343 if (isinf(newValue)) {
344 ec = INVALID_STATE_ERR;
345 return;
346 }
347 double acceptableError = m_inputType->acceptableError(step);
348 if (newValue - m_inputType->minimum() < -acceptableError) {
349 ec = INVALID_STATE_ERR;
350 return;
351 }
352 if (newValue < m_inputType->minimum())
353 newValue = m_inputType->minimum();
354 unsigned baseDecimalPlaces;
355 double base = m_inputType->stepBaseWithDecimalPlaces(&baseDecimalPlaces);
356 baseDecimalPlaces = min(baseDecimalPlaces, 16u);
357 if (newValue < pow(10.0, 21.0)) {
358 if (stepMismatch(value())) {
359 double scale = pow(10.0, static_cast<double>(max(stepDecimalPlaces, currentDecimalPlaces)));
360 newValue = round(newValue * scale) / scale;
361 } else {
362 double scale = pow(10.0, static_cast<double>(max(stepDecimalPlaces, baseDecimalPlaces)));
363 newValue = round((base + round((newValue - base) / step) * step) * scale) / scale;
364 }
365 }
366 if (newValue - m_inputType->maximum() > acceptableError) {
367 ec = INVALID_STATE_ERR;
368 return;
369 }
370 if (newValue > m_inputType->maximum())
371 newValue = m_inputType->maximum();
372 setValueAsNumber(newValue, ec);
373
374 if (AXObjectCache::accessibilityEnabled())
375 document()->axObjectCache()->postNotification(renderer(), AXObjectCache::AXValueChanged, true);
376 }
377
stepUp(int n,ExceptionCode & ec)378 void HTMLInputElement::stepUp(int n, ExceptionCode& ec)
379 {
380 applyStep(n, ec);
381 }
382
stepDown(int n,ExceptionCode & ec)383 void HTMLInputElement::stepDown(int n, ExceptionCode& ec)
384 {
385 applyStep(-n, ec);
386 }
387
isKeyboardFocusable(KeyboardEvent * event) const388 bool HTMLInputElement::isKeyboardFocusable(KeyboardEvent* event) const
389 {
390 if (isTextField())
391 return HTMLFormControlElementWithState::isFocusable();
392 return HTMLFormControlElementWithState::isKeyboardFocusable(event) && m_inputType->isKeyboardFocusable();
393 }
394
isMouseFocusable() const395 bool HTMLInputElement::isMouseFocusable() const
396 {
397 if (isTextField())
398 return HTMLFormControlElementWithState::isFocusable();
399 return HTMLFormControlElementWithState::isMouseFocusable();
400 }
401
updateFocusAppearance(bool restorePreviousSelection)402 void HTMLInputElement::updateFocusAppearance(bool restorePreviousSelection)
403 {
404 if (isTextField())
405 InputElement::updateFocusAppearance(m_data, this, this, restorePreviousSelection);
406 else
407 HTMLFormControlElementWithState::updateFocusAppearance(restorePreviousSelection);
408 }
409
aboutToUnload()410 void HTMLInputElement::aboutToUnload()
411 {
412 InputElement::aboutToUnload(this, this);
413 }
414
shouldUseInputMethod() const415 bool HTMLInputElement::shouldUseInputMethod() const
416 {
417 return m_inputType->shouldUseInputMethod();
418 }
419
handleFocusEvent()420 void HTMLInputElement::handleFocusEvent()
421 {
422 InputElement::dispatchFocusEvent(this, this);
423 }
424
handleBlurEvent()425 void HTMLInputElement::handleBlurEvent()
426 {
427 m_inputType->handleBlurEvent();
428 InputElement::dispatchBlurEvent(this, this);
429 }
430
setType(const String & type)431 void HTMLInputElement::setType(const String& type)
432 {
433 // FIXME: This should just call setAttribute. No reason to handle the empty string specially.
434 // We should write a test case to show that setting to the empty string does not remove the
435 // attribute in other browsers and then fix this. Note that setting to null *does* remove
436 // the attribute and setAttribute implements that.
437 if (type.isEmpty()) {
438 ExceptionCode ec;
439 removeAttribute(typeAttr, ec);
440 } else
441 setAttribute(typeAttr, type);
442 }
443
updateType()444 void HTMLInputElement::updateType()
445 {
446 OwnPtr<InputType> newType = InputType::create(this, fastGetAttribute(typeAttr));
447 bool hadType = m_hasType;
448 m_hasType = true;
449 if (m_inputType->formControlType() == newType->formControlType())
450 return;
451
452 if (hadType && !newType->canChangeFromAnotherType()) {
453 // Set the attribute back to the old value.
454 // Useful in case we were called from inside parseMappedAttribute.
455 setAttribute(typeAttr, type());
456 return;
457 }
458
459 checkedRadioButtons().removeButton(this);
460
461 bool wasAttached = attached();
462 if (wasAttached)
463 detach();
464
465 bool didStoreValue = m_inputType->storesValueSeparateFromAttribute();
466 bool neededActivationCallback = needsActivationCallback();
467 bool didRespectHeightAndWidth = m_inputType->shouldRespectHeightAndWidthAttributes();
468
469 m_inputType->destroyShadowSubtree();
470 m_inputType = newType.release();
471 m_inputType->createShadowSubtree();
472
473 setNeedsWillValidateCheck();
474
475 bool willStoreValue = m_inputType->storesValueSeparateFromAttribute();
476
477 if (didStoreValue && !willStoreValue && !m_data.value().isNull()) {
478 setAttribute(valueAttr, m_data.value());
479 m_data.setValue(String());
480 }
481 if (!didStoreValue && willStoreValue)
482 m_data.setValue(sanitizeValue(fastGetAttribute(valueAttr)));
483 else
484 InputElement::updateValueIfNeeded(m_data, this);
485
486 if (neededActivationCallback)
487 unregisterForActivationCallbackIfNeeded();
488 else
489 registerForActivationCallbackIfNeeded();
490
491 if (didRespectHeightAndWidth != m_inputType->shouldRespectHeightAndWidthAttributes()) {
492 NamedNodeMap* map = attributeMap();
493 ASSERT(map);
494 if (Attribute* height = map->getAttributeItem(heightAttr))
495 attributeChanged(height, false);
496 if (Attribute* width = map->getAttributeItem(widthAttr))
497 attributeChanged(width, false);
498 if (Attribute* align = map->getAttributeItem(alignAttr))
499 attributeChanged(align, false);
500 }
501
502 if (wasAttached) {
503 attach();
504 if (document()->focusedNode() == this)
505 updateFocusAppearance(true);
506 }
507
508 setChangedSinceLastFormControlChangeEvent(false);
509
510 checkedRadioButtons().addButton(this);
511
512 setNeedsValidityCheck();
513 InputElement::notifyFormStateChanged(this);
514 }
515
formControlType() const516 const AtomicString& HTMLInputElement::formControlType() const
517 {
518 return m_inputType->formControlType();
519 }
520
saveFormControlState(String & result) const521 bool HTMLInputElement::saveFormControlState(String& result) const
522 {
523 return m_inputType->saveFormControlState(result);
524 }
525
restoreFormControlState(const String & state)526 void HTMLInputElement::restoreFormControlState(const String& state)
527 {
528 m_inputType->restoreFormControlState(state);
529 m_stateRestored = true;
530 }
531
canStartSelection() const532 bool HTMLInputElement::canStartSelection() const
533 {
534 if (!isTextField())
535 return false;
536 return HTMLFormControlElementWithState::canStartSelection();
537 }
538
canHaveSelection() const539 bool HTMLInputElement::canHaveSelection() const
540 {
541 return isTextField();
542 }
543
accessKeyAction(bool sendToAnyElement)544 void HTMLInputElement::accessKeyAction(bool sendToAnyElement)
545 {
546 m_inputType->accessKeyAction(sendToAnyElement);
547 }
548
mapToEntry(const QualifiedName & attrName,MappedAttributeEntry & result) const549 bool HTMLInputElement::mapToEntry(const QualifiedName& attrName, MappedAttributeEntry& result) const
550 {
551 if (((attrName == heightAttr || attrName == widthAttr) && m_inputType->shouldRespectHeightAndWidthAttributes())
552 || attrName == vspaceAttr
553 || attrName == hspaceAttr) {
554 result = eUniversal;
555 return false;
556 }
557
558 if (attrName == alignAttr && m_inputType->shouldRespectAlignAttribute()) {
559 // Share with <img> since the alignment behavior is the same.
560 result = eReplaced;
561 return false;
562 }
563
564 return HTMLElement::mapToEntry(attrName, result);
565 }
566
parseMappedAttribute(Attribute * attr)567 void HTMLInputElement::parseMappedAttribute(Attribute* attr)
568 {
569 if (attr->name() == nameAttr) {
570 checkedRadioButtons().removeButton(this);
571 m_data.setName(attr->value());
572 checkedRadioButtons().addButton(this);
573 HTMLFormControlElementWithState::parseMappedAttribute(attr);
574 } else if (attr->name() == autocompleteAttr) {
575 if (equalIgnoringCase(attr->value(), "off")) {
576 m_autocomplete = Off;
577 registerForActivationCallbackIfNeeded();
578 } else {
579 bool needsToUnregister = m_autocomplete == Off;
580
581 if (attr->isEmpty())
582 m_autocomplete = Uninitialized;
583 else
584 m_autocomplete = On;
585
586 if (needsToUnregister)
587 unregisterForActivationCallbackIfNeeded();
588 }
589 } else if (attr->name() == typeAttr) {
590 updateType();
591 } else if (attr->name() == valueAttr) {
592 // We only need to setChanged if the form is looking at the default value right now.
593 if (m_data.value().isNull())
594 setNeedsStyleRecalc();
595 setFormControlValueMatchesRenderer(false);
596 setNeedsValidityCheck();
597 } else if (attr->name() == checkedAttr) {
598 // Another radio button in the same group might be checked by state
599 // restore. We shouldn't call setChecked() even if this has the checked
600 // attribute. So, delay the setChecked() call until
601 // finishParsingChildren() is called if parsing is in progress.
602 if (!m_parsingInProgress && m_reflectsCheckedAttribute) {
603 setChecked(!attr->isNull());
604 m_reflectsCheckedAttribute = true;
605 }
606 } else if (attr->name() == maxlengthAttr) {
607 InputElement::parseMaxLengthAttribute(m_data, this, this, attr);
608 setNeedsValidityCheck();
609 } else if (attr->name() == sizeAttr)
610 InputElement::parseSizeAttribute(m_data, this, attr);
611 else if (attr->name() == altAttr)
612 m_inputType->altAttributeChanged();
613 else if (attr->name() == srcAttr)
614 m_inputType->srcAttributeChanged();
615 else if (attr->name() == usemapAttr || attr->name() == accesskeyAttr) {
616 // FIXME: ignore for the moment
617 } else if (attr->name() == vspaceAttr) {
618 addCSSLength(attr, CSSPropertyMarginTop, attr->value());
619 addCSSLength(attr, CSSPropertyMarginBottom, attr->value());
620 } else if (attr->name() == hspaceAttr) {
621 addCSSLength(attr, CSSPropertyMarginLeft, attr->value());
622 addCSSLength(attr, CSSPropertyMarginRight, attr->value());
623 } else if (attr->name() == alignAttr) {
624 if (m_inputType->shouldRespectAlignAttribute())
625 addHTMLAlignment(attr);
626 } else if (attr->name() == widthAttr) {
627 if (m_inputType->shouldRespectHeightAndWidthAttributes())
628 addCSSLength(attr, CSSPropertyWidth, attr->value());
629 } else if (attr->name() == heightAttr) {
630 if (m_inputType->shouldRespectHeightAndWidthAttributes())
631 addCSSLength(attr, CSSPropertyHeight, attr->value());
632 } else if (attr->name() == onsearchAttr) {
633 // Search field and slider attributes all just cause updateFromElement to be called through style recalcing.
634 setAttributeEventListener(eventNames().searchEvent, createAttributeEventListener(this, attr));
635 } else if (attr->name() == resultsAttr) {
636 int oldResults = m_maxResults;
637 m_maxResults = !attr->isNull() ? std::min(attr->value().toInt(), maxSavedResults) : -1;
638 // FIXME: Detaching just for maxResults change is not ideal. We should figure out the right
639 // time to relayout for this change.
640 if (m_maxResults != oldResults && (m_maxResults <= 0 || oldResults <= 0) && attached()) {
641 detach();
642 attach();
643 }
644 setNeedsStyleRecalc();
645 } else if (attr->name() == autosaveAttr || attr->name() == incrementalAttr)
646 setNeedsStyleRecalc();
647 else if (attr->name() == minAttr || attr->name() == maxAttr) {
648 m_inputType->minOrMaxAttributeChanged();
649 setNeedsValidityCheck();
650 } else if (attr->name() == multipleAttr || attr->name() == patternAttr || attr->name() == precisionAttr || attr->name() == stepAttr)
651 setNeedsValidityCheck();
652 #if ENABLE(DATALIST)
653 else if (attr->name() == listAttr)
654 m_hasNonEmptyList = !attr->isEmpty();
655 // FIXME: we need to tell this change to a renderer if the attribute affects the appearance.
656 #endif
657 #if ENABLE(INPUT_SPEECH)
658 else if (attr->name() == webkitspeechAttr) {
659 if (renderer()) {
660 // This renderer and its children have quite different layouts and styles depending on
661 // whether the speech button is visible or not. So we reset the whole thing and recreate
662 // to get the right styles and layout.
663 detach();
664 attach();
665 }
666 setNeedsStyleRecalc();
667 } else if (attr->name() == onwebkitspeechchangeAttr)
668 setAttributeEventListener(eventNames().webkitspeechchangeEvent, createAttributeEventListener(this, attr));
669 #endif
670 else
671 HTMLTextFormControlElement::parseMappedAttribute(attr);
672 }
673
finishParsingChildren()674 void HTMLInputElement::finishParsingChildren()
675 {
676 m_parsingInProgress = false;
677 HTMLFormControlElementWithState::finishParsingChildren();
678 if (!m_stateRestored) {
679 bool checked = hasAttribute(checkedAttr);
680 if (checked)
681 setChecked(checked);
682 m_reflectsCheckedAttribute = true;
683 }
684 }
685
rendererIsNeeded(RenderStyle * style)686 bool HTMLInputElement::rendererIsNeeded(RenderStyle* style)
687 {
688 return m_inputType->rendererIsNeeded() && HTMLFormControlElementWithState::rendererIsNeeded(style);
689 }
690
createRenderer(RenderArena * arena,RenderStyle * style)691 RenderObject* HTMLInputElement::createRenderer(RenderArena* arena, RenderStyle* style)
692 {
693 return m_inputType->createRenderer(arena, style);
694 }
695
attach()696 void HTMLInputElement::attach()
697 {
698 suspendPostAttachCallbacks();
699
700 if (!m_hasType)
701 updateType();
702
703 HTMLFormControlElementWithState::attach();
704
705 m_inputType->attach();
706
707 if (document()->focusedNode() == this)
708 document()->updateFocusAppearanceSoon(true /* restore selection */);
709
710 resumePostAttachCallbacks();
711 }
712
detach()713 void HTMLInputElement::detach()
714 {
715 HTMLFormControlElementWithState::detach();
716 setFormControlValueMatchesRenderer(false);
717 }
718
altText() const719 String HTMLInputElement::altText() const
720 {
721 // http://www.w3.org/TR/1998/REC-html40-19980424/appendix/notes.html#altgen
722 // also heavily discussed by Hixie on bugzilla
723 // note this is intentionally different to HTMLImageElement::altText()
724 String alt = fastGetAttribute(altAttr);
725 // fall back to title attribute
726 if (alt.isNull())
727 alt = getAttribute(titleAttr);
728 if (alt.isNull())
729 alt = getAttribute(valueAttr);
730 if (alt.isEmpty())
731 alt = inputElementAltText();
732 return alt;
733 }
734
isSuccessfulSubmitButton() const735 bool HTMLInputElement::isSuccessfulSubmitButton() const
736 {
737 // HTML spec says that buttons must have names to be considered successful.
738 // However, other browsers do not impose this constraint. So we do not.
739 return !disabled() && m_inputType->canBeSuccessfulSubmitButton();
740 }
741
isActivatedSubmit() const742 bool HTMLInputElement::isActivatedSubmit() const
743 {
744 return m_isActivatedSubmit;
745 }
746
setActivatedSubmit(bool flag)747 void HTMLInputElement::setActivatedSubmit(bool flag)
748 {
749 m_isActivatedSubmit = flag;
750 }
751
appendFormData(FormDataList & encoding,bool multipart)752 bool HTMLInputElement::appendFormData(FormDataList& encoding, bool multipart)
753 {
754 return m_inputType->isFormDataAppendable() && m_inputType->appendFormData(encoding, multipart);
755 }
756
reset()757 void HTMLInputElement::reset()
758 {
759 if (m_inputType->storesValueSeparateFromAttribute())
760 setValue(String());
761
762 setAutofilled(false);
763 setChecked(hasAttribute(checkedAttr));
764 m_reflectsCheckedAttribute = true;
765 }
766
isTextField() const767 bool HTMLInputElement::isTextField() const
768 {
769 return m_inputType->isTextField();
770 }
771
isTextType() const772 bool HTMLInputElement::isTextType() const
773 {
774 return m_inputType->isTextType();
775 }
776
setChecked(bool nowChecked,bool sendChangeEvent)777 void HTMLInputElement::setChecked(bool nowChecked, bool sendChangeEvent)
778 {
779 if (checked() == nowChecked)
780 return;
781
782 checkedRadioButtons().removeButton(this);
783
784 m_reflectsCheckedAttribute = false;
785 m_isChecked = nowChecked;
786 setNeedsStyleRecalc();
787
788 updateCheckedRadioButtons();
789 setNeedsValidityCheck();
790
791 // Ideally we'd do this from the render tree (matching
792 // RenderTextView), but it's not possible to do it at the moment
793 // because of the way the code is structured.
794 if (renderer() && AXObjectCache::accessibilityEnabled())
795 renderer()->document()->axObjectCache()->postNotification(renderer(), AXObjectCache::AXCheckedStateChanged, true);
796
797 // Only send a change event for items in the document (avoid firing during
798 // parsing) and don't send a change event for a radio button that's getting
799 // unchecked to match other browsers. DOM is not a useful standard for this
800 // because it says only to fire change events at "lose focus" time, which is
801 // definitely wrong in practice for these types of elements.
802 if (sendChangeEvent && inDocument() && m_inputType->shouldSendChangeEventAfterCheckedChanged()) {
803 setTextAsOfLastFormControlChangeEvent(String());
804 dispatchFormControlChangeEvent();
805 }
806 }
807
setIndeterminate(bool newValue)808 void HTMLInputElement::setIndeterminate(bool newValue)
809 {
810 if (!m_inputType->isCheckable() || indeterminate() == newValue)
811 return;
812
813 m_isIndeterminate = newValue;
814
815 setNeedsStyleRecalc();
816
817 if (renderer() && renderer()->style()->hasAppearance())
818 renderer()->theme()->stateChanged(renderer(), CheckedState);
819 }
820
size() const821 int HTMLInputElement::size() const
822 {
823 return m_data.size();
824 }
825
copyNonAttributeProperties(const Element * source)826 void HTMLInputElement::copyNonAttributeProperties(const Element* source)
827 {
828 const HTMLInputElement* sourceElement = static_cast<const HTMLInputElement*>(source);
829
830 m_data.setValue(sourceElement->m_data.value());
831 setChecked(sourceElement->m_isChecked);
832 m_reflectsCheckedAttribute = sourceElement->m_reflectsCheckedAttribute;
833 m_isIndeterminate = sourceElement->m_isIndeterminate;
834
835 HTMLFormControlElementWithState::copyNonAttributeProperties(source);
836 }
837
value() const838 String HTMLInputElement::value() const
839 {
840 String value;
841 if (m_inputType->getTypeSpecificValue(value))
842 return value;
843
844 value = m_data.value();
845 if (!value.isNull())
846 return value;
847
848 value = sanitizeValue(fastGetAttribute(valueAttr));
849 if (!value.isNull())
850 return value;
851
852 return m_inputType->fallbackValue();
853 }
854
valueWithDefault() const855 String HTMLInputElement::valueWithDefault() const
856 {
857 String value = this->value();
858 if (!value.isNull())
859 return value;
860
861 return m_inputType->defaultValue();
862 }
863
setValueForUser(const String & value)864 void HTMLInputElement::setValueForUser(const String& value)
865 {
866 // Call setValue and make it send a change event.
867 setValue(value, true);
868 }
869
suggestedValue() const870 const String& HTMLInputElement::suggestedValue() const
871 {
872 return m_data.suggestedValue();
873 }
874
setSuggestedValue(const String & value)875 void HTMLInputElement::setSuggestedValue(const String& value)
876 {
877 if (!m_inputType->canSetSuggestedValue())
878 return;
879 setFormControlValueMatchesRenderer(false);
880 m_data.setSuggestedValue(sanitizeValue(value));
881 updatePlaceholderVisibility(false);
882 if (renderer())
883 renderer()->updateFromElement();
884 setNeedsStyleRecalc();
885 }
886
setValue(const String & value,bool sendChangeEvent)887 void HTMLInputElement::setValue(const String& value, bool sendChangeEvent)
888 {
889 if (!m_inputType->canSetValue(value))
890 return;
891
892 setFormControlValueMatchesRenderer(false);
893 if (m_inputType->storesValueSeparateFromAttribute()) {
894 if (files())
895 files()->clear();
896 else {
897 m_data.setValue(sanitizeValue(value));
898 if (isTextField())
899 updatePlaceholderVisibility(false);
900 }
901 setNeedsStyleRecalc();
902 } else
903 setAttribute(valueAttr, sanitizeValue(value));
904
905 setNeedsValidityCheck();
906
907 if (isTextField()) {
908 unsigned max = m_data.value().length();
909 #ifdef ANDROID_ACCEPT_CHANGES_TO_FOCUSED_TEXTFIELDS
910 // Make sure our UI side textfield changes to match the RenderTextControl
911 PlatformBridge::updateTextfield(document()->view(), this, value);
912 #endif
913 if (document()->focusedNode() == this)
914 InputElement::updateSelectionRange(this, this, max, max);
915 else
916 cacheSelection(max, max);
917 m_data.setSuggestedValue(String());
918 }
919 m_inputType->valueChanged();
920
921 if (sendChangeEvent) {
922 // If the user is still editing this field, dispatch an input event rather than a change event.
923 // The change event will be dispatched when editing finishes.
924 if (isTextField() && focused())
925 dispatchFormControlInputEvent();
926 else
927 dispatchFormControlChangeEvent();
928 }
929
930 if (isText() && (!focused() || !sendChangeEvent))
931 setTextAsOfLastFormControlChangeEvent(value);
932
933 InputElement::notifyFormStateChanged(this);
934 }
935
valueAsDate() const936 double HTMLInputElement::valueAsDate() const
937 {
938 return m_inputType->valueAsDate();
939 }
940
setValueAsDate(double value,ExceptionCode & ec)941 void HTMLInputElement::setValueAsDate(double value, ExceptionCode& ec)
942 {
943 m_inputType->setValueAsDate(value, ec);
944 }
945
valueAsNumber() const946 double HTMLInputElement::valueAsNumber() const
947 {
948 return m_inputType->valueAsNumber();
949 }
950
setValueAsNumber(double newValue,ExceptionCode & ec)951 void HTMLInputElement::setValueAsNumber(double newValue, ExceptionCode& ec)
952 {
953 if (!isfinite(newValue)) {
954 ec = NOT_SUPPORTED_ERR;
955 return;
956 }
957 m_inputType->setValueAsNumber(newValue, ec);
958 }
959
placeholder() const960 String HTMLInputElement::placeholder() const
961 {
962 return fastGetAttribute(placeholderAttr).string();
963 }
964
setPlaceholder(const String & value)965 void HTMLInputElement::setPlaceholder(const String& value)
966 {
967 setAttribute(placeholderAttr, value);
968 }
969
searchEventsShouldBeDispatched() const970 bool HTMLInputElement::searchEventsShouldBeDispatched() const
971 {
972 return hasAttribute(incrementalAttr);
973 }
974
setValueFromRenderer(const String & value)975 void HTMLInputElement::setValueFromRenderer(const String& value)
976 {
977 // File upload controls will always use setFileListFromRenderer.
978 ASSERT(!isFileUpload());
979
980 m_data.setSuggestedValue(String());
981 InputElement::setValueFromRenderer(m_data, this, this, value);
982 updatePlaceholderVisibility(false);
983 setNeedsValidityCheck();
984
985 // Clear autofill flag (and yellow background) on user edit.
986 setAutofilled(false);
987 }
988
setFileListFromRenderer(const Vector<String> & paths)989 void HTMLInputElement::setFileListFromRenderer(const Vector<String>& paths)
990 {
991 m_inputType->setFileList(paths);
992
993 setFormControlValueMatchesRenderer(true);
994 InputElement::notifyFormStateChanged(this);
995 setNeedsValidityCheck();
996 }
997
preDispatchEventHandler(Event * event)998 void* HTMLInputElement::preDispatchEventHandler(Event* event)
999 {
1000 if (event->type() == eventNames().textInputEvent && m_inputType->shouldSubmitImplicitly(event)) {
1001 event->stopPropagation();
1002 return 0;
1003 }
1004 if (event->type() != eventNames().clickEvent)
1005 return 0;
1006 if (!event->isMouseEvent() || static_cast<MouseEvent*>(event)->button() != LeftButton)
1007 return 0;
1008 // FIXME: Check whether there are any cases where this actually ends up leaking.
1009 return m_inputType->willDispatchClick().leakPtr();
1010 }
1011
postDispatchEventHandler(Event * event,void * dataFromPreDispatch)1012 void HTMLInputElement::postDispatchEventHandler(Event* event, void* dataFromPreDispatch)
1013 {
1014 OwnPtr<ClickHandlingState> state = adoptPtr(static_cast<ClickHandlingState*>(dataFromPreDispatch));
1015 if (!state)
1016 return;
1017 m_inputType->didDispatchClick(event, *state);
1018 }
1019
defaultEventHandler(Event * evt)1020 void HTMLInputElement::defaultEventHandler(Event* evt)
1021 {
1022 if (evt->isMouseEvent() && evt->type() == eventNames().clickEvent && static_cast<MouseEvent*>(evt)->button() == LeftButton) {
1023 m_inputType->handleClickEvent(static_cast<MouseEvent*>(evt));
1024 if (evt->defaultHandled())
1025 return;
1026 }
1027
1028 if (evt->isKeyboardEvent() && evt->type() == eventNames().keydownEvent) {
1029 m_inputType->handleKeydownEvent(static_cast<KeyboardEvent*>(evt));
1030 if (evt->defaultHandled())
1031 return;
1032 }
1033
1034 // Call the base event handler before any of our own event handling for almost all events in text fields.
1035 // Makes editing keyboard handling take precedence over the keydown and keypress handling in this function.
1036 bool callBaseClassEarly = isTextField() && (evt->type() == eventNames().keydownEvent || evt->type() == eventNames().keypressEvent);
1037 if (callBaseClassEarly) {
1038 HTMLFormControlElementWithState::defaultEventHandler(evt);
1039 if (evt->defaultHandled())
1040 return;
1041 }
1042
1043 // DOMActivate events cause the input to be "activated" - in the case of image and submit inputs, this means
1044 // actually submitting the form. For reset inputs, the form is reset. These events are sent when the user clicks
1045 // on the element, or presses enter while it is the active element. JavaScript code wishing to activate the element
1046 // must dispatch a DOMActivate event - a click event will not do the job.
1047 if (evt->type() == eventNames().DOMActivateEvent) {
1048 m_inputType->handleDOMActivateEvent(evt);
1049 if (evt->defaultHandled())
1050 return;
1051 }
1052
1053 // Use key press event here since sending simulated mouse events
1054 // on key down blocks the proper sending of the key press event.
1055 if (evt->isKeyboardEvent() && evt->type() == eventNames().keypressEvent) {
1056 m_inputType->handleKeypressEvent(static_cast<KeyboardEvent*>(evt));
1057 if (evt->defaultHandled())
1058 return;
1059 }
1060
1061 if (evt->isKeyboardEvent() && evt->type() == eventNames().keyupEvent) {
1062 m_inputType->handleKeyupEvent(static_cast<KeyboardEvent*>(evt));
1063 if (evt->defaultHandled())
1064 return;
1065 }
1066
1067 if (m_inputType->shouldSubmitImplicitly(evt)) {
1068 if (isSearchField()) {
1069 addSearchResult();
1070 onSearch();
1071 }
1072 // Form submission finishes editing, just as loss of focus does.
1073 // If there was a change, send the event now.
1074 if (wasChangedSinceLastFormControlChangeEvent())
1075 dispatchFormControlChangeEvent();
1076
1077 RefPtr<HTMLFormElement> formForSubmission = m_inputType->formForSubmission();
1078 // Form may never have been present, or may have been destroyed by code responding to the change event.
1079 if (formForSubmission)
1080 formForSubmission->submitImplicitly(evt, canTriggerImplicitSubmission());
1081
1082 evt->setDefaultHandled();
1083 return;
1084 }
1085
1086 if (evt->isBeforeTextInsertedEvent())
1087 m_inputType->handleBeforeTextInsertedEvent(static_cast<BeforeTextInsertedEvent*>(evt));
1088
1089 if (evt->isWheelEvent()) {
1090 m_inputType->handleWheelEvent(static_cast<WheelEvent*>(evt));
1091 if (evt->defaultHandled())
1092 return;
1093 }
1094
1095 if (evt->isMouseEvent() && evt->type() == eventNames().mousedownEvent) {
1096 m_inputType->handleMouseDownEvent(static_cast<MouseEvent*>(evt));
1097 if (evt->defaultHandled())
1098 return;
1099 }
1100
1101 #if PLATFORM(ANDROID) && ENABLE(TOUCH_EVENTS)
1102 if (evt->isTouchEvent() && evt->type() == eventNames().touchstartEvent) {
1103 m_inputType->handleTouchStartEvent(static_cast<TouchEvent*>(evt));
1104 if (evt->defaultHandled())
1105 return;
1106 }
1107 #endif
1108
1109 m_inputType->forwardEvent(evt);
1110
1111 if (!callBaseClassEarly && !evt->defaultHandled())
1112 HTMLFormControlElementWithState::defaultEventHandler(evt);
1113 }
1114
isURLAttribute(Attribute * attr) const1115 bool HTMLInputElement::isURLAttribute(Attribute *attr) const
1116 {
1117 return (attr->name() == srcAttr || attr->name() == formactionAttr);
1118 }
1119
defaultValue() const1120 String HTMLInputElement::defaultValue() const
1121 {
1122 return fastGetAttribute(valueAttr);
1123 }
1124
setDefaultValue(const String & value)1125 void HTMLInputElement::setDefaultValue(const String &value)
1126 {
1127 setAttribute(valueAttr, value);
1128 }
1129
setDefaultName(const AtomicString & name)1130 void HTMLInputElement::setDefaultName(const AtomicString& name)
1131 {
1132 m_data.setName(name);
1133 }
1134
accept() const1135 String HTMLInputElement::accept() const
1136 {
1137 return fastGetAttribute(acceptAttr);
1138 }
1139
alt() const1140 String HTMLInputElement::alt() const
1141 {
1142 return fastGetAttribute(altAttr);
1143 }
1144
maxLength() const1145 int HTMLInputElement::maxLength() const
1146 {
1147 return m_data.maxLength();
1148 }
1149
setMaxLength(int maxLength,ExceptionCode & ec)1150 void HTMLInputElement::setMaxLength(int maxLength, ExceptionCode& ec)
1151 {
1152 if (maxLength < 0)
1153 ec = INDEX_SIZE_ERR;
1154 else
1155 setAttribute(maxlengthAttr, String::number(maxLength));
1156 }
1157
multiple() const1158 bool HTMLInputElement::multiple() const
1159 {
1160 return fastHasAttribute(multipleAttr);
1161 }
1162
setSize(unsigned size)1163 void HTMLInputElement::setSize(unsigned size)
1164 {
1165 setAttribute(sizeAttr, String::number(size));
1166 }
1167
src() const1168 KURL HTMLInputElement::src() const
1169 {
1170 return document()->completeURL(fastGetAttribute(srcAttr));
1171 }
1172
setAutofilled(bool autofilled)1173 void HTMLInputElement::setAutofilled(bool autofilled)
1174 {
1175 if (autofilled == m_isAutofilled)
1176 return;
1177
1178 m_isAutofilled = autofilled;
1179 setNeedsStyleRecalc();
1180 }
1181
files()1182 FileList* HTMLInputElement::files()
1183 {
1184 return m_inputType->files();
1185 }
1186
visibleValue() const1187 String HTMLInputElement::visibleValue() const
1188 {
1189 return m_inputType->visibleValue();
1190 }
1191
convertFromVisibleValue(const String & visibleValue) const1192 String HTMLInputElement::convertFromVisibleValue(const String& visibleValue) const
1193 {
1194 return m_inputType->convertFromVisibleValue(visibleValue);
1195 }
1196
isAcceptableValue(const String & proposedValue) const1197 bool HTMLInputElement::isAcceptableValue(const String& proposedValue) const
1198 {
1199 return m_inputType->isAcceptableValue(proposedValue);
1200 }
1201
sanitizeValue(const String & proposedValue) const1202 String HTMLInputElement::sanitizeValue(const String& proposedValue) const
1203 {
1204 return m_inputType->sanitizeValue(proposedValue);
1205 }
1206
hasUnacceptableValue() const1207 bool HTMLInputElement::hasUnacceptableValue() const
1208 {
1209 return m_inputType->hasUnacceptableValue();
1210 }
1211
isInRange() const1212 bool HTMLInputElement::isInRange() const
1213 {
1214 return m_inputType->supportsRangeLimitation() && !rangeUnderflow(value()) && !rangeOverflow(value());
1215 }
1216
isOutOfRange() const1217 bool HTMLInputElement::isOutOfRange() const
1218 {
1219 return m_inputType->supportsRangeLimitation() && (rangeUnderflow(value()) || rangeOverflow(value()));
1220 }
1221
needsActivationCallback()1222 bool HTMLInputElement::needsActivationCallback()
1223 {
1224 return m_autocomplete == Off || m_inputType->shouldResetOnDocumentActivation();
1225 }
1226
registerForActivationCallbackIfNeeded()1227 void HTMLInputElement::registerForActivationCallbackIfNeeded()
1228 {
1229 if (needsActivationCallback())
1230 document()->registerForDocumentActivationCallbacks(this);
1231 }
1232
unregisterForActivationCallbackIfNeeded()1233 void HTMLInputElement::unregisterForActivationCallbackIfNeeded()
1234 {
1235 if (!needsActivationCallback())
1236 document()->unregisterForDocumentActivationCallbacks(this);
1237 }
1238
isRequiredFormControl() const1239 bool HTMLInputElement::isRequiredFormControl() const
1240 {
1241 return m_inputType->supportsRequired() && required();
1242 }
1243
cacheSelection(int start,int end)1244 void HTMLInputElement::cacheSelection(int start, int end)
1245 {
1246 m_data.setCachedSelectionStart(start);
1247 m_data.setCachedSelectionEnd(end);
1248 }
1249
addSearchResult()1250 void HTMLInputElement::addSearchResult()
1251 {
1252 ASSERT(isSearchField());
1253 if (renderer())
1254 toRenderTextControlSingleLine(renderer())->addSearchResult();
1255 }
1256
onSearch()1257 void HTMLInputElement::onSearch()
1258 {
1259 ASSERT(isSearchField());
1260 if (renderer())
1261 toRenderTextControlSingleLine(renderer())->stopSearchEventTimer();
1262 dispatchEvent(Event::create(eventNames().searchEvent, true, false));
1263 }
1264
documentDidBecomeActive()1265 void HTMLInputElement::documentDidBecomeActive()
1266 {
1267 ASSERT(needsActivationCallback());
1268 reset();
1269 }
1270
willMoveToNewOwnerDocument()1271 void HTMLInputElement::willMoveToNewOwnerDocument()
1272 {
1273 m_inputType->willMoveToNewOwnerDocument();
1274
1275 // Always unregister for cache callbacks when leaving a document, even if we would otherwise like to be registered
1276 if (needsActivationCallback())
1277 document()->unregisterForDocumentActivationCallbacks(this);
1278
1279 document()->checkedRadioButtons().removeButton(this);
1280
1281 HTMLFormControlElementWithState::willMoveToNewOwnerDocument();
1282 }
1283
didMoveToNewOwnerDocument()1284 void HTMLInputElement::didMoveToNewOwnerDocument()
1285 {
1286 registerForActivationCallbackIfNeeded();
1287
1288 HTMLFormControlElementWithState::didMoveToNewOwnerDocument();
1289 }
1290
addSubresourceAttributeURLs(ListHashSet<KURL> & urls) const1291 void HTMLInputElement::addSubresourceAttributeURLs(ListHashSet<KURL>& urls) const
1292 {
1293 HTMLFormControlElementWithState::addSubresourceAttributeURLs(urls);
1294
1295 addSubresourceURL(urls, src());
1296 }
1297
recalcWillValidate() const1298 bool HTMLInputElement::recalcWillValidate() const
1299 {
1300 return m_inputType->supportsValidation() && HTMLFormControlElementWithState::recalcWillValidate();
1301 }
1302
1303 #if ENABLE(DATALIST)
1304
list() const1305 HTMLElement* HTMLInputElement::list() const
1306 {
1307 return dataList();
1308 }
1309
dataList() const1310 HTMLDataListElement* HTMLInputElement::dataList() const
1311 {
1312 if (!m_hasNonEmptyList)
1313 return 0;
1314
1315 if (!m_inputType->shouldRespectListAttribute())
1316 return 0;
1317
1318 Element* element = document()->getElementById(fastGetAttribute(listAttr));
1319 if (!element)
1320 return 0;
1321 if (!element->hasTagName(datalistTag))
1322 return 0;
1323
1324 return static_cast<HTMLDataListElement*>(element);
1325 }
1326
selectedOption() const1327 HTMLOptionElement* HTMLInputElement::selectedOption() const
1328 {
1329 String value = this->value();
1330
1331 // The empty string never matches to a datalist option because it
1332 // doesn't represent a suggestion according to the standard.
1333 if (value.isEmpty())
1334 return 0;
1335
1336 HTMLDataListElement* sourceElement = dataList();
1337 if (!sourceElement)
1338 return 0;
1339 RefPtr<HTMLCollection> options = sourceElement->options();
1340 if (!options)
1341 return 0;
1342 unsigned length = options->length();
1343 for (unsigned i = 0; i < length; ++i) {
1344 HTMLOptionElement* option = static_cast<HTMLOptionElement*>(options->item(i));
1345 if (!option->disabled() && value == option->value())
1346 return option;
1347 }
1348 return 0;
1349 }
1350
1351 #endif // ENABLE(DATALIST)
1352
stepUpFromRenderer(int n)1353 void HTMLInputElement::stepUpFromRenderer(int n)
1354 {
1355 // The differences from stepUp()/stepDown():
1356 //
1357 // Difference 1: the current value
1358 // If the current value is not a number, including empty, the current value is assumed as 0.
1359 // * If 0 is in-range, and matches to step value
1360 // - The value should be the +step if n > 0
1361 // - The value should be the -step if n < 0
1362 // If -step or +step is out of range, new value should be 0.
1363 // * If 0 is smaller than the minimum value
1364 // - The value should be the minimum value for any n
1365 // * If 0 is larger than the maximum value
1366 // - The value should be the maximum value for any n
1367 // * If 0 is in-range, but not matched to step value
1368 // - The value should be the larger matched value nearest to 0 if n > 0
1369 // e.g. <input type=number min=-100 step=3> -> 2
1370 // - The value should be the smaler matched value nearest to 0 if n < 0
1371 // e.g. <input type=number min=-100 step=3> -> -1
1372 // As for date/datetime-local/month/time/week types, the current value is assumed as "the current local date/time".
1373 // As for datetime type, the current value is assumed as "the current date/time in UTC".
1374 // If the current value is smaller than the minimum value:
1375 // - The value should be the minimum value if n > 0
1376 // - Nothing should happen if n < 0
1377 // If the current value is larger than the maximum value:
1378 // - The value should be the maximum value if n < 0
1379 // - Nothing should happen if n > 0
1380 //
1381 // Difference 2: clamping steps
1382 // If the current value is not matched to step value:
1383 // - The value should be the larger matched value nearest to 0 if n > 0
1384 // e.g. <input type=number value=3 min=-100 step=3> -> 5
1385 // - The value should be the smaler matched value nearest to 0 if n < 0
1386 // e.g. <input type=number value=3 min=-100 step=3> -> 2
1387 //
1388 // n is assumed as -n if step < 0.
1389
1390 ASSERT(hasSpinButton() || m_inputType->isRangeControl());
1391 if (!hasSpinButton() && !m_inputType->isRangeControl())
1392 return;
1393 ASSERT(n);
1394 if (!n)
1395 return;
1396
1397 unsigned stepDecimalPlaces, baseDecimalPlaces;
1398 double step, base;
1399 // The value will be the default value after stepping for <input value=(empty/invalid) step="any" />
1400 // FIXME: Not any changes after stepping, even if it is an invalid value, may be better.
1401 // (e.g. Stepping-up for <input type="number" value="foo" step="any" /> => "foo")
1402 if (equalIgnoringCase(fastGetAttribute(stepAttr), "any"))
1403 step = 0;
1404 else if (!getAllowedValueStepWithDecimalPlaces(&step, &stepDecimalPlaces))
1405 return;
1406 base = m_inputType->stepBaseWithDecimalPlaces(&baseDecimalPlaces);
1407 baseDecimalPlaces = min(baseDecimalPlaces, 16u);
1408
1409 int sign;
1410 if (step > 0)
1411 sign = n;
1412 else if (step < 0)
1413 sign = -n;
1414 else
1415 sign = 0;
1416
1417 const double nan = numeric_limits<double>::quiet_NaN();
1418 String currentStringValue = value();
1419 double current = m_inputType->parseToDouble(currentStringValue, nan);
1420 if (!isfinite(current)) {
1421 ExceptionCode ec;
1422 current = m_inputType->defaultValueForStepUp();
1423 setValueAsNumber(current, ec);
1424 }
1425 if ((sign > 0 && current < m_inputType->minimum()) || (sign < 0 && current > m_inputType->maximum()))
1426 setValue(m_inputType->serialize(sign > 0 ? m_inputType->minimum() : m_inputType->maximum()));
1427 else {
1428 ExceptionCode ec;
1429 if (stepMismatch(currentStringValue)) {
1430 ASSERT(step);
1431 double newValue;
1432 double scale = pow(10.0, static_cast<double>(max(stepDecimalPlaces, baseDecimalPlaces)));
1433
1434 if (sign < 0)
1435 newValue = round((base + floor((current - base) / step) * step) * scale) / scale;
1436 else if (sign > 0)
1437 newValue = round((base + ceil((current - base) / step) * step) * scale) / scale;
1438 else
1439 newValue = current;
1440
1441 if (newValue < m_inputType->minimum())
1442 newValue = m_inputType->minimum();
1443 if (newValue > m_inputType->maximum())
1444 newValue = m_inputType->maximum();
1445
1446 setValueAsNumber(newValue, ec);
1447 current = newValue;
1448 if (n > 1)
1449 applyStep(n - 1, ec);
1450 else if (n < -1)
1451 applyStep(n + 1, ec);
1452 } else
1453 applyStep(n, ec);
1454 }
1455
1456 if (currentStringValue != value()) {
1457 if (m_inputType->isRangeControl())
1458 dispatchFormControlChangeEvent();
1459 else
1460 dispatchFormControlInputEvent();
1461 }
1462 }
1463
1464 #if ENABLE(WCSS)
1465
setWapInputFormat(String & mask)1466 void HTMLInputElement::setWapInputFormat(String& mask)
1467 {
1468 String validateMask = validateInputMask(m_data, mask);
1469 if (!validateMask.isEmpty())
1470 m_data.setInputFormatMask(validateMask);
1471 }
1472
1473 #endif
1474
1475 #if ENABLE(INPUT_SPEECH)
1476
isSpeechEnabled() const1477 bool HTMLInputElement::isSpeechEnabled() const
1478 {
1479 // FIXME: Add support for RANGE, EMAIL, URL, COLOR and DATE/TIME input types.
1480 return m_inputType->shouldRespectSpeechAttribute() && RuntimeEnabledFeatures::speechInputEnabled() && hasAttribute(webkitspeechAttr);
1481 }
1482
1483 #endif
1484
isTextButton() const1485 bool HTMLInputElement::isTextButton() const
1486 {
1487 return m_inputType->isTextButton();
1488 }
1489
isRadioButton() const1490 bool HTMLInputElement::isRadioButton() const
1491 {
1492 return m_inputType->isRadioButton();
1493 }
1494
isSearchField() const1495 bool HTMLInputElement::isSearchField() const
1496 {
1497 return m_inputType->isSearchField();
1498 }
1499
isInputTypeHidden() const1500 bool HTMLInputElement::isInputTypeHidden() const
1501 {
1502 return m_inputType->isHiddenType();
1503 }
1504
isPasswordField() const1505 bool HTMLInputElement::isPasswordField() const
1506 {
1507 return m_inputType->isPasswordField();
1508 }
1509
isCheckbox() const1510 bool HTMLInputElement::isCheckbox() const
1511 {
1512 return m_inputType->isCheckbox();
1513 }
1514
isText() const1515 bool HTMLInputElement::isText() const
1516 {
1517 return m_inputType->isTextType();
1518 }
1519
isEmailField() const1520 bool HTMLInputElement::isEmailField() const
1521 {
1522 return m_inputType->isEmailField();
1523 }
1524
isFileUpload() const1525 bool HTMLInputElement::isFileUpload() const
1526 {
1527 return m_inputType->isFileUpload();
1528 }
1529
isImageButton() const1530 bool HTMLInputElement::isImageButton() const
1531 {
1532 return m_inputType->isImageButton();
1533 }
1534
isNumberField() const1535 bool HTMLInputElement::isNumberField() const
1536 {
1537 return m_inputType->isNumberField();
1538 }
1539
isSubmitButton() const1540 bool HTMLInputElement::isSubmitButton() const
1541 {
1542 return m_inputType->isSubmitButton();
1543 }
1544
isTelephoneField() const1545 bool HTMLInputElement::isTelephoneField() const
1546 {
1547 return m_inputType->isTelephoneField();
1548 }
1549
isURLField() const1550 bool HTMLInputElement::isURLField() const
1551 {
1552 return m_inputType->isURLField();
1553 }
1554
isEnumeratable() const1555 bool HTMLInputElement::isEnumeratable() const
1556 {
1557 return m_inputType->isEnumeratable();
1558 }
1559
isChecked() const1560 bool HTMLInputElement::isChecked() const
1561 {
1562 return checked() && m_inputType->isCheckable();
1563 }
1564
hasSpinButton() const1565 bool HTMLInputElement::hasSpinButton() const
1566 {
1567 return m_inputType->hasSpinButton();
1568 }
1569
supportsPlaceholder() const1570 bool HTMLInputElement::supportsPlaceholder() const
1571 {
1572 #if PLATFORM(ANDROID)
1573 return isTextType() || isNumberField();
1574 #else
1575 return isTextType();
1576 #endif
1577 }
1578
checkedRadioButtons() const1579 CheckedRadioButtons& HTMLInputElement::checkedRadioButtons() const
1580 {
1581 if (HTMLFormElement* formElement = form())
1582 return formElement->checkedRadioButtons();
1583 return document()->checkedRadioButtons();
1584 }
1585
handleBeforeTextInsertedEvent(Event * event)1586 void HTMLInputElement::handleBeforeTextInsertedEvent(Event* event)
1587 {
1588 InputElement::handleBeforeTextInsertedEvent(m_data, this, this, event);
1589 }
1590
1591 #if PLATFORM(ANDROID) && ENABLE(MEDIA_CAPTURE)
capture() const1592 String HTMLInputElement::capture() const
1593 {
1594 if (!isFileUpload()) {
1595 // capture has no meaning on anything other than file pickers.
1596 return String();
1597 }
1598
1599 String capture = fastGetAttribute(captureAttr).lower();
1600 if (capture == "camera"
1601 || capture == "camcorder"
1602 || capture == "microphone"
1603 || capture == "filesystem")
1604 return capture;
1605 // According to the HTML Media Capture specification, the invalid and
1606 // missing default value is filesystem.
1607 return "filesystem";
1608 }
1609 #endif
1610
1611 } // namespace
1612