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 #ifdef ANDROID_ACCEPT_CHANGES_TO_FOCUSED_TEXTFIELDS
448 if (newType->isPasswordField() && document()->focusedNode() == this)
449 PlatformBridge::updateTextfield(document()->view(), this, true, String());
450 #endif
451 bool hadType = m_hasType;
452 m_hasType = true;
453 if (m_inputType->formControlType() == newType->formControlType())
454 return;
455
456 if (hadType && !newType->canChangeFromAnotherType()) {
457 // Set the attribute back to the old value.
458 // Useful in case we were called from inside parseMappedAttribute.
459 setAttribute(typeAttr, type());
460 return;
461 }
462
463 checkedRadioButtons().removeButton(this);
464
465 bool wasAttached = attached();
466 if (wasAttached)
467 detach();
468
469 bool didStoreValue = m_inputType->storesValueSeparateFromAttribute();
470 bool neededActivationCallback = needsActivationCallback();
471 bool didRespectHeightAndWidth = m_inputType->shouldRespectHeightAndWidthAttributes();
472
473 m_inputType->destroyShadowSubtree();
474 m_inputType = newType.release();
475 m_inputType->createShadowSubtree();
476
477 setNeedsWillValidateCheck();
478
479 bool willStoreValue = m_inputType->storesValueSeparateFromAttribute();
480
481 if (didStoreValue && !willStoreValue && !m_data.value().isNull()) {
482 setAttribute(valueAttr, m_data.value());
483 m_data.setValue(String());
484 }
485 if (!didStoreValue && willStoreValue)
486 m_data.setValue(sanitizeValue(fastGetAttribute(valueAttr)));
487 else
488 InputElement::updateValueIfNeeded(m_data, this);
489
490 if (neededActivationCallback)
491 unregisterForActivationCallbackIfNeeded();
492 else
493 registerForActivationCallbackIfNeeded();
494
495 if (didRespectHeightAndWidth != m_inputType->shouldRespectHeightAndWidthAttributes()) {
496 NamedNodeMap* map = attributeMap();
497 ASSERT(map);
498 if (Attribute* height = map->getAttributeItem(heightAttr))
499 attributeChanged(height, false);
500 if (Attribute* width = map->getAttributeItem(widthAttr))
501 attributeChanged(width, false);
502 if (Attribute* align = map->getAttributeItem(alignAttr))
503 attributeChanged(align, false);
504 }
505
506 if (wasAttached) {
507 attach();
508 if (document()->focusedNode() == this)
509 updateFocusAppearance(true);
510 }
511
512 setChangedSinceLastFormControlChangeEvent(false);
513
514 checkedRadioButtons().addButton(this);
515
516 setNeedsValidityCheck();
517 InputElement::notifyFormStateChanged(this);
518 }
519
formControlType() const520 const AtomicString& HTMLInputElement::formControlType() const
521 {
522 return m_inputType->formControlType();
523 }
524
saveFormControlState(String & result) const525 bool HTMLInputElement::saveFormControlState(String& result) const
526 {
527 return m_inputType->saveFormControlState(result);
528 }
529
restoreFormControlState(const String & state)530 void HTMLInputElement::restoreFormControlState(const String& state)
531 {
532 m_inputType->restoreFormControlState(state);
533 m_stateRestored = true;
534 }
535
canStartSelection() const536 bool HTMLInputElement::canStartSelection() const
537 {
538 if (!isTextField())
539 return false;
540 return HTMLFormControlElementWithState::canStartSelection();
541 }
542
canHaveSelection() const543 bool HTMLInputElement::canHaveSelection() const
544 {
545 return isTextField();
546 }
547
accessKeyAction(bool sendToAnyElement)548 void HTMLInputElement::accessKeyAction(bool sendToAnyElement)
549 {
550 m_inputType->accessKeyAction(sendToAnyElement);
551 }
552
mapToEntry(const QualifiedName & attrName,MappedAttributeEntry & result) const553 bool HTMLInputElement::mapToEntry(const QualifiedName& attrName, MappedAttributeEntry& result) const
554 {
555 if (((attrName == heightAttr || attrName == widthAttr) && m_inputType->shouldRespectHeightAndWidthAttributes())
556 || attrName == vspaceAttr
557 || attrName == hspaceAttr) {
558 result = eUniversal;
559 return false;
560 }
561
562 if (attrName == alignAttr && m_inputType->shouldRespectAlignAttribute()) {
563 // Share with <img> since the alignment behavior is the same.
564 result = eReplaced;
565 return false;
566 }
567
568 return HTMLElement::mapToEntry(attrName, result);
569 }
570
parseMappedAttribute(Attribute * attr)571 void HTMLInputElement::parseMappedAttribute(Attribute* attr)
572 {
573 if (attr->name() == nameAttr) {
574 checkedRadioButtons().removeButton(this);
575 m_data.setName(attr->value());
576 checkedRadioButtons().addButton(this);
577 HTMLFormControlElementWithState::parseMappedAttribute(attr);
578 } else if (attr->name() == autocompleteAttr) {
579 if (equalIgnoringCase(attr->value(), "off")) {
580 m_autocomplete = Off;
581 registerForActivationCallbackIfNeeded();
582 } else {
583 bool needsToUnregister = m_autocomplete == Off;
584
585 if (attr->isEmpty())
586 m_autocomplete = Uninitialized;
587 else
588 m_autocomplete = On;
589
590 if (needsToUnregister)
591 unregisterForActivationCallbackIfNeeded();
592 }
593 } else if (attr->name() == typeAttr) {
594 updateType();
595 } else if (attr->name() == valueAttr) {
596 // We only need to setChanged if the form is looking at the default value right now.
597 if (m_data.value().isNull())
598 setNeedsStyleRecalc();
599 setFormControlValueMatchesRenderer(false);
600 setNeedsValidityCheck();
601 } else if (attr->name() == checkedAttr) {
602 // Another radio button in the same group might be checked by state
603 // restore. We shouldn't call setChecked() even if this has the checked
604 // attribute. So, delay the setChecked() call until
605 // finishParsingChildren() is called if parsing is in progress.
606 if (!m_parsingInProgress && m_reflectsCheckedAttribute) {
607 setChecked(!attr->isNull());
608 m_reflectsCheckedAttribute = true;
609 }
610 } else if (attr->name() == maxlengthAttr) {
611 InputElement::parseMaxLengthAttribute(m_data, this, this, attr);
612 setNeedsValidityCheck();
613 } else if (attr->name() == sizeAttr)
614 InputElement::parseSizeAttribute(m_data, this, attr);
615 else if (attr->name() == altAttr)
616 m_inputType->altAttributeChanged();
617 else if (attr->name() == srcAttr)
618 m_inputType->srcAttributeChanged();
619 else if (attr->name() == usemapAttr || attr->name() == accesskeyAttr) {
620 // FIXME: ignore for the moment
621 } else if (attr->name() == vspaceAttr) {
622 addCSSLength(attr, CSSPropertyMarginTop, attr->value());
623 addCSSLength(attr, CSSPropertyMarginBottom, attr->value());
624 } else if (attr->name() == hspaceAttr) {
625 addCSSLength(attr, CSSPropertyMarginLeft, attr->value());
626 addCSSLength(attr, CSSPropertyMarginRight, attr->value());
627 } else if (attr->name() == alignAttr) {
628 if (m_inputType->shouldRespectAlignAttribute())
629 addHTMLAlignment(attr);
630 } else if (attr->name() == widthAttr) {
631 if (m_inputType->shouldRespectHeightAndWidthAttributes())
632 addCSSLength(attr, CSSPropertyWidth, attr->value());
633 } else if (attr->name() == heightAttr) {
634 if (m_inputType->shouldRespectHeightAndWidthAttributes())
635 addCSSLength(attr, CSSPropertyHeight, attr->value());
636 } else if (attr->name() == onsearchAttr) {
637 // Search field and slider attributes all just cause updateFromElement to be called through style recalcing.
638 setAttributeEventListener(eventNames().searchEvent, createAttributeEventListener(this, attr));
639 } else if (attr->name() == resultsAttr) {
640 int oldResults = m_maxResults;
641 m_maxResults = !attr->isNull() ? std::min(attr->value().toInt(), maxSavedResults) : -1;
642 // FIXME: Detaching just for maxResults change is not ideal. We should figure out the right
643 // time to relayout for this change.
644 if (m_maxResults != oldResults && (m_maxResults <= 0 || oldResults <= 0) && attached()) {
645 detach();
646 attach();
647 }
648 setNeedsStyleRecalc();
649 } else if (attr->name() == autosaveAttr || attr->name() == incrementalAttr)
650 setNeedsStyleRecalc();
651 else if (attr->name() == minAttr || attr->name() == maxAttr) {
652 m_inputType->minOrMaxAttributeChanged();
653 setNeedsValidityCheck();
654 } else if (attr->name() == multipleAttr || attr->name() == patternAttr || attr->name() == precisionAttr || attr->name() == stepAttr)
655 setNeedsValidityCheck();
656 #if ENABLE(DATALIST)
657 else if (attr->name() == listAttr)
658 m_hasNonEmptyList = !attr->isEmpty();
659 // FIXME: we need to tell this change to a renderer if the attribute affects the appearance.
660 #endif
661 #if ENABLE(INPUT_SPEECH)
662 else if (attr->name() == webkitspeechAttr) {
663 if (renderer()) {
664 // This renderer and its children have quite different layouts and styles depending on
665 // whether the speech button is visible or not. So we reset the whole thing and recreate
666 // to get the right styles and layout.
667 detach();
668 attach();
669 }
670 setNeedsStyleRecalc();
671 } else if (attr->name() == onwebkitspeechchangeAttr)
672 setAttributeEventListener(eventNames().webkitspeechchangeEvent, createAttributeEventListener(this, attr));
673 #endif
674 else
675 HTMLTextFormControlElement::parseMappedAttribute(attr);
676 }
677
finishParsingChildren()678 void HTMLInputElement::finishParsingChildren()
679 {
680 m_parsingInProgress = false;
681 HTMLFormControlElementWithState::finishParsingChildren();
682 if (!m_stateRestored) {
683 bool checked = hasAttribute(checkedAttr);
684 if (checked)
685 setChecked(checked);
686 m_reflectsCheckedAttribute = true;
687 }
688 }
689
rendererIsNeeded(RenderStyle * style)690 bool HTMLInputElement::rendererIsNeeded(RenderStyle* style)
691 {
692 return m_inputType->rendererIsNeeded() && HTMLFormControlElementWithState::rendererIsNeeded(style);
693 }
694
createRenderer(RenderArena * arena,RenderStyle * style)695 RenderObject* HTMLInputElement::createRenderer(RenderArena* arena, RenderStyle* style)
696 {
697 return m_inputType->createRenderer(arena, style);
698 }
699
attach()700 void HTMLInputElement::attach()
701 {
702 suspendPostAttachCallbacks();
703
704 if (!m_hasType)
705 updateType();
706
707 HTMLFormControlElementWithState::attach();
708
709 m_inputType->attach();
710
711 if (document()->focusedNode() == this)
712 document()->updateFocusAppearanceSoon(true /* restore selection */);
713
714 resumePostAttachCallbacks();
715 }
716
detach()717 void HTMLInputElement::detach()
718 {
719 HTMLFormControlElementWithState::detach();
720 setFormControlValueMatchesRenderer(false);
721 }
722
altText() const723 String HTMLInputElement::altText() const
724 {
725 // http://www.w3.org/TR/1998/REC-html40-19980424/appendix/notes.html#altgen
726 // also heavily discussed by Hixie on bugzilla
727 // note this is intentionally different to HTMLImageElement::altText()
728 String alt = fastGetAttribute(altAttr);
729 // fall back to title attribute
730 if (alt.isNull())
731 alt = getAttribute(titleAttr);
732 if (alt.isNull())
733 alt = getAttribute(valueAttr);
734 if (alt.isEmpty())
735 alt = inputElementAltText();
736 return alt;
737 }
738
isSuccessfulSubmitButton() const739 bool HTMLInputElement::isSuccessfulSubmitButton() const
740 {
741 // HTML spec says that buttons must have names to be considered successful.
742 // However, other browsers do not impose this constraint. So we do not.
743 return !disabled() && m_inputType->canBeSuccessfulSubmitButton();
744 }
745
isActivatedSubmit() const746 bool HTMLInputElement::isActivatedSubmit() const
747 {
748 return m_isActivatedSubmit;
749 }
750
setActivatedSubmit(bool flag)751 void HTMLInputElement::setActivatedSubmit(bool flag)
752 {
753 m_isActivatedSubmit = flag;
754 }
755
appendFormData(FormDataList & encoding,bool multipart)756 bool HTMLInputElement::appendFormData(FormDataList& encoding, bool multipart)
757 {
758 return m_inputType->isFormDataAppendable() && m_inputType->appendFormData(encoding, multipart);
759 }
760
reset()761 void HTMLInputElement::reset()
762 {
763 if (m_inputType->storesValueSeparateFromAttribute())
764 setValue(String());
765
766 setAutofilled(false);
767 setChecked(hasAttribute(checkedAttr));
768 m_reflectsCheckedAttribute = true;
769 }
770
isTextField() const771 bool HTMLInputElement::isTextField() const
772 {
773 return m_inputType->isTextField();
774 }
775
isTextType() const776 bool HTMLInputElement::isTextType() const
777 {
778 return m_inputType->isTextType();
779 }
780
setChecked(bool nowChecked,bool sendChangeEvent)781 void HTMLInputElement::setChecked(bool nowChecked, bool sendChangeEvent)
782 {
783 if (checked() == nowChecked)
784 return;
785
786 checkedRadioButtons().removeButton(this);
787
788 m_reflectsCheckedAttribute = false;
789 m_isChecked = nowChecked;
790 setNeedsStyleRecalc();
791
792 updateCheckedRadioButtons();
793 setNeedsValidityCheck();
794
795 // Ideally we'd do this from the render tree (matching
796 // RenderTextView), but it's not possible to do it at the moment
797 // because of the way the code is structured.
798 if (renderer() && AXObjectCache::accessibilityEnabled())
799 renderer()->document()->axObjectCache()->postNotification(renderer(), AXObjectCache::AXCheckedStateChanged, true);
800
801 // Only send a change event for items in the document (avoid firing during
802 // parsing) and don't send a change event for a radio button that's getting
803 // unchecked to match other browsers. DOM is not a useful standard for this
804 // because it says only to fire change events at "lose focus" time, which is
805 // definitely wrong in practice for these types of elements.
806 if (sendChangeEvent && inDocument() && m_inputType->shouldSendChangeEventAfterCheckedChanged()) {
807 setTextAsOfLastFormControlChangeEvent(String());
808 dispatchFormControlChangeEvent();
809 }
810 }
811
setIndeterminate(bool newValue)812 void HTMLInputElement::setIndeterminate(bool newValue)
813 {
814 if (!m_inputType->isCheckable() || indeterminate() == newValue)
815 return;
816
817 m_isIndeterminate = newValue;
818
819 setNeedsStyleRecalc();
820
821 if (renderer() && renderer()->style()->hasAppearance())
822 renderer()->theme()->stateChanged(renderer(), CheckedState);
823 }
824
size() const825 int HTMLInputElement::size() const
826 {
827 return m_data.size();
828 }
829
copyNonAttributeProperties(const Element * source)830 void HTMLInputElement::copyNonAttributeProperties(const Element* source)
831 {
832 const HTMLInputElement* sourceElement = static_cast<const HTMLInputElement*>(source);
833
834 m_data.setValue(sourceElement->m_data.value());
835 setChecked(sourceElement->m_isChecked);
836 m_reflectsCheckedAttribute = sourceElement->m_reflectsCheckedAttribute;
837 m_isIndeterminate = sourceElement->m_isIndeterminate;
838
839 HTMLFormControlElementWithState::copyNonAttributeProperties(source);
840 }
841
value() const842 String HTMLInputElement::value() const
843 {
844 String value;
845 if (m_inputType->getTypeSpecificValue(value))
846 return value;
847
848 value = m_data.value();
849 if (!value.isNull())
850 return value;
851
852 value = sanitizeValue(fastGetAttribute(valueAttr));
853 if (!value.isNull())
854 return value;
855
856 return m_inputType->fallbackValue();
857 }
858
valueWithDefault() const859 String HTMLInputElement::valueWithDefault() const
860 {
861 String value = this->value();
862 if (!value.isNull())
863 return value;
864
865 return m_inputType->defaultValue();
866 }
867
setValueForUser(const String & value)868 void HTMLInputElement::setValueForUser(const String& value)
869 {
870 // Call setValue and make it send a change event.
871 setValue(value, true);
872 }
873
suggestedValue() const874 const String& HTMLInputElement::suggestedValue() const
875 {
876 return m_data.suggestedValue();
877 }
878
setSuggestedValue(const String & value)879 void HTMLInputElement::setSuggestedValue(const String& value)
880 {
881 if (!m_inputType->canSetSuggestedValue())
882 return;
883 setFormControlValueMatchesRenderer(false);
884 m_data.setSuggestedValue(sanitizeValue(value));
885 updatePlaceholderVisibility(false);
886 if (renderer())
887 renderer()->updateFromElement();
888 setNeedsStyleRecalc();
889 }
890
setValue(const String & value,bool sendChangeEvent)891 void HTMLInputElement::setValue(const String& value, bool sendChangeEvent)
892 {
893 if (!m_inputType->canSetValue(value))
894 return;
895
896 setFormControlValueMatchesRenderer(false);
897 if (m_inputType->storesValueSeparateFromAttribute()) {
898 if (files())
899 files()->clear();
900 else {
901 m_data.setValue(sanitizeValue(value));
902 if (isTextField())
903 updatePlaceholderVisibility(false);
904 }
905 setNeedsStyleRecalc();
906 } else
907 setAttribute(valueAttr, sanitizeValue(value));
908
909 setNeedsValidityCheck();
910
911 if (isTextField()) {
912 unsigned max = m_data.value().length();
913 #ifdef ANDROID_ACCEPT_CHANGES_TO_FOCUSED_TEXTFIELDS
914 // Make sure our UI side textfield changes to match the RenderTextControl
915 PlatformBridge::updateTextfield(document()->view(), this, false, value);
916 #endif
917 if (document()->focusedNode() == this)
918 InputElement::updateSelectionRange(this, this, max, max);
919 else
920 cacheSelection(max, max);
921 m_data.setSuggestedValue(String());
922 }
923 m_inputType->valueChanged();
924
925 if (sendChangeEvent) {
926 // If the user is still editing this field, dispatch an input event rather than a change event.
927 // The change event will be dispatched when editing finishes.
928 if (isTextField() && focused())
929 dispatchFormControlInputEvent();
930 else
931 dispatchFormControlChangeEvent();
932 }
933
934 if (isText() && (!focused() || !sendChangeEvent))
935 setTextAsOfLastFormControlChangeEvent(value);
936
937 InputElement::notifyFormStateChanged(this);
938 }
939
valueAsDate() const940 double HTMLInputElement::valueAsDate() const
941 {
942 return m_inputType->valueAsDate();
943 }
944
setValueAsDate(double value,ExceptionCode & ec)945 void HTMLInputElement::setValueAsDate(double value, ExceptionCode& ec)
946 {
947 m_inputType->setValueAsDate(value, ec);
948 }
949
valueAsNumber() const950 double HTMLInputElement::valueAsNumber() const
951 {
952 return m_inputType->valueAsNumber();
953 }
954
setValueAsNumber(double newValue,ExceptionCode & ec)955 void HTMLInputElement::setValueAsNumber(double newValue, ExceptionCode& ec)
956 {
957 if (!isfinite(newValue)) {
958 ec = NOT_SUPPORTED_ERR;
959 return;
960 }
961 m_inputType->setValueAsNumber(newValue, ec);
962 }
963
placeholder() const964 String HTMLInputElement::placeholder() const
965 {
966 return fastGetAttribute(placeholderAttr).string();
967 }
968
setPlaceholder(const String & value)969 void HTMLInputElement::setPlaceholder(const String& value)
970 {
971 setAttribute(placeholderAttr, value);
972 }
973
searchEventsShouldBeDispatched() const974 bool HTMLInputElement::searchEventsShouldBeDispatched() const
975 {
976 return hasAttribute(incrementalAttr);
977 }
978
setValueFromRenderer(const String & value)979 void HTMLInputElement::setValueFromRenderer(const String& value)
980 {
981 // File upload controls will always use setFileListFromRenderer.
982 ASSERT(!isFileUpload());
983
984 m_data.setSuggestedValue(String());
985 InputElement::setValueFromRenderer(m_data, this, this, value);
986 updatePlaceholderVisibility(false);
987 setNeedsValidityCheck();
988
989 // Clear autofill flag (and yellow background) on user edit.
990 setAutofilled(false);
991 }
992
setFileListFromRenderer(const Vector<String> & paths)993 void HTMLInputElement::setFileListFromRenderer(const Vector<String>& paths)
994 {
995 m_inputType->setFileList(paths);
996
997 setFormControlValueMatchesRenderer(true);
998 InputElement::notifyFormStateChanged(this);
999 setNeedsValidityCheck();
1000 }
1001
preDispatchEventHandler(Event * event)1002 void* HTMLInputElement::preDispatchEventHandler(Event* event)
1003 {
1004 if (event->type() == eventNames().textInputEvent && m_inputType->shouldSubmitImplicitly(event)) {
1005 event->stopPropagation();
1006 return 0;
1007 }
1008 if (event->type() != eventNames().clickEvent)
1009 return 0;
1010 if (!event->isMouseEvent() || static_cast<MouseEvent*>(event)->button() != LeftButton)
1011 return 0;
1012 // FIXME: Check whether there are any cases where this actually ends up leaking.
1013 return m_inputType->willDispatchClick().leakPtr();
1014 }
1015
postDispatchEventHandler(Event * event,void * dataFromPreDispatch)1016 void HTMLInputElement::postDispatchEventHandler(Event* event, void* dataFromPreDispatch)
1017 {
1018 OwnPtr<ClickHandlingState> state = adoptPtr(static_cast<ClickHandlingState*>(dataFromPreDispatch));
1019 if (!state)
1020 return;
1021 m_inputType->didDispatchClick(event, *state);
1022 }
1023
defaultEventHandler(Event * evt)1024 void HTMLInputElement::defaultEventHandler(Event* evt)
1025 {
1026 if (evt->isMouseEvent() && evt->type() == eventNames().clickEvent && static_cast<MouseEvent*>(evt)->button() == LeftButton) {
1027 m_inputType->handleClickEvent(static_cast<MouseEvent*>(evt));
1028 if (evt->defaultHandled())
1029 return;
1030 }
1031
1032 if (evt->isKeyboardEvent() && evt->type() == eventNames().keydownEvent) {
1033 m_inputType->handleKeydownEvent(static_cast<KeyboardEvent*>(evt));
1034 if (evt->defaultHandled())
1035 return;
1036 }
1037
1038 // Call the base event handler before any of our own event handling for almost all events in text fields.
1039 // Makes editing keyboard handling take precedence over the keydown and keypress handling in this function.
1040 bool callBaseClassEarly = isTextField() && (evt->type() == eventNames().keydownEvent || evt->type() == eventNames().keypressEvent);
1041 if (callBaseClassEarly) {
1042 HTMLFormControlElementWithState::defaultEventHandler(evt);
1043 if (evt->defaultHandled())
1044 return;
1045 }
1046
1047 // DOMActivate events cause the input to be "activated" - in the case of image and submit inputs, this means
1048 // actually submitting the form. For reset inputs, the form is reset. These events are sent when the user clicks
1049 // on the element, or presses enter while it is the active element. JavaScript code wishing to activate the element
1050 // must dispatch a DOMActivate event - a click event will not do the job.
1051 if (evt->type() == eventNames().DOMActivateEvent) {
1052 m_inputType->handleDOMActivateEvent(evt);
1053 if (evt->defaultHandled())
1054 return;
1055 }
1056
1057 // Use key press event here since sending simulated mouse events
1058 // on key down blocks the proper sending of the key press event.
1059 if (evt->isKeyboardEvent() && evt->type() == eventNames().keypressEvent) {
1060 m_inputType->handleKeypressEvent(static_cast<KeyboardEvent*>(evt));
1061 if (evt->defaultHandled())
1062 return;
1063 }
1064
1065 if (evt->isKeyboardEvent() && evt->type() == eventNames().keyupEvent) {
1066 m_inputType->handleKeyupEvent(static_cast<KeyboardEvent*>(evt));
1067 if (evt->defaultHandled())
1068 return;
1069 }
1070
1071 if (m_inputType->shouldSubmitImplicitly(evt)) {
1072 if (isSearchField()) {
1073 addSearchResult();
1074 onSearch();
1075 }
1076 // Form submission finishes editing, just as loss of focus does.
1077 // If there was a change, send the event now.
1078 if (wasChangedSinceLastFormControlChangeEvent())
1079 dispatchFormControlChangeEvent();
1080
1081 RefPtr<HTMLFormElement> formForSubmission = m_inputType->formForSubmission();
1082 // Form may never have been present, or may have been destroyed by code responding to the change event.
1083 if (formForSubmission)
1084 formForSubmission->submitImplicitly(evt, canTriggerImplicitSubmission());
1085
1086 evt->setDefaultHandled();
1087 return;
1088 }
1089
1090 if (evt->isBeforeTextInsertedEvent())
1091 m_inputType->handleBeforeTextInsertedEvent(static_cast<BeforeTextInsertedEvent*>(evt));
1092
1093 if (evt->isWheelEvent()) {
1094 m_inputType->handleWheelEvent(static_cast<WheelEvent*>(evt));
1095 if (evt->defaultHandled())
1096 return;
1097 }
1098
1099 if (evt->isMouseEvent() && evt->type() == eventNames().mousedownEvent) {
1100 m_inputType->handleMouseDownEvent(static_cast<MouseEvent*>(evt));
1101 if (evt->defaultHandled())
1102 return;
1103 }
1104
1105 #if PLATFORM(ANDROID) && ENABLE(TOUCH_EVENTS)
1106 if (evt->isTouchEvent() && evt->type() == eventNames().touchstartEvent) {
1107 m_inputType->handleTouchStartEvent(static_cast<TouchEvent*>(evt));
1108 if (evt->defaultHandled())
1109 return;
1110 }
1111 #endif
1112
1113 m_inputType->forwardEvent(evt);
1114
1115 if (!callBaseClassEarly && !evt->defaultHandled())
1116 HTMLFormControlElementWithState::defaultEventHandler(evt);
1117 }
1118
isURLAttribute(Attribute * attr) const1119 bool HTMLInputElement::isURLAttribute(Attribute *attr) const
1120 {
1121 return (attr->name() == srcAttr || attr->name() == formactionAttr);
1122 }
1123
defaultValue() const1124 String HTMLInputElement::defaultValue() const
1125 {
1126 return fastGetAttribute(valueAttr);
1127 }
1128
setDefaultValue(const String & value)1129 void HTMLInputElement::setDefaultValue(const String &value)
1130 {
1131 setAttribute(valueAttr, value);
1132 }
1133
setDefaultName(const AtomicString & name)1134 void HTMLInputElement::setDefaultName(const AtomicString& name)
1135 {
1136 m_data.setName(name);
1137 }
1138
accept() const1139 String HTMLInputElement::accept() const
1140 {
1141 return fastGetAttribute(acceptAttr);
1142 }
1143
alt() const1144 String HTMLInputElement::alt() const
1145 {
1146 return fastGetAttribute(altAttr);
1147 }
1148
maxLength() const1149 int HTMLInputElement::maxLength() const
1150 {
1151 return m_data.maxLength();
1152 }
1153
setMaxLength(int maxLength,ExceptionCode & ec)1154 void HTMLInputElement::setMaxLength(int maxLength, ExceptionCode& ec)
1155 {
1156 if (maxLength < 0)
1157 ec = INDEX_SIZE_ERR;
1158 else
1159 setAttribute(maxlengthAttr, String::number(maxLength));
1160 }
1161
multiple() const1162 bool HTMLInputElement::multiple() const
1163 {
1164 return fastHasAttribute(multipleAttr);
1165 }
1166
setSize(unsigned size)1167 void HTMLInputElement::setSize(unsigned size)
1168 {
1169 setAttribute(sizeAttr, String::number(size));
1170 }
1171
src() const1172 KURL HTMLInputElement::src() const
1173 {
1174 return document()->completeURL(fastGetAttribute(srcAttr));
1175 }
1176
setAutofilled(bool autofilled)1177 void HTMLInputElement::setAutofilled(bool autofilled)
1178 {
1179 if (autofilled == m_isAutofilled)
1180 return;
1181
1182 m_isAutofilled = autofilled;
1183 setNeedsStyleRecalc();
1184 }
1185
files()1186 FileList* HTMLInputElement::files()
1187 {
1188 return m_inputType->files();
1189 }
1190
visibleValue() const1191 String HTMLInputElement::visibleValue() const
1192 {
1193 return m_inputType->visibleValue();
1194 }
1195
convertFromVisibleValue(const String & visibleValue) const1196 String HTMLInputElement::convertFromVisibleValue(const String& visibleValue) const
1197 {
1198 return m_inputType->convertFromVisibleValue(visibleValue);
1199 }
1200
isAcceptableValue(const String & proposedValue) const1201 bool HTMLInputElement::isAcceptableValue(const String& proposedValue) const
1202 {
1203 return m_inputType->isAcceptableValue(proposedValue);
1204 }
1205
sanitizeValue(const String & proposedValue) const1206 String HTMLInputElement::sanitizeValue(const String& proposedValue) const
1207 {
1208 return m_inputType->sanitizeValue(proposedValue);
1209 }
1210
hasUnacceptableValue() const1211 bool HTMLInputElement::hasUnacceptableValue() const
1212 {
1213 return m_inputType->hasUnacceptableValue();
1214 }
1215
isInRange() const1216 bool HTMLInputElement::isInRange() const
1217 {
1218 return m_inputType->supportsRangeLimitation() && !rangeUnderflow(value()) && !rangeOverflow(value());
1219 }
1220
isOutOfRange() const1221 bool HTMLInputElement::isOutOfRange() const
1222 {
1223 return m_inputType->supportsRangeLimitation() && (rangeUnderflow(value()) || rangeOverflow(value()));
1224 }
1225
needsActivationCallback()1226 bool HTMLInputElement::needsActivationCallback()
1227 {
1228 return m_autocomplete == Off || m_inputType->shouldResetOnDocumentActivation();
1229 }
1230
registerForActivationCallbackIfNeeded()1231 void HTMLInputElement::registerForActivationCallbackIfNeeded()
1232 {
1233 if (needsActivationCallback())
1234 document()->registerForDocumentActivationCallbacks(this);
1235 }
1236
unregisterForActivationCallbackIfNeeded()1237 void HTMLInputElement::unregisterForActivationCallbackIfNeeded()
1238 {
1239 if (!needsActivationCallback())
1240 document()->unregisterForDocumentActivationCallbacks(this);
1241 }
1242
isRequiredFormControl() const1243 bool HTMLInputElement::isRequiredFormControl() const
1244 {
1245 return m_inputType->supportsRequired() && required();
1246 }
1247
cacheSelection(int start,int end)1248 void HTMLInputElement::cacheSelection(int start, int end)
1249 {
1250 m_data.setCachedSelectionStart(start);
1251 m_data.setCachedSelectionEnd(end);
1252 }
1253
addSearchResult()1254 void HTMLInputElement::addSearchResult()
1255 {
1256 ASSERT(isSearchField());
1257 if (renderer())
1258 toRenderTextControlSingleLine(renderer())->addSearchResult();
1259 }
1260
onSearch()1261 void HTMLInputElement::onSearch()
1262 {
1263 ASSERT(isSearchField());
1264 if (renderer())
1265 toRenderTextControlSingleLine(renderer())->stopSearchEventTimer();
1266 dispatchEvent(Event::create(eventNames().searchEvent, true, false));
1267 }
1268
documentDidBecomeActive()1269 void HTMLInputElement::documentDidBecomeActive()
1270 {
1271 ASSERT(needsActivationCallback());
1272 reset();
1273 }
1274
willMoveToNewOwnerDocument()1275 void HTMLInputElement::willMoveToNewOwnerDocument()
1276 {
1277 m_inputType->willMoveToNewOwnerDocument();
1278
1279 // Always unregister for cache callbacks when leaving a document, even if we would otherwise like to be registered
1280 if (needsActivationCallback())
1281 document()->unregisterForDocumentActivationCallbacks(this);
1282
1283 document()->checkedRadioButtons().removeButton(this);
1284
1285 HTMLFormControlElementWithState::willMoveToNewOwnerDocument();
1286 }
1287
didMoveToNewOwnerDocument()1288 void HTMLInputElement::didMoveToNewOwnerDocument()
1289 {
1290 registerForActivationCallbackIfNeeded();
1291
1292 HTMLFormControlElementWithState::didMoveToNewOwnerDocument();
1293 }
1294
addSubresourceAttributeURLs(ListHashSet<KURL> & urls) const1295 void HTMLInputElement::addSubresourceAttributeURLs(ListHashSet<KURL>& urls) const
1296 {
1297 HTMLFormControlElementWithState::addSubresourceAttributeURLs(urls);
1298
1299 addSubresourceURL(urls, src());
1300 }
1301
recalcWillValidate() const1302 bool HTMLInputElement::recalcWillValidate() const
1303 {
1304 return m_inputType->supportsValidation() && HTMLFormControlElementWithState::recalcWillValidate();
1305 }
1306
1307 #if ENABLE(DATALIST)
1308
list() const1309 HTMLElement* HTMLInputElement::list() const
1310 {
1311 return dataList();
1312 }
1313
dataList() const1314 HTMLDataListElement* HTMLInputElement::dataList() const
1315 {
1316 if (!m_hasNonEmptyList)
1317 return 0;
1318
1319 if (!m_inputType->shouldRespectListAttribute())
1320 return 0;
1321
1322 Element* element = document()->getElementById(fastGetAttribute(listAttr));
1323 if (!element)
1324 return 0;
1325 if (!element->hasTagName(datalistTag))
1326 return 0;
1327
1328 return static_cast<HTMLDataListElement*>(element);
1329 }
1330
selectedOption() const1331 HTMLOptionElement* HTMLInputElement::selectedOption() const
1332 {
1333 String value = this->value();
1334
1335 // The empty string never matches to a datalist option because it
1336 // doesn't represent a suggestion according to the standard.
1337 if (value.isEmpty())
1338 return 0;
1339
1340 HTMLDataListElement* sourceElement = dataList();
1341 if (!sourceElement)
1342 return 0;
1343 RefPtr<HTMLCollection> options = sourceElement->options();
1344 if (!options)
1345 return 0;
1346 unsigned length = options->length();
1347 for (unsigned i = 0; i < length; ++i) {
1348 HTMLOptionElement* option = static_cast<HTMLOptionElement*>(options->item(i));
1349 if (!option->disabled() && value == option->value())
1350 return option;
1351 }
1352 return 0;
1353 }
1354
1355 #endif // ENABLE(DATALIST)
1356
stepUpFromRenderer(int n)1357 void HTMLInputElement::stepUpFromRenderer(int n)
1358 {
1359 // The differences from stepUp()/stepDown():
1360 //
1361 // Difference 1: the current value
1362 // If the current value is not a number, including empty, the current value is assumed as 0.
1363 // * If 0 is in-range, and matches to step value
1364 // - The value should be the +step if n > 0
1365 // - The value should be the -step if n < 0
1366 // If -step or +step is out of range, new value should be 0.
1367 // * If 0 is smaller than the minimum value
1368 // - The value should be the minimum value for any n
1369 // * If 0 is larger than the maximum value
1370 // - The value should be the maximum value for any n
1371 // * If 0 is in-range, but not matched to step value
1372 // - The value should be the larger matched value nearest to 0 if n > 0
1373 // e.g. <input type=number min=-100 step=3> -> 2
1374 // - The value should be the smaler matched value nearest to 0 if n < 0
1375 // e.g. <input type=number min=-100 step=3> -> -1
1376 // As for date/datetime-local/month/time/week types, the current value is assumed as "the current local date/time".
1377 // As for datetime type, the current value is assumed as "the current date/time in UTC".
1378 // If the current value is smaller than the minimum value:
1379 // - The value should be the minimum value if n > 0
1380 // - Nothing should happen if n < 0
1381 // If the current value is larger than the maximum value:
1382 // - The value should be the maximum value if n < 0
1383 // - Nothing should happen if n > 0
1384 //
1385 // Difference 2: clamping steps
1386 // If the current value is not matched to step value:
1387 // - The value should be the larger matched value nearest to 0 if n > 0
1388 // e.g. <input type=number value=3 min=-100 step=3> -> 5
1389 // - The value should be the smaler matched value nearest to 0 if n < 0
1390 // e.g. <input type=number value=3 min=-100 step=3> -> 2
1391 //
1392 // n is assumed as -n if step < 0.
1393
1394 ASSERT(hasSpinButton() || m_inputType->isRangeControl());
1395 if (!hasSpinButton() && !m_inputType->isRangeControl())
1396 return;
1397 ASSERT(n);
1398 if (!n)
1399 return;
1400
1401 unsigned stepDecimalPlaces, baseDecimalPlaces;
1402 double step, base;
1403 // The value will be the default value after stepping for <input value=(empty/invalid) step="any" />
1404 // FIXME: Not any changes after stepping, even if it is an invalid value, may be better.
1405 // (e.g. Stepping-up for <input type="number" value="foo" step="any" /> => "foo")
1406 if (equalIgnoringCase(fastGetAttribute(stepAttr), "any"))
1407 step = 0;
1408 else if (!getAllowedValueStepWithDecimalPlaces(&step, &stepDecimalPlaces))
1409 return;
1410 base = m_inputType->stepBaseWithDecimalPlaces(&baseDecimalPlaces);
1411 baseDecimalPlaces = min(baseDecimalPlaces, 16u);
1412
1413 int sign;
1414 if (step > 0)
1415 sign = n;
1416 else if (step < 0)
1417 sign = -n;
1418 else
1419 sign = 0;
1420
1421 const double nan = numeric_limits<double>::quiet_NaN();
1422 String currentStringValue = value();
1423 double current = m_inputType->parseToDouble(currentStringValue, nan);
1424 if (!isfinite(current)) {
1425 ExceptionCode ec;
1426 current = m_inputType->defaultValueForStepUp();
1427 setValueAsNumber(current, ec);
1428 }
1429 if ((sign > 0 && current < m_inputType->minimum()) || (sign < 0 && current > m_inputType->maximum()))
1430 setValue(m_inputType->serialize(sign > 0 ? m_inputType->minimum() : m_inputType->maximum()));
1431 else {
1432 ExceptionCode ec;
1433 if (stepMismatch(currentStringValue)) {
1434 ASSERT(step);
1435 double newValue;
1436 double scale = pow(10.0, static_cast<double>(max(stepDecimalPlaces, baseDecimalPlaces)));
1437
1438 if (sign < 0)
1439 newValue = round((base + floor((current - base) / step) * step) * scale) / scale;
1440 else if (sign > 0)
1441 newValue = round((base + ceil((current - base) / step) * step) * scale) / scale;
1442 else
1443 newValue = current;
1444
1445 if (newValue < m_inputType->minimum())
1446 newValue = m_inputType->minimum();
1447 if (newValue > m_inputType->maximum())
1448 newValue = m_inputType->maximum();
1449
1450 setValueAsNumber(newValue, ec);
1451 current = newValue;
1452 if (n > 1)
1453 applyStep(n - 1, ec);
1454 else if (n < -1)
1455 applyStep(n + 1, ec);
1456 } else
1457 applyStep(n, ec);
1458 }
1459
1460 if (currentStringValue != value()) {
1461 if (m_inputType->isRangeControl())
1462 dispatchFormControlChangeEvent();
1463 else
1464 dispatchFormControlInputEvent();
1465 }
1466 }
1467
1468 #if ENABLE(WCSS)
1469
setWapInputFormat(String & mask)1470 void HTMLInputElement::setWapInputFormat(String& mask)
1471 {
1472 String validateMask = validateInputMask(m_data, mask);
1473 if (!validateMask.isEmpty())
1474 m_data.setInputFormatMask(validateMask);
1475 }
1476
1477 #endif
1478
1479 #if ENABLE(INPUT_SPEECH)
1480
isSpeechEnabled() const1481 bool HTMLInputElement::isSpeechEnabled() const
1482 {
1483 // FIXME: Add support for RANGE, EMAIL, URL, COLOR and DATE/TIME input types.
1484 return m_inputType->shouldRespectSpeechAttribute() && RuntimeEnabledFeatures::speechInputEnabled() && hasAttribute(webkitspeechAttr);
1485 }
1486
1487 #endif
1488
isTextButton() const1489 bool HTMLInputElement::isTextButton() const
1490 {
1491 return m_inputType->isTextButton();
1492 }
1493
isRadioButton() const1494 bool HTMLInputElement::isRadioButton() const
1495 {
1496 return m_inputType->isRadioButton();
1497 }
1498
isSearchField() const1499 bool HTMLInputElement::isSearchField() const
1500 {
1501 return m_inputType->isSearchField();
1502 }
1503
isInputTypeHidden() const1504 bool HTMLInputElement::isInputTypeHidden() const
1505 {
1506 return m_inputType->isHiddenType();
1507 }
1508
isPasswordField() const1509 bool HTMLInputElement::isPasswordField() const
1510 {
1511 return m_inputType->isPasswordField();
1512 }
1513
isCheckbox() const1514 bool HTMLInputElement::isCheckbox() const
1515 {
1516 return m_inputType->isCheckbox();
1517 }
1518
isText() const1519 bool HTMLInputElement::isText() const
1520 {
1521 return m_inputType->isTextType();
1522 }
1523
isEmailField() const1524 bool HTMLInputElement::isEmailField() const
1525 {
1526 return m_inputType->isEmailField();
1527 }
1528
isFileUpload() const1529 bool HTMLInputElement::isFileUpload() const
1530 {
1531 return m_inputType->isFileUpload();
1532 }
1533
isImageButton() const1534 bool HTMLInputElement::isImageButton() const
1535 {
1536 return m_inputType->isImageButton();
1537 }
1538
isNumberField() const1539 bool HTMLInputElement::isNumberField() const
1540 {
1541 return m_inputType->isNumberField();
1542 }
1543
isSubmitButton() const1544 bool HTMLInputElement::isSubmitButton() const
1545 {
1546 return m_inputType->isSubmitButton();
1547 }
1548
isTelephoneField() const1549 bool HTMLInputElement::isTelephoneField() const
1550 {
1551 return m_inputType->isTelephoneField();
1552 }
1553
isURLField() const1554 bool HTMLInputElement::isURLField() const
1555 {
1556 return m_inputType->isURLField();
1557 }
1558
isEnumeratable() const1559 bool HTMLInputElement::isEnumeratable() const
1560 {
1561 return m_inputType->isEnumeratable();
1562 }
1563
isChecked() const1564 bool HTMLInputElement::isChecked() const
1565 {
1566 return checked() && m_inputType->isCheckable();
1567 }
1568
hasSpinButton() const1569 bool HTMLInputElement::hasSpinButton() const
1570 {
1571 return m_inputType->hasSpinButton();
1572 }
1573
supportsPlaceholder() const1574 bool HTMLInputElement::supportsPlaceholder() const
1575 {
1576 return isTextType();
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