• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
4  *           (C) 2001 Dirk Mueller (mueller@kde.org)
5  * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
6  *           (C) 2006 Alexey Proskuryakov (ap@nypop.com)
7  * Copyright (C) 2007 Samuel Weinig (sam@webkit.org)
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Library General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Library General Public License for more details.
18  *
19  * You should have received a copy of the GNU Library General Public License
20  * along with this library; see the file COPYING.LIB.  If not, write to
21  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22  * Boston, MA 02110-1301, USA.
23  *
24  */
25 
26 #include "config.h"
27 #include "HTMLInputElement.h"
28 
29 #include "AXObjectCache.h"
30 #include "CSSPropertyNames.h"
31 #include "ChromeClient.h"
32 #include "DateComponents.h"
33 #include "Document.h"
34 #include "Editor.h"
35 #include "Event.h"
36 #include "EventHandler.h"
37 #include "EventNames.h"
38 #include "ExceptionCode.h"
39 #include "File.h"
40 #include "FileList.h"
41 #include "FocusController.h"
42 #include "FormDataList.h"
43 #include "Frame.h"
44 #include "HTMLDataListElement.h"
45 #include "HTMLFormElement.h"
46 #include "HTMLImageLoader.h"
47 #include "HTMLNames.h"
48 #include "HTMLOptionElement.h"
49 #include "ScriptEventListener.h"
50 #include "KeyboardEvent.h"
51 #include "LocalizedStrings.h"
52 #include "MappedAttribute.h"
53 #include "MouseEvent.h"
54 #include "Page.h"
55 #include "RegularExpression.h"
56 #include "RenderButton.h"
57 #include "RenderFileUploadControl.h"
58 #include "RenderImage.h"
59 #include "RenderSlider.h"
60 #include "RenderText.h"
61 #include "RenderTextControlSingleLine.h"
62 #include "RenderTheme.h"
63 #include "StringHash.h"
64 #include "TextEvent.h"
65 #ifdef ANDROID_ACCEPT_CHANGES_TO_FOCUSED_TEXTFIELDS
66 #include "WebViewCore.h"
67 #endif
68 #include <wtf/HashMap.h>
69 #include <wtf/MathExtras.h>
70 #include <wtf/StdLibExtras.h>
71 #include <wtf/dtoa.h>
72 
73 using namespace std;
74 
75 namespace WebCore {
76 
77 using namespace HTMLNames;
78 
79 const int maxSavedResults = 256;
80 
81 // Constant values for getAllowedValueStep().
82 static const double dateDefaultStep = 1.0;
83 static const double dateStepScaleFactor = 86400000.0;
84 static const double dateTimeDefaultStep = 60.0;
85 static const double dateTimeStepScaleFactor = 1000.0;
86 static const double monthDefaultStep = 1.0;
87 static const double monthStepScaleFactor = 1.0;
88 static const double numberDefaultStep = 1.0;
89 static const double numberStepScaleFactor = 1.0;
90 static const double timeDefaultStep = 60.0;
91 static const double timeStepScaleFactor = 1000.0;
92 static const double weekDefaultStep = 1.0;
93 static const double weekStepScaleFactor = 604800000.0;
94 
95 // Constant values for minimum().
96 static const double dateDefaultMinimum = -12219292800000.0; // This means 1582-10-15T00:00Z.
97 static const double dateTimeDefaultMinimum = -12219292800000.0; // ditto.
98 static const double monthDefaultMinimum = (1582.0 - 1970) * 12 + 10 - 1; // 1582-10
99 static const double numberDefaultMinimum = -DBL_MAX;
100 static const double rangeDefaultMinimum = 0.0;
101 static const double timeDefaultMinimum = 0.0; // 00:00:00.000
102 static const double weekDefaultMinimum = -12212380800000.0; // 1583-01-03, the first Monday of 1583.
103 
104 // Constant values for maximum().
105 static const double dateDefaultMaximum = DBL_MAX;
106 static const double dateTimeDefaultMaximum = DBL_MAX;
107 // DateComponents::m_year can't represent a year greater than INT_MAX.
108 static const double monthDefaultMaximum = (INT_MAX - 1970) * 12.0 + 12 - 1;
109 static const double numberDefaultMaximum = DBL_MAX;
110 static const double rangeDefaultMaximum = 100.0;
111 static const double timeDefaultMaximum = 86399999.0; // 23:59:59.999
112 static const double weekDefaultMaximum = DBL_MAX;
113 
114 static const double defaultStepBase = 0.0;
115 static const double weekDefaultStepBase = -259200000.0; // The first day of 1970-W01.
116 
117 static const double msecPerMinute = 60 * 1000;
118 static const double msecPerSecond = 1000;
119 
HTMLInputElement(const QualifiedName & tagName,Document * doc,HTMLFormElement * f)120 HTMLInputElement::HTMLInputElement(const QualifiedName& tagName, Document* doc, HTMLFormElement* f)
121     : HTMLTextFormControlElement(tagName, doc, f)
122     , m_xPos(0)
123     , m_yPos(0)
124     , m_maxResults(-1)
125     , m_type(TEXT)
126     , m_checked(false)
127     , m_defaultChecked(false)
128     , m_useDefaultChecked(true)
129     , m_indeterminate(false)
130     , m_haveType(false)
131     , m_activeSubmit(false)
132     , m_autocomplete(Uninitialized)
133     , m_autofilled(false)
134     , m_inited(false)
135 {
136     ASSERT(hasTagName(inputTag) || hasTagName(isindexTag));
137 }
138 
~HTMLInputElement()139 HTMLInputElement::~HTMLInputElement()
140 {
141     if (needsActivationCallback())
142         document()->unregisterForDocumentActivationCallbacks(this);
143 
144     document()->checkedRadioButtons().removeButton(this);
145 
146     // Need to remove this from the form while it is still an HTMLInputElement,
147     // so can't wait for the base class's destructor to do it.
148     removeFromForm();
149 }
150 
formControlName() const151 const AtomicString& HTMLInputElement::formControlName() const
152 {
153     return m_data.name();
154 }
155 
autoComplete() const156 bool HTMLInputElement::autoComplete() const
157 {
158     if (m_autocomplete != Uninitialized)
159         return m_autocomplete == On;
160 
161     // Assuming we're still in a Form, respect the Form's setting
162     if (HTMLFormElement* form = this->form())
163         return form->autoComplete();
164 
165     // The default is true
166     return true;
167 }
168 
valueMissing() const169 bool HTMLInputElement::valueMissing() const
170 {
171     if (!isRequiredFormControl() || readOnly() || disabled())
172         return false;
173 
174     switch (inputType()) {
175         case DATE:
176         case DATETIME:
177         case DATETIMELOCAL:
178         case EMAIL:
179         case FILE:
180         case MONTH:
181         case NUMBER:
182         case PASSWORD:
183         case SEARCH:
184         case TELEPHONE:
185         case TEXT:
186         case TIME:
187         case URL:
188         case WEEK:
189             return value().isEmpty();
190         case CHECKBOX:
191             return !checked();
192         case RADIO:
193             return !document()->checkedRadioButtons().checkedButtonForGroup(name());
194         case COLOR:
195             return false;
196         case BUTTON:
197         case HIDDEN:
198         case IMAGE:
199         case ISINDEX:
200         case RANGE:
201         case RESET:
202         case SUBMIT:
203             break;
204     }
205 
206     ASSERT_NOT_REACHED();
207     return false;
208 }
209 
patternMismatch() const210 bool HTMLInputElement::patternMismatch() const
211 {
212     switch (inputType()) {
213         case BUTTON:
214         case CHECKBOX:
215         case COLOR:
216         case DATE:
217         case DATETIME:
218         case DATETIMELOCAL:
219         case FILE:
220         case HIDDEN:
221         case IMAGE:
222         case ISINDEX:
223         case MONTH:
224         case NUMBER:
225         case RADIO:
226         case RANGE:
227         case RESET:
228         case SUBMIT:
229         case TIME:
230         case WEEK:
231             return false;
232         case EMAIL:
233         case PASSWORD:
234         case SEARCH:
235         case TELEPHONE:
236         case TEXT:
237         case URL:
238             const AtomicString& pattern = getAttribute(patternAttr);
239             String value = this->value();
240 
241             // Empty values can't be mismatched
242             if (pattern.isEmpty() || value.isEmpty())
243                 return false;
244 
245             RegularExpression patternRegExp(pattern, TextCaseSensitive);
246             int matchLength = 0;
247             int valueLength = value.length();
248             int matchOffset = patternRegExp.match(value, 0, &matchLength);
249 
250             return matchOffset != 0 || matchLength != valueLength;
251     }
252 
253     ASSERT_NOT_REACHED();
254     return false;
255 }
256 
tooLong() const257 bool HTMLInputElement::tooLong() const
258 {
259     switch (inputType()) {
260     case EMAIL:
261     case PASSWORD:
262     case SEARCH:
263     case TELEPHONE:
264     case TEXT:
265     case URL: {
266         int max = maxLength();
267         if (max < 0)
268             return false;
269         // Return false for the default value even if it is longer than maxLength.
270         bool userEdited = !m_data.value().isNull();
271         if (!userEdited)
272             return false;
273         return value().numGraphemeClusters() > static_cast<unsigned>(max);
274     }
275     case BUTTON:
276     case CHECKBOX:
277     case COLOR:
278     case DATE:
279     case DATETIME:
280     case DATETIMELOCAL:
281     case FILE:
282     case HIDDEN:
283     case IMAGE:
284     case ISINDEX:
285     case MONTH:
286     case NUMBER:
287     case RADIO:
288     case RANGE:
289     case RESET:
290     case SUBMIT:
291     case TIME:
292     case WEEK:
293         return false;
294     }
295     ASSERT_NOT_REACHED();
296     return false;
297 }
298 
rangeUnderflow() const299 bool HTMLInputElement::rangeUnderflow() const
300 {
301     const double nan = numeric_limits<double>::quiet_NaN();
302     switch (inputType()) {
303     case DATE:
304     case DATETIME:
305     case DATETIMELOCAL:
306     case MONTH:
307     case NUMBER:
308     case RANGE:
309     case TIME:
310     case WEEK: {
311         double doubleValue = parseToDouble(value(), nan);
312         return isfinite(doubleValue) && doubleValue < minimum();
313     }
314     case BUTTON:
315     case CHECKBOX:
316     case COLOR:
317     case EMAIL:
318     case FILE:
319     case HIDDEN:
320     case IMAGE:
321     case ISINDEX:
322     case PASSWORD:
323     case RADIO:
324     case RESET:
325     case SEARCH:
326     case SUBMIT:
327     case TELEPHONE:
328     case TEXT:
329     case URL:
330         break;
331     }
332     return false;
333 }
334 
rangeOverflow() const335 bool HTMLInputElement::rangeOverflow() const
336 {
337     const double nan = numeric_limits<double>::quiet_NaN();
338     switch (inputType()) {
339     case DATE:
340     case DATETIME:
341     case DATETIMELOCAL:
342     case MONTH:
343     case NUMBER:
344     case RANGE:
345     case TIME:
346     case WEEK: {
347         double doubleValue = parseToDouble(value(), nan);
348         return isfinite(doubleValue) && doubleValue >  maximum();
349     }
350     case BUTTON:
351     case CHECKBOX:
352     case COLOR:
353     case EMAIL:
354     case FILE:
355     case HIDDEN:
356     case IMAGE:
357     case ISINDEX:
358     case PASSWORD:
359     case RADIO:
360     case RESET:
361     case SEARCH:
362     case SUBMIT:
363     case TELEPHONE:
364     case TEXT:
365     case URL:
366         break;
367     }
368     return false;
369 }
370 
minimum() const371 double HTMLInputElement::minimum() const
372 {
373     switch (inputType()) {
374     case DATE:
375         return parseToDouble(getAttribute(minAttr), dateDefaultMinimum);
376     case DATETIME:
377     case DATETIMELOCAL:
378         return parseToDouble(getAttribute(minAttr), dateTimeDefaultMinimum);
379     case MONTH:
380         return parseToDouble(getAttribute(minAttr), monthDefaultMinimum);
381     case NUMBER:
382         return parseToDouble(getAttribute(minAttr), numberDefaultMinimum);
383     case RANGE:
384         return parseToDouble(getAttribute(minAttr), rangeDefaultMinimum);
385     case TIME:
386         return parseToDouble(getAttribute(minAttr), timeDefaultMinimum);
387     case WEEK:
388         return parseToDouble(getAttribute(minAttr), weekDefaultMinimum);
389     case BUTTON:
390     case CHECKBOX:
391     case COLOR:
392     case EMAIL:
393     case FILE:
394     case HIDDEN:
395     case IMAGE:
396     case ISINDEX:
397     case PASSWORD:
398     case RADIO:
399     case RESET:
400     case SEARCH:
401     case SUBMIT:
402     case TELEPHONE:
403     case TEXT:
404     case URL:
405         break;
406     }
407     ASSERT_NOT_REACHED();
408     return 0;
409 }
410 
maximum() const411 double HTMLInputElement::maximum() const
412 {
413     switch (inputType()) {
414     case DATE:
415         return parseToDouble(getAttribute(maxAttr), dateDefaultMaximum);
416     case DATETIME:
417     case DATETIMELOCAL:
418         return parseToDouble(getAttribute(maxAttr), dateTimeDefaultMaximum);
419     case MONTH:
420         return parseToDouble(getAttribute(maxAttr), monthDefaultMaximum);
421     case NUMBER:
422         return parseToDouble(getAttribute(maxAttr), numberDefaultMaximum);
423     case RANGE: {
424         double max = parseToDouble(getAttribute(maxAttr), rangeDefaultMaximum);
425         // A remedy for the inconsistent min/max values for RANGE.
426         // Sets the maximum to the default or the minimum value.
427         double min = minimum();
428         if (max < min)
429             max = std::max(min, rangeDefaultMaximum);
430         return max;
431     }
432     case TIME:
433         return parseToDouble(getAttribute(maxAttr), timeDefaultMaximum);
434     case WEEK:
435         return parseToDouble(getAttribute(maxAttr), weekDefaultMaximum);
436     case BUTTON:
437     case CHECKBOX:
438     case COLOR:
439     case EMAIL:
440     case FILE:
441     case HIDDEN:
442     case IMAGE:
443     case ISINDEX:
444     case PASSWORD:
445     case RADIO:
446     case RESET:
447     case SEARCH:
448     case SUBMIT:
449     case TELEPHONE:
450     case TEXT:
451     case URL:
452         break;
453     }
454     ASSERT_NOT_REACHED();
455     return 0;
456 }
457 
stepBase() const458 double HTMLInputElement::stepBase() const
459 {
460     switch (inputType()) {
461     case RANGE:
462         return minimum();
463     case DATE:
464     case DATETIME:
465     case DATETIMELOCAL:
466     case MONTH:
467     case NUMBER:
468     case TIME:
469         return parseToDouble(getAttribute(minAttr), defaultStepBase);
470     case WEEK:
471         return parseToDouble(getAttribute(minAttr), weekDefaultStepBase);
472     case BUTTON:
473     case CHECKBOX:
474     case COLOR:
475     case EMAIL:
476     case FILE:
477     case HIDDEN:
478     case IMAGE:
479     case ISINDEX:
480     case PASSWORD:
481     case RADIO:
482     case RESET:
483     case SEARCH:
484     case SUBMIT:
485     case TELEPHONE:
486     case TEXT:
487     case URL:
488         break;
489     }
490     ASSERT_NOT_REACHED();
491     return 0.0;
492 }
493 
stepMismatch() const494 bool HTMLInputElement::stepMismatch() const
495 {
496     double step;
497     if (!getAllowedValueStep(&step))
498         return false;
499     switch (inputType()) {
500     case RANGE:
501         // stepMismatch doesn't occur for RANGE. RenderSlider guarantees the
502         // value matches to step.
503         return false;
504     case NUMBER: {
505         double doubleValue;
506         if (!formStringToDouble(value(), &doubleValue))
507             return false;
508         doubleValue = fabs(doubleValue - stepBase());
509         if (isinf(doubleValue))
510             return false;
511         // double's fractional part size is DBL_MAN_DIG-bit.  If the current
512         // value is greater than step*2^DBL_MANT_DIG, the following fmod() makes
513         // no sense.
514         if (doubleValue / pow(2.0, DBL_MANT_DIG) > step)
515             return false;
516         double remainder = fmod(doubleValue, step);
517         // Accepts errors in lower 7-bit.
518         double acceptableError = step / pow(2.0, DBL_MANT_DIG - 7);
519         return acceptableError < remainder && remainder < (step - acceptableError);
520     }
521     case DATE:
522     case DATETIME:
523     case DATETIMELOCAL:
524     case MONTH:
525     case TIME:
526     case WEEK: {
527         const double nan = numeric_limits<double>::quiet_NaN();
528         double doubleValue = parseToDouble(value(), nan);
529         doubleValue = fabs(doubleValue - stepBase());
530         if (!isfinite(doubleValue))
531             return false;
532         ASSERT(round(doubleValue) == doubleValue);
533         ASSERT(round(step) == step);
534         return fmod(doubleValue, step);
535     }
536     case BUTTON:
537     case CHECKBOX:
538     case COLOR:
539     case EMAIL:
540     case FILE:
541     case HIDDEN:
542     case IMAGE:
543     case ISINDEX:
544     case PASSWORD:
545     case RADIO:
546     case RESET:
547     case SEARCH:
548     case SUBMIT:
549     case TELEPHONE:
550     case TEXT:
551     case URL:
552         break;
553     }
554     // Non-supported types should be rejected by getAllowedValueStep().
555     ASSERT_NOT_REACHED();
556     return false;
557 }
558 
getStepParameters(double * defaultStep,double * stepScaleFactor) const559 bool HTMLInputElement::getStepParameters(double* defaultStep, double* stepScaleFactor) const
560 {
561     ASSERT(defaultStep);
562     ASSERT(stepScaleFactor);
563     switch (inputType()) {
564     case NUMBER:
565     case RANGE:
566         *defaultStep = numberDefaultStep;
567         *stepScaleFactor = numberStepScaleFactor;
568         return true;
569     case DATE:
570         *defaultStep = dateDefaultStep;
571         *stepScaleFactor = dateStepScaleFactor;
572         return true;
573     case DATETIME:
574     case DATETIMELOCAL:
575         *defaultStep = dateTimeDefaultStep;
576         *stepScaleFactor = dateTimeStepScaleFactor;
577         return true;
578     case MONTH:
579         *defaultStep = monthDefaultStep;
580         *stepScaleFactor = monthStepScaleFactor;
581         return true;
582     case TIME:
583         *defaultStep = timeDefaultStep;
584         *stepScaleFactor = timeStepScaleFactor;
585         return true;
586     case WEEK:
587         *defaultStep = weekDefaultStep;
588         *stepScaleFactor = weekStepScaleFactor;
589         return true;
590     case BUTTON:
591     case CHECKBOX:
592     case COLOR:
593     case EMAIL:
594     case FILE:
595     case HIDDEN:
596     case IMAGE:
597     case ISINDEX:
598     case PASSWORD:
599     case RADIO:
600     case RESET:
601     case SEARCH:
602     case SUBMIT:
603     case TELEPHONE:
604     case TEXT:
605     case URL:
606         return false;
607     }
608     ASSERT_NOT_REACHED();
609     return false;
610 }
611 
getAllowedValueStep(double * step) const612 bool HTMLInputElement::getAllowedValueStep(double* step) const
613 {
614     ASSERT(step);
615     double defaultStep;
616     double stepScaleFactor;
617     if (!getStepParameters(&defaultStep, &stepScaleFactor))
618         return false;
619     const AtomicString& stepString = getAttribute(stepAttr);
620     if (stepString.isEmpty()) {
621         *step = defaultStep * stepScaleFactor;
622         return true;
623     }
624     if (equalIgnoringCase(stepString, "any"))
625         return false;
626     double parsed;
627     if (!formStringToDouble(stepString, &parsed) || parsed <= 0.0) {
628         *step = defaultStep * stepScaleFactor;
629         return true;
630     }
631     // For DATE, MONTH, WEEK, the parsed value should be an integer.
632     if (inputType() == DATE || inputType() == MONTH || inputType() == WEEK)
633         parsed = max(round(parsed), 1.0);
634     double result = parsed * stepScaleFactor;
635     // For DATETIME, DATETIMELOCAL, TIME, the result should be an integer.
636     if (inputType() == DATETIME || inputType() == DATETIMELOCAL || inputType() == TIME)
637         result = max(round(result), 1.0);
638     ASSERT(result > 0);
639     *step = result;
640     return true;
641 }
642 
applyStep(double count,ExceptionCode & ec)643 void HTMLInputElement::applyStep(double count, ExceptionCode& ec)
644 {
645     double step;
646     if (!getAllowedValueStep(&step)) {
647         ec = INVALID_STATE_ERR;
648         return;
649     }
650     const double nan = numeric_limits<double>::quiet_NaN();
651     double current = parseToDouble(value(), nan);
652     if (!isfinite(current)) {
653         ec = INVALID_STATE_ERR;
654         return;
655     }
656     double newValue = current + step * count;
657     if (isinf(newValue)) {
658         ec = INVALID_STATE_ERR;
659         return;
660     }
661     if (newValue < minimum()) {
662         ec = INVALID_STATE_ERR;
663         return;
664     }
665     double base = stepBase();
666     newValue = base + round((newValue - base) / step) * step;
667     if (newValue > maximum()) {
668         ec = INVALID_STATE_ERR;
669         return;
670     }
671     setValueAsNumber(newValue, ec);
672 }
673 
stepUp(int n,ExceptionCode & ec)674 void HTMLInputElement::stepUp(int n, ExceptionCode& ec)
675 {
676     applyStep(n, ec);
677 }
678 
stepDown(int n,ExceptionCode & ec)679 void HTMLInputElement::stepDown(int n, ExceptionCode& ec)
680 {
681     applyStep(-n, ec);
682 }
683 
checkedRadioButtons(const HTMLInputElement * element)684 static inline CheckedRadioButtons& checkedRadioButtons(const HTMLInputElement *element)
685 {
686     if (HTMLFormElement* form = element->form())
687         return form->checkedRadioButtons();
688 
689     return element->document()->checkedRadioButtons();
690 }
691 
isKeyboardFocusable(KeyboardEvent * event) const692 bool HTMLInputElement::isKeyboardFocusable(KeyboardEvent* event) const
693 {
694     // If text fields can be focused, then they should always be keyboard focusable
695     if (isTextField())
696         return HTMLFormControlElementWithState::isFocusable();
697 
698     // If the base class says we can't be focused, then we can stop now.
699     if (!HTMLFormControlElementWithState::isKeyboardFocusable(event))
700         return false;
701 
702     if (inputType() == RADIO) {
703 
704         // Never allow keyboard tabbing to leave you in the same radio group.  Always
705         // skip any other elements in the group.
706         Node* currentFocusedNode = document()->focusedNode();
707         if (currentFocusedNode && currentFocusedNode->hasTagName(inputTag)) {
708             HTMLInputElement* focusedInput = static_cast<HTMLInputElement*>(currentFocusedNode);
709             if (focusedInput->inputType() == RADIO && focusedInput->form() == form() &&
710                 focusedInput->name() == name())
711                 return false;
712         }
713 
714         // Allow keyboard focus if we're checked or if nothing in the group is checked.
715         return checked() || !checkedRadioButtons(this).checkedButtonForGroup(name());
716     }
717 
718     return true;
719 }
720 
isMouseFocusable() const721 bool HTMLInputElement::isMouseFocusable() const
722 {
723     if (isTextField())
724         return HTMLFormControlElementWithState::isFocusable();
725     return HTMLFormControlElementWithState::isMouseFocusable();
726 }
727 
updateFocusAppearance(bool restorePreviousSelection)728 void HTMLInputElement::updateFocusAppearance(bool restorePreviousSelection)
729 {
730     if (isTextField())
731         InputElement::updateFocusAppearance(m_data, this, this, restorePreviousSelection);
732     else
733         HTMLFormControlElementWithState::updateFocusAppearance(restorePreviousSelection);
734 }
735 
aboutToUnload()736 void HTMLInputElement::aboutToUnload()
737 {
738     InputElement::aboutToUnload(this, this);
739 }
740 
shouldUseInputMethod() const741 bool HTMLInputElement::shouldUseInputMethod() const
742 {
743     return m_type == TEXT || m_type == SEARCH || m_type == ISINDEX;
744 }
745 
handleFocusEvent()746 void HTMLInputElement::handleFocusEvent()
747 {
748     InputElement::dispatchFocusEvent(this, this);
749 
750     if (isTextField())
751         m_autofilled = false;
752 }
753 
handleBlurEvent()754 void HTMLInputElement::handleBlurEvent()
755 {
756     InputElement::dispatchBlurEvent(this, this);
757 }
758 
setType(const String & t)759 void HTMLInputElement::setType(const String& t)
760 {
761     if (t.isEmpty()) {
762         int exccode;
763         removeAttribute(typeAttr, exccode);
764     } else
765         setAttribute(typeAttr, t);
766 }
767 
768 typedef HashMap<String, HTMLInputElement::InputType, CaseFoldingHash> InputTypeMap;
createTypeMap()769 static const InputTypeMap* createTypeMap()
770 {
771     InputTypeMap* map = new InputTypeMap;
772     map->add("button", HTMLInputElement::BUTTON);
773     map->add("checkbox", HTMLInputElement::CHECKBOX);
774     map->add("color", HTMLInputElement::COLOR);
775     map->add("date", HTMLInputElement::DATE);
776     map->add("datetime", HTMLInputElement::DATETIME);
777     map->add("datetime-local", HTMLInputElement::DATETIMELOCAL);
778     map->add("email", HTMLInputElement::EMAIL);
779     map->add("file", HTMLInputElement::FILE);
780     map->add("hidden", HTMLInputElement::HIDDEN);
781     map->add("image", HTMLInputElement::IMAGE);
782     map->add("khtml_isindex", HTMLInputElement::ISINDEX);
783     map->add("month", HTMLInputElement::MONTH);
784     map->add("number", HTMLInputElement::NUMBER);
785     map->add("password", HTMLInputElement::PASSWORD);
786     map->add("radio", HTMLInputElement::RADIO);
787     map->add("range", HTMLInputElement::RANGE);
788     map->add("reset", HTMLInputElement::RESET);
789     map->add("search", HTMLInputElement::SEARCH);
790     map->add("submit", HTMLInputElement::SUBMIT);
791     map->add("tel", HTMLInputElement::TELEPHONE);
792     map->add("time", HTMLInputElement::TIME);
793     map->add("url", HTMLInputElement::URL);
794     map->add("week", HTMLInputElement::WEEK);
795     // No need to register "text" because it is the default type.
796     return map;
797 }
798 
setInputType(const String & t)799 void HTMLInputElement::setInputType(const String& t)
800 {
801     static const InputTypeMap* typeMap = createTypeMap();
802     InputType newType = t.isNull() ? TEXT : typeMap->get(t);
803 #ifdef ANDROID_ACCEPT_CHANGES_TO_FOCUSED_TEXTFIELDS
804     if (newType == PASSWORD && document()->focusedNode() == this)
805         android::WebViewCore::getWebViewCore(document()->view())->updateTextfield(this, true, String());
806 #endif
807 
808     // IMPORTANT: Don't allow the type to be changed to FILE after the first
809     // type change, otherwise a JavaScript programmer would be able to set a text
810     // field's value to something like /etc/passwd and then change it to a file field.
811     if (inputType() != newType) {
812         bool oldWillValidate = willValidate();
813         if (newType == FILE && m_haveType)
814             // Set the attribute back to the old value.
815             // Useful in case we were called from inside parseMappedAttribute.
816             setAttribute(typeAttr, type());
817         else {
818             checkedRadioButtons(this).removeButton(this);
819 
820             if (newType == FILE && !m_fileList)
821                 m_fileList = FileList::create();
822 
823             bool wasAttached = attached();
824             if (wasAttached)
825                 detach();
826 
827             bool didStoreValue = storesValueSeparateFromAttribute();
828             bool wasPasswordField = inputType() == PASSWORD;
829             bool didRespectHeightAndWidth = respectHeightAndWidthAttrs();
830             m_type = newType;
831             bool willStoreValue = storesValueSeparateFromAttribute();
832             bool isPasswordField = inputType() == PASSWORD;
833             bool willRespectHeightAndWidth = respectHeightAndWidthAttrs();
834 
835             if (didStoreValue && !willStoreValue && !m_data.value().isNull()) {
836                 setAttribute(valueAttr, m_data.value());
837                 m_data.setValue(String());
838             }
839             if (!didStoreValue && willStoreValue)
840                 m_data.setValue(sanitizeValue(getAttribute(valueAttr)));
841             else
842                 InputElement::updateValueIfNeeded(m_data, this);
843 
844             if (wasPasswordField && !isPasswordField)
845                 unregisterForActivationCallbackIfNeeded();
846             else if (!wasPasswordField && isPasswordField)
847                 registerForActivationCallbackIfNeeded();
848 
849             if (didRespectHeightAndWidth != willRespectHeightAndWidth) {
850                 NamedMappedAttrMap* map = mappedAttributes();
851                 ASSERT(map);
852                 if (Attribute* height = map->getAttributeItem(heightAttr))
853                     attributeChanged(height, false);
854                 if (Attribute* width = map->getAttributeItem(widthAttr))
855                     attributeChanged(width, false);
856                 if (Attribute* align = map->getAttributeItem(alignAttr))
857                     attributeChanged(align, false);
858             }
859 
860             if (wasAttached) {
861                 attach();
862                 if (document()->focusedNode() == this)
863                     updateFocusAppearance(true);
864             }
865 
866             checkedRadioButtons(this).addButton(this);
867         }
868 
869         setNeedsValidityCheck();
870         if (oldWillValidate != willValidate())
871             setNeedsWillValidateCheck();
872         InputElement::notifyFormStateChanged(this);
873     }
874     m_haveType = true;
875 
876     if (inputType() != IMAGE && m_imageLoader)
877         m_imageLoader.clear();
878 }
879 
createFormControlTypes()880 static const AtomicString* createFormControlTypes()
881 {
882     AtomicString* types = new AtomicString[HTMLInputElement::numberOfTypes];
883     // The values must be lowercased because they will be the return values of
884     //  input.type and it must be lowercase according to DOM Level 2.
885     types[HTMLInputElement::BUTTON] = "button";
886     types[HTMLInputElement::CHECKBOX] = "checkbox";
887     types[HTMLInputElement::COLOR] = "color";
888     types[HTMLInputElement::DATE] = "date";
889     types[HTMLInputElement::DATETIME] = "datetime";
890     types[HTMLInputElement::DATETIMELOCAL] = "datetime-local";
891     types[HTMLInputElement::EMAIL] = "email";
892     types[HTMLInputElement::FILE] = "file";
893     types[HTMLInputElement::HIDDEN] = "hidden";
894     types[HTMLInputElement::IMAGE] = "image";
895     types[HTMLInputElement::ISINDEX] = emptyAtom;
896     types[HTMLInputElement::MONTH] = "month";
897     types[HTMLInputElement::NUMBER] = "number";
898     types[HTMLInputElement::PASSWORD] = "password";
899     types[HTMLInputElement::RADIO] = "radio";
900     types[HTMLInputElement::RANGE] = "range";
901     types[HTMLInputElement::RESET] = "reset";
902     types[HTMLInputElement::SEARCH] = "search";
903     types[HTMLInputElement::SUBMIT] = "submit";
904     types[HTMLInputElement::TELEPHONE] = "tel";
905     types[HTMLInputElement::TEXT] = "text";
906     types[HTMLInputElement::TIME] = "time";
907     types[HTMLInputElement::URL] = "url";
908     types[HTMLInputElement::WEEK] = "week";
909     return types;
910 }
911 
formControlType() const912 const AtomicString& HTMLInputElement::formControlType() const
913 {
914     static const AtomicString* formControlTypes = createFormControlTypes();
915     return formControlTypes[inputType()];
916 }
917 
saveFormControlState(String & result) const918 bool HTMLInputElement::saveFormControlState(String& result) const
919 {
920     if (!autoComplete())
921         return false;
922 
923     switch (inputType()) {
924         case BUTTON:
925         case COLOR:
926         case DATE:
927         case DATETIME:
928         case DATETIMELOCAL:
929         case EMAIL:
930         case FILE:
931         case HIDDEN:
932         case IMAGE:
933         case ISINDEX:
934         case MONTH:
935         case NUMBER:
936         case RANGE:
937         case RESET:
938         case SEARCH:
939         case SUBMIT:
940         case TELEPHONE:
941         case TEXT:
942         case TIME:
943         case URL:
944         case WEEK:
945             result = value();
946             return true;
947         case CHECKBOX:
948         case RADIO:
949             result = checked() ? "on" : "off";
950             return true;
951         case PASSWORD:
952             return false;
953     }
954     ASSERT_NOT_REACHED();
955     return false;
956 }
957 
restoreFormControlState(const String & state)958 void HTMLInputElement::restoreFormControlState(const String& state)
959 {
960     ASSERT(inputType() != PASSWORD); // should never save/restore password fields
961     switch (inputType()) {
962         case BUTTON:
963         case COLOR:
964         case DATE:
965         case DATETIME:
966         case DATETIMELOCAL:
967         case EMAIL:
968         case FILE:
969         case HIDDEN:
970         case IMAGE:
971         case ISINDEX:
972         case MONTH:
973         case NUMBER:
974         case RANGE:
975         case RESET:
976         case SEARCH:
977         case SUBMIT:
978         case TELEPHONE:
979         case TEXT:
980         case TIME:
981         case URL:
982         case WEEK:
983             setValue(state);
984             break;
985         case CHECKBOX:
986         case RADIO:
987             setChecked(state == "on");
988             break;
989         case PASSWORD:
990             break;
991     }
992 }
993 
canStartSelection() const994 bool HTMLInputElement::canStartSelection() const
995 {
996     if (!isTextField())
997         return false;
998     return HTMLFormControlElementWithState::canStartSelection();
999 }
1000 
canHaveSelection() const1001 bool HTMLInputElement::canHaveSelection() const
1002 {
1003     return isTextField();
1004 }
1005 
accessKeyAction(bool sendToAnyElement)1006 void HTMLInputElement::accessKeyAction(bool sendToAnyElement)
1007 {
1008     switch (inputType()) {
1009         case BUTTON:
1010         case CHECKBOX:
1011         case FILE:
1012         case IMAGE:
1013         case RADIO:
1014         case RANGE:
1015         case RESET:
1016         case SUBMIT:
1017             focus(false);
1018             // send the mouse button events iff the caller specified sendToAnyElement
1019             dispatchSimulatedClick(0, sendToAnyElement);
1020             break;
1021         case HIDDEN:
1022             // a no-op for this type
1023             break;
1024         case COLOR:
1025         case DATE:
1026         case DATETIME:
1027         case DATETIMELOCAL:
1028         case EMAIL:
1029         case ISINDEX:
1030         case MONTH:
1031         case NUMBER:
1032         case PASSWORD:
1033         case SEARCH:
1034         case TELEPHONE:
1035         case TEXT:
1036         case TIME:
1037         case URL:
1038         case WEEK:
1039             // should never restore previous selection here
1040             focus(false);
1041             break;
1042     }
1043 }
1044 
mapToEntry(const QualifiedName & attrName,MappedAttributeEntry & result) const1045 bool HTMLInputElement::mapToEntry(const QualifiedName& attrName, MappedAttributeEntry& result) const
1046 {
1047     if (((attrName == heightAttr || attrName == widthAttr) && respectHeightAndWidthAttrs()) ||
1048         attrName == vspaceAttr ||
1049         attrName == hspaceAttr) {
1050         result = eUniversal;
1051         return false;
1052     }
1053 
1054     if (attrName == alignAttr) {
1055         if (inputType() == IMAGE) {
1056             // Share with <img> since the alignment behavior is the same.
1057             result = eReplaced;
1058             return false;
1059         }
1060     }
1061 
1062     return HTMLElement::mapToEntry(attrName, result);
1063 }
1064 
parseMappedAttribute(MappedAttribute * attr)1065 void HTMLInputElement::parseMappedAttribute(MappedAttribute *attr)
1066 {
1067     if (attr->name() == nameAttr) {
1068         checkedRadioButtons(this).removeButton(this);
1069         m_data.setName(attr->value());
1070         checkedRadioButtons(this).addButton(this);
1071         HTMLFormControlElementWithState::parseMappedAttribute(attr);
1072     } else if (attr->name() == autocompleteAttr) {
1073         if (equalIgnoringCase(attr->value(), "off")) {
1074             m_autocomplete = Off;
1075             registerForActivationCallbackIfNeeded();
1076         } else {
1077             bool needsToUnregister = m_autocomplete == Off;
1078 
1079             if (attr->isEmpty())
1080                 m_autocomplete = Uninitialized;
1081             else
1082                 m_autocomplete = On;
1083 
1084             if (needsToUnregister)
1085                 unregisterForActivationCallbackIfNeeded();
1086         }
1087     } else if (attr->name() == typeAttr) {
1088         setInputType(attr->value());
1089     } else if (attr->name() == valueAttr) {
1090         // We only need to setChanged if the form is looking at the default value right now.
1091         if (m_data.value().isNull())
1092             setNeedsStyleRecalc();
1093         setFormControlValueMatchesRenderer(false);
1094         setNeedsValidityCheck();
1095     } else if (attr->name() == checkedAttr) {
1096         m_defaultChecked = !attr->isNull();
1097         if (m_useDefaultChecked) {
1098             setChecked(m_defaultChecked);
1099             m_useDefaultChecked = true;
1100         }
1101         setNeedsValidityCheck();
1102     } else if (attr->name() == maxlengthAttr) {
1103         InputElement::parseMaxLengthAttribute(m_data, this, this, attr);
1104         setNeedsValidityCheck();
1105     } else if (attr->name() == sizeAttr)
1106         InputElement::parseSizeAttribute(m_data, this, attr);
1107     else if (attr->name() == altAttr) {
1108         if (renderer() && inputType() == IMAGE)
1109             toRenderImage(renderer())->updateAltText();
1110     } else if (attr->name() == srcAttr) {
1111         if (renderer() && inputType() == IMAGE) {
1112             if (!m_imageLoader)
1113                 m_imageLoader.set(new HTMLImageLoader(this));
1114             m_imageLoader->updateFromElementIgnoringPreviousError();
1115         }
1116     } else if (attr->name() == usemapAttr ||
1117                attr->name() == accesskeyAttr) {
1118         // FIXME: ignore for the moment
1119     } else if (attr->name() == vspaceAttr) {
1120         addCSSLength(attr, CSSPropertyMarginTop, attr->value());
1121         addCSSLength(attr, CSSPropertyMarginBottom, attr->value());
1122     } else if (attr->name() == hspaceAttr) {
1123         addCSSLength(attr, CSSPropertyMarginLeft, attr->value());
1124         addCSSLength(attr, CSSPropertyMarginRight, attr->value());
1125     } else if (attr->name() == alignAttr) {
1126         if (inputType() == IMAGE)
1127             addHTMLAlignment(attr);
1128     } else if (attr->name() == widthAttr) {
1129         if (respectHeightAndWidthAttrs())
1130             addCSSLength(attr, CSSPropertyWidth, attr->value());
1131     } else if (attr->name() == heightAttr) {
1132         if (respectHeightAndWidthAttrs())
1133             addCSSLength(attr, CSSPropertyHeight, attr->value());
1134     }
1135     // Search field and slider attributes all just cause updateFromElement to be called through style
1136     // recalcing.
1137     else if (attr->name() == onsearchAttr) {
1138         setAttributeEventListener(eventNames().searchEvent, createAttributeEventListener(this, attr));
1139     } else if (attr->name() == resultsAttr) {
1140         int oldResults = m_maxResults;
1141         m_maxResults = !attr->isNull() ? std::min(attr->value().toInt(), maxSavedResults) : -1;
1142         // FIXME: Detaching just for maxResults change is not ideal.  We should figure out the right
1143         // time to relayout for this change.
1144         if (m_maxResults != oldResults && (m_maxResults <= 0 || oldResults <= 0) && attached()) {
1145             detach();
1146             attach();
1147         }
1148         setNeedsStyleRecalc();
1149     } else if (attr->name() == autosaveAttr
1150                || attr->name() == incrementalAttr)
1151         setNeedsStyleRecalc();
1152     else if (attr->name() == minAttr
1153              || attr->name() == maxAttr
1154              || attr->name() == multipleAttr
1155              || attr->name() == patternAttr
1156              || attr->name() == precisionAttr
1157              || attr->name() == stepAttr)
1158         setNeedsValidityCheck();
1159 #if ENABLE(DATALIST)
1160     else if (attr->name() == listAttr)
1161         m_hasNonEmptyList = !attr->isEmpty();
1162         // FIXME: we need to tell this change to a renderer if the attribute affects the appearance.
1163 #endif
1164     else
1165         HTMLTextFormControlElement::parseMappedAttribute(attr);
1166 }
1167 
rendererIsNeeded(RenderStyle * style)1168 bool HTMLInputElement::rendererIsNeeded(RenderStyle *style)
1169 {
1170     if (inputType() == HIDDEN)
1171         return false;
1172     return HTMLFormControlElementWithState::rendererIsNeeded(style);
1173 }
1174 
createRenderer(RenderArena * arena,RenderStyle * style)1175 RenderObject *HTMLInputElement::createRenderer(RenderArena *arena, RenderStyle *style)
1176 {
1177     switch (inputType()) {
1178         case BUTTON:
1179         case RESET:
1180         case SUBMIT:
1181             return new (arena) RenderButton(this);
1182         case CHECKBOX:
1183         case RADIO:
1184             return RenderObject::createObject(this, style);
1185         case FILE:
1186             return new (arena) RenderFileUploadControl(this);
1187         case HIDDEN:
1188             break;
1189         case IMAGE:
1190             return new (arena) RenderImage(this);
1191         case RANGE:
1192             return new (arena) RenderSlider(this);
1193         case COLOR:
1194         case DATE:
1195         case DATETIME:
1196         case DATETIMELOCAL:
1197         case EMAIL:
1198         case ISINDEX:
1199         case MONTH:
1200         case NUMBER:
1201         case PASSWORD:
1202         case SEARCH:
1203         case TELEPHONE:
1204         case TEXT:
1205         case TIME:
1206         case URL:
1207         case WEEK:
1208             return new (arena) RenderTextControlSingleLine(this, placeholderShouldBeVisible());
1209     }
1210     ASSERT(false);
1211     return 0;
1212 }
1213 
attach()1214 void HTMLInputElement::attach()
1215 {
1216     if (!m_inited) {
1217         if (!m_haveType)
1218             setInputType(getAttribute(typeAttr));
1219         m_inited = true;
1220     }
1221 
1222     HTMLFormControlElementWithState::attach();
1223 
1224     if (inputType() == IMAGE) {
1225         if (!m_imageLoader)
1226             m_imageLoader.set(new HTMLImageLoader(this));
1227         m_imageLoader->updateFromElement();
1228         if (renderer() && m_imageLoader->haveFiredBeforeLoadEvent()) {
1229             RenderImage* imageObj = toRenderImage(renderer());
1230             imageObj->setCachedImage(m_imageLoader->image());
1231 
1232             // If we have no image at all because we have no src attribute, set
1233             // image height and width for the alt text instead.
1234             if (!m_imageLoader->image() && !imageObj->cachedImage())
1235                 imageObj->setImageSizeForAltText();
1236         }
1237     }
1238 
1239     if (document()->focusedNode() == this)
1240         document()->updateFocusAppearanceSoon(true /* restore selection */);
1241 }
1242 
detach()1243 void HTMLInputElement::detach()
1244 {
1245     HTMLFormControlElementWithState::detach();
1246     setFormControlValueMatchesRenderer(false);
1247 }
1248 
altText() const1249 String HTMLInputElement::altText() const
1250 {
1251     // http://www.w3.org/TR/1998/REC-html40-19980424/appendix/notes.html#altgen
1252     // also heavily discussed by Hixie on bugzilla
1253     // note this is intentionally different to HTMLImageElement::altText()
1254     String alt = getAttribute(altAttr);
1255     // fall back to title attribute
1256     if (alt.isNull())
1257         alt = getAttribute(titleAttr);
1258     if (alt.isNull())
1259         alt = getAttribute(valueAttr);
1260     if (alt.isEmpty())
1261         alt = inputElementAltText();
1262     return alt;
1263 }
1264 
isSuccessfulSubmitButton() const1265 bool HTMLInputElement::isSuccessfulSubmitButton() const
1266 {
1267     // HTML spec says that buttons must have names to be considered successful.
1268     // However, other browsers do not impose this constraint. So we do likewise.
1269     return !disabled() && (inputType() == IMAGE || inputType() == SUBMIT);
1270 }
1271 
isActivatedSubmit() const1272 bool HTMLInputElement::isActivatedSubmit() const
1273 {
1274     return m_activeSubmit;
1275 }
1276 
setActivatedSubmit(bool flag)1277 void HTMLInputElement::setActivatedSubmit(bool flag)
1278 {
1279     m_activeSubmit = flag;
1280 }
1281 
appendFormData(FormDataList & encoding,bool multipart)1282 bool HTMLInputElement::appendFormData(FormDataList& encoding, bool multipart)
1283 {
1284     // image generates its own names, but for other types there is no form data unless there's a name
1285     if (name().isEmpty() && inputType() != IMAGE)
1286         return false;
1287 
1288     switch (inputType()) {
1289         case COLOR:
1290         case DATE:
1291         case DATETIME:
1292         case DATETIMELOCAL:
1293         case EMAIL:
1294         case HIDDEN:
1295         case ISINDEX:
1296         case MONTH:
1297         case NUMBER:
1298         case PASSWORD:
1299         case RANGE:
1300         case SEARCH:
1301         case TELEPHONE:
1302         case TEXT:
1303         case TIME:
1304         case URL:
1305         case WEEK:
1306             // always successful
1307             encoding.appendData(name(), value());
1308             return true;
1309 
1310         case CHECKBOX:
1311         case RADIO:
1312             if (checked()) {
1313                 encoding.appendData(name(), value());
1314                 return true;
1315             }
1316             break;
1317 
1318         case BUTTON:
1319         case RESET:
1320             // these types of buttons are never successful
1321             return false;
1322 
1323         case IMAGE:
1324             if (m_activeSubmit) {
1325                 encoding.appendData(name().isEmpty() ? "x" : (name() + ".x"), m_xPos);
1326                 encoding.appendData(name().isEmpty() ? "y" : (name() + ".y"), m_yPos);
1327                 if (!name().isEmpty() && !value().isEmpty())
1328                     encoding.appendData(name(), value());
1329                 return true;
1330             }
1331             break;
1332 
1333         case SUBMIT:
1334             if (m_activeSubmit) {
1335                 String enc_str = valueWithDefault();
1336                 encoding.appendData(name(), enc_str);
1337                 return true;
1338             }
1339             break;
1340 
1341         case FILE: {
1342             unsigned numFiles = m_fileList->length();
1343             if (!multipart) {
1344                 // Send only the basenames.
1345                 // 4.10.16.4 and 4.10.16.6 sections in HTML5.
1346 
1347                 // Unlike the multipart case, we have no special
1348                 // handling for the empty fileList because Netscape
1349                 // doesn't support for non-multipart submission of
1350                 // file inputs, and Firefox doesn't add "name=" query
1351                 // parameter.
1352 
1353                 for (unsigned i = 0; i < numFiles; ++i) {
1354                     encoding.appendData(name(), m_fileList->item(i)->fileName());
1355                 }
1356                 return true;
1357             }
1358 
1359             // If no filename at all is entered, return successful but empty.
1360             // Null would be more logical, but Netscape posts an empty file. Argh.
1361             if (!numFiles) {
1362                 encoding.appendFile(name(), File::create(""));
1363                 return true;
1364             }
1365 
1366             for (unsigned i = 0; i < numFiles; ++i)
1367                 encoding.appendFile(name(), m_fileList->item(i));
1368             return true;
1369         }
1370     }
1371     return false;
1372 }
1373 
reset()1374 void HTMLInputElement::reset()
1375 {
1376     if (storesValueSeparateFromAttribute())
1377         setValue(String());
1378 
1379     setChecked(m_defaultChecked);
1380     m_useDefaultChecked = true;
1381 }
1382 
isTextField() const1383 bool HTMLInputElement::isTextField() const
1384 {
1385     switch (inputType()) {
1386     case COLOR:
1387     case DATE:
1388     case DATETIME:
1389     case DATETIMELOCAL:
1390     case EMAIL:
1391     case ISINDEX:
1392     case MONTH:
1393     case NUMBER:
1394     case PASSWORD:
1395     case SEARCH:
1396     case TELEPHONE:
1397     case TEXT:
1398     case TIME:
1399     case URL:
1400     case WEEK:
1401         return true;
1402     case BUTTON:
1403     case CHECKBOX:
1404     case FILE:
1405     case HIDDEN:
1406     case IMAGE:
1407     case RADIO:
1408     case RANGE:
1409     case RESET:
1410     case SUBMIT:
1411         return false;
1412     }
1413     ASSERT_NOT_REACHED();
1414     return false;
1415 }
1416 
setChecked(bool nowChecked,bool sendChangeEvent)1417 void HTMLInputElement::setChecked(bool nowChecked, bool sendChangeEvent)
1418 {
1419     if (checked() == nowChecked)
1420         return;
1421 
1422     checkedRadioButtons(this).removeButton(this);
1423 
1424     m_useDefaultChecked = false;
1425     m_checked = nowChecked;
1426     setNeedsStyleRecalc();
1427 
1428     checkedRadioButtons(this).addButton(this);
1429 
1430     if (renderer() && renderer()->style()->hasAppearance())
1431         renderer()->theme()->stateChanged(renderer(), CheckedState);
1432 
1433     // Ideally we'd do this from the render tree (matching
1434     // RenderTextView), but it's not possible to do it at the moment
1435     // because of the way the code is structured.
1436     if (renderer() && AXObjectCache::accessibilityEnabled())
1437         renderer()->document()->axObjectCache()->postNotification(renderer(), AXObjectCache::AXCheckedStateChanged, true);
1438 
1439     // Only send a change event for items in the document (avoid firing during
1440     // parsing) and don't send a change event for a radio button that's getting
1441     // unchecked to match other browsers. DOM is not a useful standard for this
1442     // because it says only to fire change events at "lose focus" time, which is
1443     // definitely wrong in practice for these types of elements.
1444     if (sendChangeEvent && inDocument() && (inputType() != RADIO || nowChecked))
1445         dispatchFormControlChangeEvent();
1446 }
1447 
setIndeterminate(bool _indeterminate)1448 void HTMLInputElement::setIndeterminate(bool _indeterminate)
1449 {
1450     // Only checkboxes honor indeterminate.
1451     if (inputType() != CHECKBOX || indeterminate() == _indeterminate)
1452         return;
1453 
1454     m_indeterminate = _indeterminate;
1455 
1456     setNeedsStyleRecalc();
1457 
1458     if (renderer() && renderer()->style()->hasAppearance())
1459         renderer()->theme()->stateChanged(renderer(), CheckedState);
1460 }
1461 
size() const1462 int HTMLInputElement::size() const
1463 {
1464     return m_data.size();
1465 }
1466 
copyNonAttributeProperties(const Element * source)1467 void HTMLInputElement::copyNonAttributeProperties(const Element* source)
1468 {
1469     const HTMLInputElement* sourceElement = static_cast<const HTMLInputElement*>(source);
1470 
1471     m_data.setValue(sourceElement->m_data.value());
1472     setChecked(sourceElement->m_checked);
1473     m_defaultChecked = sourceElement->m_defaultChecked;
1474     m_useDefaultChecked = sourceElement->m_useDefaultChecked;
1475     m_indeterminate = sourceElement->m_indeterminate;
1476 
1477     HTMLFormControlElementWithState::copyNonAttributeProperties(source);
1478 }
1479 
value() const1480 String HTMLInputElement::value() const
1481 {
1482     // The HTML5 spec (as of the 10/24/08 working draft) says that the value attribute isn't applicable to the file upload control
1483     // but we don't want to break existing websites, who may be relying on being able to get the file name as a value.
1484     if (inputType() == FILE) {
1485         if (!m_fileList->isEmpty())
1486             return m_fileList->item(0)->fileName();
1487         return String();
1488     }
1489 
1490     String value = m_data.value();
1491     if (value.isNull()) {
1492         value = sanitizeValue(getAttribute(valueAttr));
1493 
1494         // If no attribute exists, then just use "on" or "" based off the checked() state of the control.
1495         if (value.isNull() && (inputType() == CHECKBOX || inputType() == RADIO))
1496             return checked() ? "on" : "";
1497     }
1498 
1499     return value;
1500 }
1501 
valueWithDefault() const1502 String HTMLInputElement::valueWithDefault() const
1503 {
1504     String v = value();
1505     if (v.isNull()) {
1506         switch (inputType()) {
1507             case BUTTON:
1508             case CHECKBOX:
1509             case COLOR:
1510             case DATE:
1511             case DATETIME:
1512             case DATETIMELOCAL:
1513             case EMAIL:
1514             case FILE:
1515             case HIDDEN:
1516             case IMAGE:
1517             case ISINDEX:
1518             case MONTH:
1519             case NUMBER:
1520             case PASSWORD:
1521             case RADIO:
1522             case RANGE:
1523             case SEARCH:
1524             case TELEPHONE:
1525             case TEXT:
1526             case TIME:
1527             case URL:
1528             case WEEK:
1529                 break;
1530             case RESET:
1531                 v = resetButtonDefaultLabel();
1532                 break;
1533             case SUBMIT:
1534                 v = submitButtonDefaultLabel();
1535                 break;
1536         }
1537     }
1538     return v;
1539 }
1540 
setValueForUser(const String & value)1541 void HTMLInputElement::setValueForUser(const String& value)
1542 {
1543     // Call setValue and make it send a change event.
1544     setValue(value, true);
1545 }
1546 
suggestedValue() const1547 const String& HTMLInputElement::suggestedValue() const
1548 {
1549     return m_data.suggestedValue();
1550 }
1551 
setSuggestedValue(const String & value)1552 void HTMLInputElement::setSuggestedValue(const String& value)
1553 {
1554     if (inputType() != TEXT)
1555         return;
1556     setFormControlValueMatchesRenderer(false);
1557     m_data.setSuggestedValue(sanitizeValue(value));
1558     updatePlaceholderVisibility(false);
1559     if (renderer())
1560         renderer()->updateFromElement();
1561     setNeedsStyleRecalc();
1562 }
1563 
setValue(const String & value,bool sendChangeEvent)1564 void HTMLInputElement::setValue(const String& value, bool sendChangeEvent)
1565 {
1566     // For security reasons, we don't allow setting the filename, but we do allow clearing it.
1567     // The HTML5 spec (as of the 10/24/08 working draft) says that the value attribute isn't applicable to the file upload control
1568     // but we don't want to break existing websites, who may be relying on this method to clear things.
1569     if (inputType() == FILE && !value.isEmpty())
1570         return;
1571 
1572     setFormControlValueMatchesRenderer(false);
1573     if (storesValueSeparateFromAttribute()) {
1574         if (inputType() == FILE)
1575             m_fileList->clear();
1576         else {
1577             m_data.setValue(sanitizeValue(value));
1578             if (isTextField()) {
1579                 updatePlaceholderVisibility(false);
1580                 if (inDocument())
1581                     document()->updateStyleIfNeeded();
1582             }
1583         }
1584         if (renderer())
1585             renderer()->updateFromElement();
1586         setNeedsStyleRecalc();
1587     } else
1588         setAttribute(valueAttr, sanitizeValue(value));
1589 
1590     if (isTextField()) {
1591         unsigned max = m_data.value().length();
1592 #ifdef ANDROID_ACCEPT_CHANGES_TO_FOCUSED_TEXTFIELDS
1593         // Make sure our UI side textfield changes to match the RenderTextControl
1594         android::WebViewCore::getWebViewCore(document()->view())->updateTextfield(this, false, value);
1595 #endif
1596         if (document()->focusedNode() == this)
1597             InputElement::updateSelectionRange(this, this, max, max);
1598         else
1599             cacheSelection(max, max);
1600         m_data.setSuggestedValue(String());
1601     }
1602 
1603     // Don't dispatch the change event when focused, it will be dispatched
1604     // when the control loses focus.
1605     if (sendChangeEvent && document()->focusedNode() != this)
1606         dispatchFormControlChangeEvent();
1607 
1608     InputElement::notifyFormStateChanged(this);
1609     setNeedsValidityCheck();
1610 }
1611 
parseToDouble(const String & src,double defaultValue) const1612 double HTMLInputElement::parseToDouble(const String& src, double defaultValue) const
1613 {
1614     switch (inputType()) {
1615     case DATE:
1616     case DATETIME:
1617     case DATETIMELOCAL:
1618     case TIME:
1619     case WEEK: {
1620         DateComponents date;
1621         if (!formStringToDateComponents(inputType(), src, &date))
1622             return defaultValue;
1623         double msec = date.millisecondsSinceEpoch();
1624         ASSERT(isfinite(msec));
1625         return msec;
1626     }
1627     case MONTH: {
1628         DateComponents date;
1629         if (!formStringToDateComponents(inputType(), src, &date))
1630             return defaultValue;
1631         double months = date.monthsSinceEpoch();
1632         ASSERT(isfinite(months));
1633         return months;
1634     }
1635     case NUMBER:
1636     case RANGE: {
1637         double numberValue;
1638         if (!formStringToDouble(src, &numberValue))
1639             return defaultValue;
1640         ASSERT(isfinite(numberValue));
1641         return numberValue;
1642     }
1643 
1644     case BUTTON:
1645     case CHECKBOX:
1646     case COLOR:
1647     case EMAIL:
1648     case FILE:
1649     case HIDDEN:
1650     case IMAGE:
1651     case ISINDEX:
1652     case PASSWORD:
1653     case RADIO:
1654     case RESET:
1655     case SEARCH:
1656     case SUBMIT:
1657     case TELEPHONE:
1658     case TEXT:
1659     case URL:
1660         return defaultValue;
1661     }
1662     ASSERT_NOT_REACHED();
1663     return defaultValue;
1664 }
1665 
valueAsDate() const1666 double HTMLInputElement::valueAsDate() const
1667 {
1668     switch (inputType()) {
1669     case DATE:
1670     case DATETIME:
1671     case TIME:
1672     case WEEK:
1673         return parseToDouble(value(), DateComponents::invalidMilliseconds());
1674     case MONTH: {
1675         DateComponents date;
1676         if (!formStringToDateComponents(inputType(), value(), &date))
1677             return DateComponents::invalidMilliseconds();
1678         double msec = date.millisecondsSinceEpoch();
1679         ASSERT(isfinite(msec));
1680         return msec;
1681     }
1682 
1683     case BUTTON:
1684     case CHECKBOX:
1685     case COLOR:
1686     case DATETIMELOCAL: // valueAsDate doesn't work for the DATETIMELOCAL type according to the standard.
1687     case EMAIL:
1688     case FILE:
1689     case HIDDEN:
1690     case IMAGE:
1691     case ISINDEX:
1692     case NUMBER:
1693     case PASSWORD:
1694     case RADIO:
1695     case RANGE:
1696     case RESET:
1697     case SEARCH:
1698     case SUBMIT:
1699     case TELEPHONE:
1700     case TEXT:
1701     case URL:
1702         return DateComponents::invalidMilliseconds();
1703     }
1704     ASSERT_NOT_REACHED();
1705     return DateComponents::invalidMilliseconds();
1706 }
1707 
setValueAsDate(double value,ExceptionCode & ec)1708 void HTMLInputElement::setValueAsDate(double value, ExceptionCode& ec)
1709 {
1710     DateComponents date;
1711     bool success;
1712     switch (inputType()) {
1713     case DATE:
1714         success = date.setMillisecondsSinceEpochForDate(value);
1715         break;
1716     case DATETIME:
1717         success = date.setMillisecondsSinceEpochForDateTime(value);
1718         break;
1719     case MONTH:
1720         success = date.setMillisecondsSinceEpochForMonth(value);
1721         break;
1722     case TIME:
1723         success = date.setMillisecondsSinceMidnight(value);
1724         break;
1725     case WEEK:
1726         success = date.setMillisecondsSinceEpochForWeek(value);
1727         break;
1728     case BUTTON:
1729     case CHECKBOX:
1730     case COLOR:
1731     case DATETIMELOCAL: // valueAsDate doesn't work for the DATETIMELOCAL type according to the standard.
1732     case EMAIL:
1733     case FILE:
1734     case HIDDEN:
1735     case IMAGE:
1736     case ISINDEX:
1737     case NUMBER:
1738     case PASSWORD:
1739     case RADIO:
1740     case RANGE:
1741     case RESET:
1742     case SEARCH:
1743     case SUBMIT:
1744     case TELEPHONE:
1745     case TEXT:
1746     case URL:
1747         ec = INVALID_STATE_ERR;
1748         return;
1749     default:
1750         ASSERT_NOT_REACHED();
1751         success = false;
1752     }
1753     if (!success) {
1754         setValue(String());
1755         return;
1756     }
1757     setDateValue(date);
1758 }
1759 
setDateValue(const DateComponents & date)1760 void HTMLInputElement::setDateValue(const DateComponents& date)
1761 {
1762     double step;
1763     if (!getAllowedValueStep(&step)) {
1764         setValue(date.toString());
1765         return;
1766     }
1767     if (!fmod(step, msecPerMinute)) {
1768         setValue(date.toString(DateComponents::None));
1769         return;
1770     }
1771     if (!fmod(step, msecPerSecond)) {
1772         setValue(date.toString(DateComponents::Second));
1773         return;
1774     }
1775     setValue(date.toString(DateComponents::Millisecond));
1776 }
1777 
valueAsNumber() const1778 double HTMLInputElement::valueAsNumber() const
1779 {
1780     const double nan = numeric_limits<double>::quiet_NaN();
1781     switch (inputType()) {
1782     case DATE:
1783     case DATETIME:
1784     case DATETIMELOCAL:
1785     case MONTH:
1786     case NUMBER:
1787     case RANGE:
1788     case TIME:
1789     case WEEK:
1790         return parseToDouble(value(), nan);
1791 
1792     case BUTTON:
1793     case CHECKBOX:
1794     case COLOR:
1795     case EMAIL:
1796     case FILE:
1797     case HIDDEN:
1798     case IMAGE:
1799     case ISINDEX:
1800     case PASSWORD:
1801     case RADIO:
1802     case RESET:
1803     case SEARCH:
1804     case SUBMIT:
1805     case TELEPHONE:
1806     case TEXT:
1807     case URL:
1808         return nan;
1809     }
1810     ASSERT_NOT_REACHED();
1811     return nan;
1812 }
1813 
setValueAsNumber(double newValue,ExceptionCode & ec)1814 void HTMLInputElement::setValueAsNumber(double newValue, ExceptionCode& ec)
1815 {
1816     if (!isfinite(newValue)) {
1817         ec = NOT_SUPPORTED_ERR;
1818         return;
1819     }
1820     switch (inputType()) {
1821     case DATE:
1822     case DATETIME:
1823     case TIME:
1824     case WEEK:
1825         setValueAsDate(newValue, ec);
1826         return;
1827     case MONTH: {
1828         DateComponents date;
1829         if (!date.setMonthsSinceEpoch(newValue)) {
1830             setValue(String());
1831             return;
1832         }
1833         setValue(date.toString());
1834         return;
1835     }
1836     case DATETIMELOCAL: {
1837         DateComponents date;
1838         if (!date.setMillisecondsSinceEpochForDateTimeLocal(newValue)) {
1839             setValue(String());
1840             return;
1841         }
1842         setDateValue(date);
1843         return;
1844     }
1845     case NUMBER:
1846     case RANGE:
1847         setValue(formStringFromDouble(newValue));
1848         return;
1849 
1850     case BUTTON:
1851     case CHECKBOX:
1852     case COLOR:
1853     case EMAIL:
1854     case FILE:
1855     case HIDDEN:
1856     case IMAGE:
1857     case ISINDEX:
1858     case PASSWORD:
1859     case RADIO:
1860     case RESET:
1861     case SEARCH:
1862     case SUBMIT:
1863     case TELEPHONE:
1864     case TEXT:
1865     case URL:
1866         ec = INVALID_STATE_ERR;
1867         return;
1868     }
1869     ASSERT_NOT_REACHED();
1870     return;
1871 }
1872 
placeholder() const1873 String HTMLInputElement::placeholder() const
1874 {
1875     return getAttribute(placeholderAttr).string();
1876 }
1877 
setPlaceholder(const String & value)1878 void HTMLInputElement::setPlaceholder(const String& value)
1879 {
1880     setAttribute(placeholderAttr, value);
1881 }
1882 
searchEventsShouldBeDispatched() const1883 bool HTMLInputElement::searchEventsShouldBeDispatched() const
1884 {
1885     return hasAttribute(incrementalAttr);
1886 }
1887 
setValueFromRenderer(const String & value)1888 void HTMLInputElement::setValueFromRenderer(const String& value)
1889 {
1890     // File upload controls will always use setFileListFromRenderer.
1891     ASSERT(inputType() != FILE);
1892     m_data.setSuggestedValue(String());
1893     updatePlaceholderVisibility(false);
1894     InputElement::setValueFromRenderer(m_data, this, this, value);
1895     setNeedsValidityCheck();
1896 }
1897 
setFileListFromRenderer(const Vector<String> & paths)1898 void HTMLInputElement::setFileListFromRenderer(const Vector<String>& paths)
1899 {
1900     m_fileList->clear();
1901     int size = paths.size();
1902     for (int i = 0; i < size; i++)
1903         m_fileList->append(File::create(paths[i]));
1904 
1905     setFormControlValueMatchesRenderer(true);
1906     InputElement::notifyFormStateChanged(this);
1907     setNeedsValidityCheck();
1908 }
1909 
storesValueSeparateFromAttribute() const1910 bool HTMLInputElement::storesValueSeparateFromAttribute() const
1911 {
1912     switch (inputType()) {
1913         case BUTTON:
1914         case CHECKBOX:
1915         case HIDDEN:
1916         case IMAGE:
1917         case RADIO:
1918         case RESET:
1919         case SUBMIT:
1920             return false;
1921         case COLOR:
1922         case DATE:
1923         case DATETIME:
1924         case DATETIMELOCAL:
1925         case EMAIL:
1926         case FILE:
1927         case ISINDEX:
1928         case MONTH:
1929         case NUMBER:
1930         case PASSWORD:
1931         case RANGE:
1932         case SEARCH:
1933         case TELEPHONE:
1934         case TEXT:
1935         case TIME:
1936         case URL:
1937         case WEEK:
1938             return true;
1939     }
1940     return false;
1941 }
1942 
preDispatchEventHandler(Event * evt)1943 void* HTMLInputElement::preDispatchEventHandler(Event *evt)
1944 {
1945     // preventDefault or "return false" are used to reverse the automatic checking/selection we do here.
1946     // This result gives us enough info to perform the "undo" in postDispatch of the action we take here.
1947     void* result = 0;
1948     if ((inputType() == CHECKBOX || inputType() == RADIO) && evt->isMouseEvent()
1949             && evt->type() == eventNames().clickEvent && static_cast<MouseEvent*>(evt)->button() == LeftButton) {
1950         if (inputType() == CHECKBOX) {
1951             // As a way to store the state, we return 0 if we were unchecked, 1 if we were checked, and 2 for
1952             // indeterminate.
1953             if (indeterminate()) {
1954                 result = (void*)0x2;
1955                 setIndeterminate(false);
1956             } else {
1957                 if (checked())
1958                     result = (void*)0x1;
1959                 setChecked(!checked(), true);
1960             }
1961         } else {
1962             // For radio buttons, store the current selected radio object.
1963             // We really want radio groups to end up in sane states, i.e., to have something checked.
1964             // Therefore if nothing is currently selected, we won't allow this action to be "undone", since
1965             // we want some object in the radio group to actually get selected.
1966             HTMLInputElement* currRadio = checkedRadioButtons(this).checkedButtonForGroup(name());
1967             if (currRadio) {
1968                 // We have a radio button selected that is not us.  Cache it in our result field and ref it so
1969                 // that it can't be destroyed.
1970                 currRadio->ref();
1971                 result = currRadio;
1972             }
1973             setChecked(true, true);
1974         }
1975     }
1976     return result;
1977 }
1978 
postDispatchEventHandler(Event * evt,void * data)1979 void HTMLInputElement::postDispatchEventHandler(Event *evt, void* data)
1980 {
1981     if ((inputType() == CHECKBOX || inputType() == RADIO) && evt->isMouseEvent()
1982             && evt->type() == eventNames().clickEvent && static_cast<MouseEvent*>(evt)->button() == LeftButton) {
1983         if (inputType() == CHECKBOX) {
1984             // Reverse the checking we did in preDispatch.
1985             if (evt->defaultPrevented() || evt->defaultHandled()) {
1986                 if (data == (void*)0x2)
1987                     setIndeterminate(true);
1988                 else
1989                     setChecked(data);
1990             }
1991         } else if (data) {
1992             HTMLInputElement* input = static_cast<HTMLInputElement*>(data);
1993             if (evt->defaultPrevented() || evt->defaultHandled()) {
1994                 // Restore the original selected radio button if possible.
1995                 // Make sure it is still a radio button and only do the restoration if it still
1996                 // belongs to our group.
1997 
1998                 if (input->form() == form() && input->inputType() == RADIO && input->name() == name()) {
1999                     // Ok, the old radio button is still in our form and in our group and is still a
2000                     // radio button, so it's safe to restore selection to it.
2001                     input->setChecked(true);
2002                 }
2003             }
2004             input->deref();
2005         }
2006 
2007         // Left clicks on radio buttons and check boxes already performed default actions in preDispatchEventHandler().
2008         evt->setDefaultHandled();
2009     }
2010 }
2011 
defaultEventHandler(Event * evt)2012 void HTMLInputElement::defaultEventHandler(Event* evt)
2013 {
2014     // FIXME: It would be better to refactor this for the different types of input element.
2015     // Having them all in one giant function makes this hard to read, and almost all the handling is type-specific.
2016 
2017     bool clickDefaultFormButton = false;
2018 
2019     if (isTextField() && evt->type() == eventNames().textInputEvent && evt->isTextEvent() && static_cast<TextEvent*>(evt)->data() == "\n")
2020         clickDefaultFormButton = true;
2021 
2022     if (inputType() == IMAGE && evt->isMouseEvent() && evt->type() == eventNames().clickEvent) {
2023         // record the mouse position for when we get the DOMActivate event
2024         MouseEvent* me = static_cast<MouseEvent*>(evt);
2025         // FIXME: We could just call offsetX() and offsetY() on the event,
2026         // but that's currently broken, so for now do the computation here.
2027         if (me->isSimulated() || !renderer()) {
2028             m_xPos = 0;
2029             m_yPos = 0;
2030         } else {
2031             // FIXME: This doesn't work correctly with transforms.
2032             // FIXME: pageX/pageY need adjusting for pageZoomFactor(). Use actualPageLocation()?
2033             IntPoint absOffset = roundedIntPoint(renderer()->localToAbsolute());
2034             m_xPos = me->pageX() - absOffset.x();
2035             m_yPos = me->pageY() - absOffset.y();
2036         }
2037     }
2038 
2039     if (isTextField()
2040             && evt->type() == eventNames().keydownEvent
2041             && evt->isKeyboardEvent()
2042             && focused()
2043             && document()->frame()
2044             && document()->frame()->doTextFieldCommandFromEvent(this, static_cast<KeyboardEvent*>(evt))) {
2045         evt->setDefaultHandled();
2046         return;
2047     }
2048 
2049     if (inputType() == RADIO
2050             && evt->isMouseEvent()
2051             && evt->type() == eventNames().clickEvent
2052             && static_cast<MouseEvent*>(evt)->button() == LeftButton) {
2053         evt->setDefaultHandled();
2054         return;
2055     }
2056 
2057     // Call the base event handler before any of our own event handling for almost all events in text fields.
2058     // Makes editing keyboard handling take precedence over the keydown and keypress handling in this function.
2059     bool callBaseClassEarly = isTextField() && !clickDefaultFormButton
2060         && (evt->type() == eventNames().keydownEvent || evt->type() == eventNames().keypressEvent);
2061     if (callBaseClassEarly) {
2062         HTMLFormControlElementWithState::defaultEventHandler(evt);
2063         if (evt->defaultHandled())
2064             return;
2065     }
2066 
2067     // DOMActivate events cause the input to be "activated" - in the case of image and submit inputs, this means
2068     // actually submitting the form. For reset inputs, the form is reset. These events are sent when the user clicks
2069     // on the element, or presses enter while it is the active element. JavaScript code wishing to activate the element
2070     // must dispatch a DOMActivate event - a click event will not do the job.
2071     if (evt->type() == eventNames().DOMActivateEvent && !disabled()) {
2072         if (inputType() == IMAGE || inputType() == SUBMIT || inputType() == RESET) {
2073             if (!form())
2074                 return;
2075             if (inputType() == RESET)
2076                 form()->reset();
2077             else {
2078                 m_activeSubmit = true;
2079                 // FIXME: Would be cleaner to get m_xPos and m_yPos out of the underlying mouse
2080                 // event (if any) here instead of relying on the variables set above when
2081                 // processing the click event. Even better, appendFormData could pass the
2082                 // event in, and then we could get rid of m_xPos and m_yPos altogether!
2083                 if (!form()->prepareSubmit(evt)) {
2084                     m_xPos = 0;
2085                     m_yPos = 0;
2086                 }
2087                 m_activeSubmit = false;
2088             }
2089         } else if (inputType() == FILE && renderer())
2090             toRenderFileUploadControl(renderer())->click();
2091     }
2092 
2093     // Use key press event here since sending simulated mouse events
2094     // on key down blocks the proper sending of the key press event.
2095     if (evt->type() == eventNames().keypressEvent && evt->isKeyboardEvent()) {
2096         bool clickElement = false;
2097 
2098         int charCode = static_cast<KeyboardEvent*>(evt)->charCode();
2099 
2100         if (charCode == '\r') {
2101             switch (inputType()) {
2102                 case CHECKBOX:
2103                 case COLOR:
2104                 case DATE:
2105                 case DATETIME:
2106                 case DATETIMELOCAL:
2107                 case EMAIL:
2108                 case HIDDEN:
2109                 case ISINDEX:
2110                 case MONTH:
2111                 case NUMBER:
2112                 case PASSWORD:
2113                 case RANGE:
2114                 case SEARCH:
2115                 case TELEPHONE:
2116                 case TEXT:
2117                 case TIME:
2118                 case URL:
2119                 case WEEK:
2120                     // Simulate mouse click on the default form button for enter for these types of elements.
2121                     clickDefaultFormButton = true;
2122                     break;
2123                 case BUTTON:
2124                 case FILE:
2125                 case IMAGE:
2126                 case RESET:
2127                 case SUBMIT:
2128                     // Simulate mouse click for enter for these types of elements.
2129                     clickElement = true;
2130                     break;
2131                 case RADIO:
2132                     break; // Don't do anything for enter on a radio button.
2133             }
2134         } else if (charCode == ' ') {
2135             switch (inputType()) {
2136                 case BUTTON:
2137                 case CHECKBOX:
2138                 case FILE:
2139                 case IMAGE:
2140                 case RESET:
2141                 case SUBMIT:
2142                 case RADIO:
2143                     // Prevent scrolling down the page.
2144                     evt->setDefaultHandled();
2145                     return;
2146                 default:
2147                     break;
2148             }
2149         }
2150 
2151         if (clickElement) {
2152             dispatchSimulatedClick(evt);
2153             evt->setDefaultHandled();
2154             return;
2155         }
2156     }
2157 
2158     if (evt->type() == eventNames().keydownEvent && evt->isKeyboardEvent()) {
2159         String key = static_cast<KeyboardEvent*>(evt)->keyIdentifier();
2160 
2161         if (key == "U+0020") {
2162             switch (inputType()) {
2163                 case BUTTON:
2164                 case CHECKBOX:
2165                 case FILE:
2166                 case IMAGE:
2167                 case RESET:
2168                 case SUBMIT:
2169                 case RADIO:
2170                     setActive(true, true);
2171                     // No setDefaultHandled(), because IE dispatches a keypress in this case
2172                     // and the caller will only dispatch a keypress if we don't call setDefaultHandled.
2173                     return;
2174                 default:
2175                     break;
2176             }
2177         }
2178 
2179 // allow enter to change state of radio
2180         if (inputType() == RADIO && (key == "Up" || key == "Down" || key == "Left" || key == "Right")) {
2181             // Left and up mean "previous radio button".
2182             // Right and down mean "next radio button".
2183             // Tested in WinIE, and even for RTL, left still means previous radio button (and so moves
2184             // to the right).  Seems strange, but we'll match it.
2185             bool forward = (key == "Down" || key == "Right");
2186 
2187             // We can only stay within the form's children if the form hasn't been demoted to a leaf because
2188             // of malformed HTML.
2189             Node* n = this;
2190             while ((n = (forward ? n->traverseNextNode() : n->traversePreviousNode()))) {
2191                 // Once we encounter a form element, we know we're through.
2192                 if (n->hasTagName(formTag))
2193                     break;
2194 
2195                 // Look for more radio buttons.
2196                 if (n->hasTagName(inputTag)) {
2197                     HTMLInputElement* elt = static_cast<HTMLInputElement*>(n);
2198                     if (elt->form() != form())
2199                         break;
2200                     if (n->hasTagName(inputTag)) {
2201                         HTMLInputElement* inputElt = static_cast<HTMLInputElement*>(n);
2202                         if (inputElt->inputType() == RADIO && inputElt->name() == name() && inputElt->isFocusable()) {
2203                             inputElt->setChecked(true);
2204                             document()->setFocusedNode(inputElt);
2205                             inputElt->dispatchSimulatedClick(evt, false, false);
2206                             evt->setDefaultHandled();
2207                             break;
2208                         }
2209                     }
2210                 }
2211             }
2212         }
2213     }
2214 
2215     if (evt->type() == eventNames().keyupEvent && evt->isKeyboardEvent()) {
2216         bool clickElement = false;
2217 
2218         String key = static_cast<KeyboardEvent*>(evt)->keyIdentifier();
2219 
2220         if (key == "U+0020") {
2221             switch (inputType()) {
2222                 case BUTTON:
2223                 case CHECKBOX:
2224                 case FILE:
2225                 case IMAGE:
2226                 case RESET:
2227                 case SUBMIT:
2228                     // Simulate mouse click for spacebar for these types of elements.
2229                     // The AppKit already does this for some, but not all, of them.
2230                     clickElement = true;
2231                     break;
2232                 case RADIO:
2233                     // If an unselected radio is tabbed into (because the entire group has nothing
2234                     // checked, or because of some explicit .focus() call), then allow space to check it.
2235                     if (!checked())
2236                         clickElement = true;
2237                     break;
2238                 case COLOR:
2239                 case DATE:
2240                 case DATETIME:
2241                 case DATETIMELOCAL:
2242                 case EMAIL:
2243                 case HIDDEN:
2244                 case ISINDEX:
2245                 case MONTH:
2246                 case NUMBER:
2247                 case PASSWORD:
2248                 case RANGE:
2249                 case SEARCH:
2250                 case TELEPHONE:
2251                 case TEXT:
2252                 case TIME:
2253                 case URL:
2254                 case WEEK:
2255                     break;
2256             }
2257         }
2258 
2259         if (clickElement) {
2260             if (active())
2261                 dispatchSimulatedClick(evt);
2262             evt->setDefaultHandled();
2263             return;
2264         }
2265     }
2266 
2267     if (clickDefaultFormButton) {
2268         if (isSearchField()) {
2269             addSearchResult();
2270             onSearch();
2271         }
2272         // Fire onChange for text fields.
2273         RenderObject* r = renderer();
2274         if (r && r->isTextField() && toRenderTextControl(r)->wasChangedSinceLastChangeEvent()) {
2275             dispatchFormControlChangeEvent();
2276             // Refetch the renderer since arbitrary JS code run during onchange can do anything, including destroying it.
2277             r = renderer();
2278             if (r && r->isTextField())
2279                 toRenderTextControl(r)->setChangedSinceLastChangeEvent(false);
2280         }
2281 
2282         RefPtr<HTMLFormElement> formForSubmission = form();
2283         // If there is no form and the element is an <isindex>, then create a temporary form just to be used for submission.
2284         if (!formForSubmission && inputType() == ISINDEX)
2285             formForSubmission = createTemporaryFormForIsIndex();
2286 
2287         // Form may never have been present, or may have been destroyed by code responding to the change event.
2288         if (formForSubmission)
2289             formForSubmission->submitClick(evt);
2290 
2291         evt->setDefaultHandled();
2292         return;
2293     }
2294 
2295     if (evt->isBeforeTextInsertedEvent())
2296         InputElement::handleBeforeTextInsertedEvent(m_data, this, this, evt);
2297 
2298     if (isTextField() && renderer() && (evt->isMouseEvent() || evt->isDragEvent() || evt->isWheelEvent() || evt->type() == eventNames().blurEvent || evt->type() == eventNames().focusEvent))
2299         toRenderTextControlSingleLine(renderer())->forwardEvent(evt);
2300 
2301     if (inputType() == RANGE && renderer() && (evt->isMouseEvent() || evt->isDragEvent() || evt->isWheelEvent()))
2302         toRenderSlider(renderer())->forwardEvent(evt);
2303 
2304     if (!callBaseClassEarly && !evt->defaultHandled())
2305         HTMLFormControlElementWithState::defaultEventHandler(evt);
2306 }
2307 
createTemporaryFormForIsIndex()2308 PassRefPtr<HTMLFormElement> HTMLInputElement::createTemporaryFormForIsIndex()
2309 {
2310     RefPtr<HTMLFormElement> form = new HTMLFormElement(formTag, document());
2311     form->registerFormElement(this);
2312     form->setMethod("GET");
2313     if (!document()->baseURL().isEmpty()) {
2314         // We treat the href property of the <base> element as the form action, as per section 7.5
2315         // "Queries and Indexes" of the HTML 2.0 spec. <http://www.w3.org/MarkUp/html-spec/html-spec_7.html#SEC7.5>.
2316         form->setAction(document()->baseURL().string());
2317     }
2318     return form.release();
2319 }
2320 
isURLAttribute(Attribute * attr) const2321 bool HTMLInputElement::isURLAttribute(Attribute *attr) const
2322 {
2323     return (attr->name() == srcAttr);
2324 }
2325 
defaultValue() const2326 String HTMLInputElement::defaultValue() const
2327 {
2328     return getAttribute(valueAttr);
2329 }
2330 
setDefaultValue(const String & value)2331 void HTMLInputElement::setDefaultValue(const String &value)
2332 {
2333     setAttribute(valueAttr, value);
2334 }
2335 
defaultChecked() const2336 bool HTMLInputElement::defaultChecked() const
2337 {
2338     return !getAttribute(checkedAttr).isNull();
2339 }
2340 
setDefaultChecked(bool defaultChecked)2341 void HTMLInputElement::setDefaultChecked(bool defaultChecked)
2342 {
2343     setAttribute(checkedAttr, defaultChecked ? "" : 0);
2344 }
2345 
setDefaultName(const AtomicString & name)2346 void HTMLInputElement::setDefaultName(const AtomicString& name)
2347 {
2348     m_data.setName(name);
2349 }
2350 
accept() const2351 String HTMLInputElement::accept() const
2352 {
2353     return getAttribute(acceptAttr);
2354 }
2355 
setAccept(const String & value)2356 void HTMLInputElement::setAccept(const String &value)
2357 {
2358     setAttribute(acceptAttr, value);
2359 }
2360 
accessKey() const2361 String HTMLInputElement::accessKey() const
2362 {
2363     return getAttribute(accesskeyAttr);
2364 }
2365 
setAccessKey(const String & value)2366 void HTMLInputElement::setAccessKey(const String &value)
2367 {
2368     setAttribute(accesskeyAttr, value);
2369 }
2370 
align() const2371 String HTMLInputElement::align() const
2372 {
2373     return getAttribute(alignAttr);
2374 }
2375 
setAlign(const String & value)2376 void HTMLInputElement::setAlign(const String &value)
2377 {
2378     setAttribute(alignAttr, value);
2379 }
2380 
alt() const2381 String HTMLInputElement::alt() const
2382 {
2383     return getAttribute(altAttr);
2384 }
2385 
setAlt(const String & value)2386 void HTMLInputElement::setAlt(const String &value)
2387 {
2388     setAttribute(altAttr, value);
2389 }
2390 
maxLength() const2391 int HTMLInputElement::maxLength() const
2392 {
2393     return m_data.maxLength();
2394 }
2395 
setMaxLength(int maxLength,ExceptionCode & ec)2396 void HTMLInputElement::setMaxLength(int maxLength, ExceptionCode& ec)
2397 {
2398     if (maxLength < 0)
2399         ec = INDEX_SIZE_ERR;
2400     else
2401         setAttribute(maxlengthAttr, String::number(maxLength));
2402 }
2403 
multiple() const2404 bool HTMLInputElement::multiple() const
2405 {
2406     return !getAttribute(multipleAttr).isNull();
2407 }
2408 
setMultiple(bool multiple)2409 void HTMLInputElement::setMultiple(bool multiple)
2410 {
2411     setAttribute(multipleAttr, multiple ? "" : 0);
2412 }
2413 
setSize(unsigned _size)2414 void HTMLInputElement::setSize(unsigned _size)
2415 {
2416     setAttribute(sizeAttr, String::number(_size));
2417 }
2418 
src() const2419 KURL HTMLInputElement::src() const
2420 {
2421     return document()->completeURL(getAttribute(srcAttr));
2422 }
2423 
setSrc(const String & value)2424 void HTMLInputElement::setSrc(const String &value)
2425 {
2426     setAttribute(srcAttr, value);
2427 }
2428 
useMap() const2429 String HTMLInputElement::useMap() const
2430 {
2431     return getAttribute(usemapAttr);
2432 }
2433 
setUseMap(const String & value)2434 void HTMLInputElement::setUseMap(const String &value)
2435 {
2436     setAttribute(usemapAttr, value);
2437 }
2438 
setAutofilled(bool b)2439 void HTMLInputElement::setAutofilled(bool b)
2440 {
2441     if (b == m_autofilled)
2442         return;
2443 
2444     m_autofilled = b;
2445     setNeedsStyleRecalc();
2446 }
2447 
files()2448 FileList* HTMLInputElement::files()
2449 {
2450     if (inputType() != FILE)
2451         return 0;
2452     return m_fileList.get();
2453 }
2454 
sanitizeValue(const String & proposedValue) const2455 String HTMLInputElement::sanitizeValue(const String& proposedValue) const
2456 {
2457     if (isTextField())
2458         return InputElement::sanitizeValue(this, proposedValue);
2459     return proposedValue;
2460 }
2461 
needsActivationCallback()2462 bool HTMLInputElement::needsActivationCallback()
2463 {
2464     return inputType() == PASSWORD || m_autocomplete == Off;
2465 }
2466 
registerForActivationCallbackIfNeeded()2467 void HTMLInputElement::registerForActivationCallbackIfNeeded()
2468 {
2469     if (needsActivationCallback())
2470         document()->registerForDocumentActivationCallbacks(this);
2471 }
2472 
unregisterForActivationCallbackIfNeeded()2473 void HTMLInputElement::unregisterForActivationCallbackIfNeeded()
2474 {
2475     if (!needsActivationCallback())
2476         document()->unregisterForDocumentActivationCallbacks(this);
2477 }
2478 
isRequiredFormControl() const2479 bool HTMLInputElement::isRequiredFormControl() const
2480 {
2481     if (!required())
2482         return false;
2483 
2484     switch (inputType()) {
2485         case CHECKBOX:
2486         case DATE:
2487         case DATETIME:
2488         case DATETIMELOCAL:
2489         case EMAIL:
2490         case FILE:
2491         case MONTH:
2492         case NUMBER:
2493         case PASSWORD:
2494         case RADIO:
2495         case SEARCH:
2496         case TELEPHONE:
2497         case TEXT:
2498         case TIME:
2499         case URL:
2500         case WEEK:
2501             return true;
2502         case BUTTON:
2503         case COLOR:
2504         case HIDDEN:
2505         case IMAGE:
2506         case ISINDEX:
2507         case RANGE:
2508         case RESET:
2509         case SUBMIT:
2510             return false;
2511     }
2512 
2513     ASSERT_NOT_REACHED();
2514     return false;
2515 }
2516 
cacheSelection(int start,int end)2517 void HTMLInputElement::cacheSelection(int start, int end)
2518 {
2519     m_data.setCachedSelectionStart(start);
2520     m_data.setCachedSelectionEnd(end);
2521 }
2522 
addSearchResult()2523 void HTMLInputElement::addSearchResult()
2524 {
2525     ASSERT(isSearchField());
2526     if (renderer())
2527         toRenderTextControlSingleLine(renderer())->addSearchResult();
2528 }
2529 
onSearch()2530 void HTMLInputElement::onSearch()
2531 {
2532     ASSERT(isSearchField());
2533     if (renderer())
2534         toRenderTextControlSingleLine(renderer())->stopSearchEventTimer();
2535     dispatchEvent(Event::create(eventNames().searchEvent, true, false));
2536 }
2537 
documentDidBecomeActive()2538 void HTMLInputElement::documentDidBecomeActive()
2539 {
2540     ASSERT(needsActivationCallback());
2541     reset();
2542 }
2543 
willMoveToNewOwnerDocument()2544 void HTMLInputElement::willMoveToNewOwnerDocument()
2545 {
2546     // Always unregister for cache callbacks when leaving a document, even if we would otherwise like to be registered
2547     if (needsActivationCallback())
2548         document()->unregisterForDocumentActivationCallbacks(this);
2549 
2550     document()->checkedRadioButtons().removeButton(this);
2551 
2552     HTMLFormControlElementWithState::willMoveToNewOwnerDocument();
2553 }
2554 
didMoveToNewOwnerDocument()2555 void HTMLInputElement::didMoveToNewOwnerDocument()
2556 {
2557     registerForActivationCallbackIfNeeded();
2558 
2559     HTMLFormControlElementWithState::didMoveToNewOwnerDocument();
2560 }
2561 
addSubresourceAttributeURLs(ListHashSet<KURL> & urls) const2562 void HTMLInputElement::addSubresourceAttributeURLs(ListHashSet<KURL>& urls) const
2563 {
2564     HTMLFormControlElementWithState::addSubresourceAttributeURLs(urls);
2565 
2566     addSubresourceURL(urls, src());
2567 }
2568 
willValidate() const2569 bool HTMLInputElement::willValidate() const
2570 {
2571     // FIXME: This shall check for new WF2 input types too
2572     return HTMLFormControlElementWithState::willValidate() && inputType() != HIDDEN &&
2573            inputType() != BUTTON && inputType() != RESET;
2574 }
2575 
formStringFromDouble(double number)2576 String HTMLInputElement::formStringFromDouble(double number)
2577 {
2578     // According to HTML5, "the best representation of the number n as a floating
2579     // point number" is a string produced by applying ToString() to n.
2580     DtoaBuffer buffer;
2581     unsigned length;
2582     doubleToStringInJavaScriptFormat(number, buffer, &length);
2583     return String(buffer, length);
2584 }
2585 
formStringToDouble(const String & src,double * out)2586 bool HTMLInputElement::formStringToDouble(const String& src, double* out)
2587 {
2588     // See HTML5 2.4.4.3 `Real numbers.'
2589 
2590     if (src.isEmpty())
2591         return false;
2592     // String::toDouble() accepts leading + \t \n \v \f \r and SPACE, which are invalid in HTML5.
2593     // So, check the first character.
2594     if (src[0] != '-' && (src[0] < '0' || src[0] > '9'))
2595         return false;
2596 
2597     bool valid = false;
2598     double value = src.toDouble(&valid);
2599     if (!valid)
2600         return false;
2601     // NaN and Infinity are not valid numbers according to the standard.
2602     if (!isfinite(value))
2603         return false;
2604     // -0 -> 0
2605     if (!value)
2606         value = 0;
2607     if (out)
2608         *out = value;
2609     return true;
2610 }
2611 
formStringToDateComponents(InputType type,const String & formString,DateComponents * out)2612 bool HTMLInputElement::formStringToDateComponents(InputType type, const String& formString, DateComponents* out)
2613 {
2614     if (formString.isEmpty())
2615         return false;
2616     DateComponents ignoredResult;
2617     if (!out)
2618         out = &ignoredResult;
2619     const UChar* characters = formString.characters();
2620     unsigned length = formString.length();
2621     unsigned end;
2622 
2623     switch (type) {
2624     case DATE:
2625         return out->parseDate(characters, length, 0, end) && end == length;
2626     case DATETIME:
2627         return out->parseDateTime(characters, length, 0, end) && end == length;
2628     case DATETIMELOCAL:
2629         return out->parseDateTimeLocal(characters, length, 0, end) && end == length;
2630     case MONTH:
2631         return out->parseMonth(characters, length, 0, end) && end == length;
2632     case WEEK:
2633         return out->parseWeek(characters, length, 0, end) && end == length;
2634     case TIME:
2635         return out->parseTime(characters, length, 0, end) && end == length;
2636     default:
2637         ASSERT_NOT_REACHED();
2638         return false;
2639     }
2640 }
2641 
2642 #if ENABLE(DATALIST)
list() const2643 HTMLElement* HTMLInputElement::list() const
2644 {
2645     return dataList();
2646 }
2647 
dataList() const2648 HTMLDataListElement* HTMLInputElement::dataList() const
2649 {
2650     if (!m_hasNonEmptyList)
2651         return 0;
2652 
2653     switch (inputType()) {
2654     case COLOR:
2655     case DATE:
2656     case DATETIME:
2657     case DATETIMELOCAL:
2658     case EMAIL:
2659     case MONTH:
2660     case NUMBER:
2661     case RANGE:
2662     case SEARCH:
2663     case TELEPHONE:
2664     case TEXT:
2665     case TIME:
2666     case URL:
2667     case WEEK: {
2668         Element* element = document()->getElementById(getAttribute(listAttr));
2669         if (element && element->hasTagName(datalistTag))
2670             return static_cast<HTMLDataListElement*>(element);
2671         break;
2672     }
2673     case BUTTON:
2674     case CHECKBOX:
2675     case FILE:
2676     case HIDDEN:
2677     case IMAGE:
2678     case ISINDEX:
2679     case PASSWORD:
2680     case RADIO:
2681     case RESET:
2682     case SUBMIT:
2683         break;
2684     }
2685     return 0;
2686 }
2687 
selectedOption() const2688 HTMLOptionElement* HTMLInputElement::selectedOption() const
2689 {
2690     String currentValue = value();
2691     // The empty value never matches to a datalist option because it
2692     // doesn't represent a suggestion according to the standard.
2693     if (currentValue.isEmpty())
2694         return 0;
2695 
2696     HTMLDataListElement* sourceElement = dataList();
2697     if (!sourceElement)
2698         return 0;
2699     RefPtr<HTMLCollection> options = sourceElement->options();
2700     for (unsigned i = 0; options && i < options->length(); ++i) {
2701         HTMLOptionElement* option = static_cast<HTMLOptionElement*>(options->item(i));
2702         if (!option->disabled() && currentValue == option->value())
2703             return option;
2704     }
2705     return 0;
2706 }
2707 #endif  // ENABLE(DATALIST)
2708 
2709 } // namespace
2710