HTMLInputElement.cpp revision 17789fff81dac758d724db8595a5ce80c949af5e
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 "Document.h"
33#include "Editor.h"
34#include "Event.h"
35#include "EventHandler.h"
36#include "EventNames.h"
37#include "ExceptionCode.h"
38#include "File.h"
39#include "FileList.h"
40#include "FocusController.h"
41#include "FormDataList.h"
42#include "Frame.h"
43#include "HTMLDataListElement.h"
44#include "HTMLFormElement.h"
45#include "HTMLImageLoader.h"
46#include "HTMLNames.h"
47#include "HTMLOptionElement.h"
48#include "ISODateTime.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
73using namespace std;
74
75namespace WebCore {
76
77using namespace HTMLNames;
78
79const int maxSavedResults = 256;
80
81// Constant values for getAllowedValueStep().
82static const double numberDefaultStep = 1.0;
83static const double numberStepScaleFactor = 1.0;
84// Constant values for minimum().
85static const double numberDefaultMinimum = -DBL_MAX;
86static const double rangeDefaultMinimum = 0.0;
87// Constant values for maximum().
88static const double numberDefaultMaximum = DBL_MAX;
89static const double rangeDefaultMaximum = 100.0;
90
91HTMLInputElement::HTMLInputElement(const QualifiedName& tagName, Document* doc, HTMLFormElement* f)
92    : HTMLTextFormControlElement(tagName, doc, f)
93    , m_xPos(0)
94    , m_yPos(0)
95    , m_maxResults(-1)
96    , m_type(TEXT)
97    , m_checked(false)
98    , m_defaultChecked(false)
99    , m_useDefaultChecked(true)
100    , m_indeterminate(false)
101    , m_haveType(false)
102    , m_activeSubmit(false)
103    , m_autocomplete(Uninitialized)
104    , m_autofilled(false)
105    , m_inited(false)
106{
107    ASSERT(hasTagName(inputTag) || hasTagName(isindexTag));
108}
109
110HTMLInputElement::~HTMLInputElement()
111{
112    if (needsActivationCallback())
113        document()->unregisterForDocumentActivationCallbacks(this);
114
115    document()->checkedRadioButtons().removeButton(this);
116
117    // Need to remove this from the form while it is still an HTMLInputElement,
118    // so can't wait for the base class's destructor to do it.
119    removeFromForm();
120}
121
122const AtomicString& HTMLInputElement::formControlName() const
123{
124    return m_data.name();
125}
126
127bool HTMLInputElement::autoComplete() const
128{
129    if (m_autocomplete != Uninitialized)
130        return m_autocomplete == On;
131
132    // Assuming we're still in a Form, respect the Form's setting
133    if (HTMLFormElement* form = this->form())
134        return form->autoComplete();
135
136    // The default is true
137    return true;
138}
139
140bool HTMLInputElement::valueMissing() const
141{
142    if (!isRequiredFormControl() || readOnly() || disabled())
143        return false;
144
145    switch (inputType()) {
146        case DATE:
147        case DATETIME:
148        case DATETIMELOCAL:
149        case EMAIL:
150        case FILE:
151        case MONTH:
152        case NUMBER:
153        case PASSWORD:
154        case SEARCH:
155        case TELEPHONE:
156        case TEXT:
157        case TIME:
158        case URL:
159        case WEEK:
160            return value().isEmpty();
161        case CHECKBOX:
162            return !checked();
163        case RADIO:
164            return !document()->checkedRadioButtons().checkedButtonForGroup(name());
165        case COLOR:
166            return false;
167        case BUTTON:
168        case HIDDEN:
169        case IMAGE:
170        case ISINDEX:
171        case RANGE:
172        case RESET:
173        case SUBMIT:
174            break;
175    }
176
177    ASSERT_NOT_REACHED();
178    return false;
179}
180
181bool HTMLInputElement::patternMismatch() const
182{
183    switch (inputType()) {
184        case BUTTON:
185        case CHECKBOX:
186        case COLOR:
187        case DATE:
188        case DATETIME:
189        case DATETIMELOCAL:
190        case FILE:
191        case HIDDEN:
192        case IMAGE:
193        case ISINDEX:
194        case MONTH:
195        case NUMBER:
196        case RADIO:
197        case RANGE:
198        case RESET:
199        case SUBMIT:
200        case TIME:
201        case WEEK:
202            return false;
203        case EMAIL:
204        case PASSWORD:
205        case SEARCH:
206        case TELEPHONE:
207        case TEXT:
208        case URL:
209            const AtomicString& pattern = getAttribute(patternAttr);
210            String value = this->value();
211
212            // Empty values can't be mismatched
213            if (pattern.isEmpty() || value.isEmpty())
214                return false;
215
216            RegularExpression patternRegExp(pattern, TextCaseSensitive);
217            int matchLength = 0;
218            int valueLength = value.length();
219            int matchOffset = patternRegExp.match(value, 0, &matchLength);
220
221            return matchOffset != 0 || matchLength != valueLength;
222    }
223
224    ASSERT_NOT_REACHED();
225    return false;
226}
227
228bool HTMLInputElement::tooLong() const
229{
230    switch (inputType()) {
231    case EMAIL:
232    case PASSWORD:
233    case SEARCH:
234    case TELEPHONE:
235    case TEXT:
236    case URL: {
237        int max = maxLength();
238        if (max < 0)
239            return false;
240        // Return false for the default value even if it is longer than maxLength.
241        bool userEdited = !m_data.value().isNull();
242        if (!userEdited)
243            return false;
244        return value().length() > static_cast<unsigned>(max);
245    }
246    case BUTTON:
247    case CHECKBOX:
248    case COLOR:
249    case DATE:
250    case DATETIME:
251    case DATETIMELOCAL:
252    case FILE:
253    case HIDDEN:
254    case IMAGE:
255    case ISINDEX:
256    case MONTH:
257    case NUMBER:
258    case RADIO:
259    case RANGE:
260    case RESET:
261    case SUBMIT:
262    case TIME:
263    case WEEK:
264        return false;
265    }
266    ASSERT_NOT_REACHED();
267    return false;
268}
269
270bool HTMLInputElement::rangeUnderflow() const
271{
272    if (inputType() == NUMBER || inputType() == RANGE) {
273        double doubleValue;
274        if (formStringToDouble(value(), &doubleValue))
275            return doubleValue < minimum();
276    }
277    return false;
278}
279
280bool HTMLInputElement::rangeOverflow() const
281{
282    if (inputType() == NUMBER || inputType() == RANGE) {
283        double doubleValue;
284        if (formStringToDouble(value(), &doubleValue))
285            return doubleValue > maximum();
286    }
287    return false;
288}
289
290double HTMLInputElement::minimum() const
291{
292    ASSERT(inputType() == NUMBER || inputType() == RANGE);
293    double min = inputType() == RANGE ? rangeDefaultMinimum : numberDefaultMinimum;
294    formStringToDouble(getAttribute(minAttr), &min);
295    return min;
296}
297
298double HTMLInputElement::maximum() const
299{
300    ASSERT(inputType() == NUMBER || inputType() == RANGE);
301    double defaultMaximum = inputType() == RANGE ? rangeDefaultMaximum : numberDefaultMaximum;
302    double max = defaultMaximum;
303    formStringToDouble(getAttribute(maxAttr), &max);
304    if (inputType() == RANGE) {
305        // A remedy for the inconsistent min/max values for RANGE.
306        // Sets the maxmimum to the default or the minimum value.
307        double min = minimum();
308        if (max < min)
309            max = std::max(min, defaultMaximum);
310    }
311    return max;
312}
313
314double HTMLInputElement::stepBase() const
315{
316    if (inputType() == RANGE)
317        return minimum();
318    if (inputType() == NUMBER) {
319        static const double defaultStepBase = 0.0;
320        double min = defaultStepBase;
321        formStringToDouble(getAttribute(minAttr), &min);
322        return min;
323    }
324    ASSERT_NOT_REACHED();
325    return 0.0;
326}
327
328bool HTMLInputElement::stepMismatch() const
329{
330    double step;
331    if (!getAllowedValueStep(&step))
332        return false;
333    if (inputType() == NUMBER) {
334        double doubleValue;
335        if (!formStringToDouble(value(), &doubleValue))
336            return false;
337        doubleValue = fabs(doubleValue - stepBase());
338        if (isinf(doubleValue))
339            return false;
340        // double's fractional part size is DBL_MAN_DIG-bit.  If the current
341        // value is greater than step*2^DBL_MANT_DIG, the following fmod() makes
342        // no sense.
343        if (doubleValue / pow(2.0, DBL_MANT_DIG) > step)
344            return false;
345        double remainder = fmod(doubleValue, step);
346        // Accepts errors in lower 7-bit.
347        double acceptableError = step / pow(2.0, DBL_MANT_DIG - 7);
348        return acceptableError < remainder && remainder < (step - acceptableError);
349    }
350    // Non-RANGE types should be rejected by getAllowedValueStep().
351    ASSERT(inputType() == RANGE);
352    // stepMismatch doesn't occur for RANGE. RenderSlider guarantees the
353    // value matches to step.
354    return false;
355}
356
357bool HTMLInputElement::getStepParameters(double* defaultStep, double* stepScaleFactor) const
358{
359    ASSERT(defaultStep);
360    ASSERT(stepScaleFactor);
361    switch (inputType()) {
362    case NUMBER:
363    case RANGE:
364        *defaultStep = numberDefaultStep;
365        *stepScaleFactor = numberStepScaleFactor;
366        return true;
367    case DATE:
368    case DATETIME:
369    case DATETIMELOCAL:
370    case MONTH:
371    case TIME:
372    case WEEK:
373        // FIXME: Implement for these types.
374        return false;
375    case BUTTON:
376    case CHECKBOX:
377    case COLOR:
378    case EMAIL:
379    case FILE:
380    case HIDDEN:
381    case IMAGE:
382    case ISINDEX:
383    case PASSWORD:
384    case RADIO:
385    case RESET:
386    case SEARCH:
387    case SUBMIT:
388    case TELEPHONE:
389    case TEXT:
390    case URL:
391        return false;
392    }
393    ASSERT_NOT_REACHED();
394    return false;
395}
396
397bool HTMLInputElement::getAllowedValueStep(double* step) const
398{
399    ASSERT(step);
400    double defaultStep;
401    double stepScaleFactor;
402    if (!getStepParameters(&defaultStep, &stepScaleFactor))
403        return false;
404    const AtomicString& stepString = getAttribute(stepAttr);
405    if (stepString.isEmpty()) {
406        *step = defaultStep * stepScaleFactor;
407        return true;
408    }
409    if (equalIgnoringCase(stepString, "any"))
410        return false;
411    double parsed;
412    if (!formStringToDouble(stepString, &parsed) || parsed <= 0.0) {
413        *step = defaultStep * stepScaleFactor;
414        return true;
415    }
416    *step = parsed * stepScaleFactor;
417    ASSERT(*step > 0);
418    return true;
419}
420
421void HTMLInputElement::applyStepForNumberOrRange(double count, ExceptionCode& ec)
422{
423    ASSERT(inputType() == NUMBER || inputType() == RANGE);
424    double step;
425    if (!getAllowedValueStep(&step)) {
426        ec = INVALID_STATE_ERR;
427        return;
428    }
429    double current;
430    if (!formStringToDouble(value(), &current)) {
431        ec = INVALID_STATE_ERR;
432        return;
433    }
434    double newValue = current + step * count;
435    if (isinf(newValue)) {
436        ec = INVALID_STATE_ERR;
437        return;
438    }
439    if (newValue < minimum()) {
440        ec = INVALID_STATE_ERR;
441        return;
442    }
443    double base = stepBase();
444    newValue = base + round((newValue - base) / step) * step;
445    if (newValue > maximum()) {
446        ec = INVALID_STATE_ERR;
447        return;
448    }
449    setValue(formStringFromDouble(newValue));
450}
451
452void HTMLInputElement::stepUp(int n, ExceptionCode& ec)
453{
454    if (inputType() != NUMBER && inputType() != RANGE) {
455        ec = INVALID_STATE_ERR;
456        return;
457    }
458    applyStepForNumberOrRange(n, ec);
459}
460
461void HTMLInputElement::stepDown(int n, ExceptionCode& ec)
462{
463    if (inputType() != NUMBER && inputType() != RANGE) {
464        ec = INVALID_STATE_ERR;
465        return;
466    }
467    applyStepForNumberOrRange(-n, ec);
468}
469
470static inline CheckedRadioButtons& checkedRadioButtons(const HTMLInputElement *element)
471{
472    if (HTMLFormElement* form = element->form())
473        return form->checkedRadioButtons();
474
475    return element->document()->checkedRadioButtons();
476}
477
478bool HTMLInputElement::isKeyboardFocusable(KeyboardEvent* event) const
479{
480    // If text fields can be focused, then they should always be keyboard focusable
481    if (isTextField())
482        return HTMLFormControlElementWithState::isFocusable();
483
484    // If the base class says we can't be focused, then we can stop now.
485    if (!HTMLFormControlElementWithState::isKeyboardFocusable(event))
486        return false;
487
488    if (inputType() == RADIO) {
489
490        // Never allow keyboard tabbing to leave you in the same radio group.  Always
491        // skip any other elements in the group.
492        Node* currentFocusedNode = document()->focusedNode();
493        if (currentFocusedNode && currentFocusedNode->hasTagName(inputTag)) {
494            HTMLInputElement* focusedInput = static_cast<HTMLInputElement*>(currentFocusedNode);
495            if (focusedInput->inputType() == RADIO && focusedInput->form() == form() &&
496                focusedInput->name() == name())
497                return false;
498        }
499
500        // Allow keyboard focus if we're checked or if nothing in the group is checked.
501        return checked() || !checkedRadioButtons(this).checkedButtonForGroup(name());
502    }
503
504    return true;
505}
506
507bool HTMLInputElement::isMouseFocusable() const
508{
509    if (isTextField())
510        return HTMLFormControlElementWithState::isFocusable();
511    return HTMLFormControlElementWithState::isMouseFocusable();
512}
513
514void HTMLInputElement::updateFocusAppearance(bool restorePreviousSelection)
515{
516    if (isTextField())
517        InputElement::updateFocusAppearance(m_data, this, this, restorePreviousSelection);
518    else
519        HTMLFormControlElementWithState::updateFocusAppearance(restorePreviousSelection);
520}
521
522void HTMLInputElement::aboutToUnload()
523{
524    InputElement::aboutToUnload(this, this);
525}
526
527bool HTMLInputElement::shouldUseInputMethod() const
528{
529    return m_type == TEXT || m_type == SEARCH || m_type == ISINDEX;
530}
531
532void HTMLInputElement::handleFocusEvent()
533{
534    InputElement::dispatchFocusEvent(this, this);
535
536    if (isTextField())
537        m_autofilled = false;
538}
539
540void HTMLInputElement::handleBlurEvent()
541{
542    InputElement::dispatchBlurEvent(this, this);
543}
544
545void HTMLInputElement::setType(const String& t)
546{
547    if (t.isEmpty()) {
548        int exccode;
549        removeAttribute(typeAttr, exccode);
550    } else
551        setAttribute(typeAttr, t);
552}
553
554typedef HashMap<String, HTMLInputElement::InputType, CaseFoldingHash> InputTypeMap;
555static const InputTypeMap* createTypeMap()
556{
557    InputTypeMap* map = new InputTypeMap;
558    map->add("button", HTMLInputElement::BUTTON);
559    map->add("checkbox", HTMLInputElement::CHECKBOX);
560    map->add("color", HTMLInputElement::COLOR);
561    map->add("date", HTMLInputElement::DATE);
562    map->add("datetime", HTMLInputElement::DATETIME);
563    map->add("datetime-local", HTMLInputElement::DATETIMELOCAL);
564    map->add("email", HTMLInputElement::EMAIL);
565    map->add("file", HTMLInputElement::FILE);
566    map->add("hidden", HTMLInputElement::HIDDEN);
567    map->add("image", HTMLInputElement::IMAGE);
568    map->add("khtml_isindex", HTMLInputElement::ISINDEX);
569    map->add("month", HTMLInputElement::MONTH);
570    map->add("number", HTMLInputElement::NUMBER);
571    map->add("password", HTMLInputElement::PASSWORD);
572    map->add("radio", HTMLInputElement::RADIO);
573    map->add("range", HTMLInputElement::RANGE);
574    map->add("reset", HTMLInputElement::RESET);
575    map->add("search", HTMLInputElement::SEARCH);
576    map->add("submit", HTMLInputElement::SUBMIT);
577    map->add("tel", HTMLInputElement::TELEPHONE);
578    map->add("time", HTMLInputElement::TIME);
579    map->add("url", HTMLInputElement::URL);
580    map->add("week", HTMLInputElement::WEEK);
581    // No need to register "text" because it is the default type.
582    return map;
583}
584
585void HTMLInputElement::setInputType(const String& t)
586{
587    static const InputTypeMap* typeMap = createTypeMap();
588    InputType newType = t.isNull() ? TEXT : typeMap->get(t);
589#ifdef ANDROID_ACCEPT_CHANGES_TO_FOCUSED_TEXTFIELDS
590    if (newType == PASSWORD && document()->focusedNode() == this)
591        android::WebViewCore::getWebViewCore(document()->view())->updateTextfield(this, true, String());
592#endif
593
594    // IMPORTANT: Don't allow the type to be changed to FILE after the first
595    // type change, otherwise a JavaScript programmer would be able to set a text
596    // field's value to something like /etc/passwd and then change it to a file field.
597    if (inputType() != newType) {
598        if (newType == FILE && m_haveType)
599            // Set the attribute back to the old value.
600            // Useful in case we were called from inside parseMappedAttribute.
601            setAttribute(typeAttr, type());
602        else {
603            checkedRadioButtons(this).removeButton(this);
604
605            if (newType == FILE && !m_fileList)
606                m_fileList = FileList::create();
607
608            bool wasAttached = attached();
609            if (wasAttached)
610                detach();
611
612            bool didStoreValue = storesValueSeparateFromAttribute();
613            bool wasPasswordField = inputType() == PASSWORD;
614            bool didRespectHeightAndWidth = respectHeightAndWidthAttrs();
615            m_type = newType;
616            bool willStoreValue = storesValueSeparateFromAttribute();
617            bool isPasswordField = inputType() == PASSWORD;
618            bool willRespectHeightAndWidth = respectHeightAndWidthAttrs();
619
620            if (didStoreValue && !willStoreValue && !m_data.value().isNull()) {
621                setAttribute(valueAttr, m_data.value());
622                m_data.setValue(String());
623            }
624            if (!didStoreValue && willStoreValue)
625                m_data.setValue(sanitizeValue(getAttribute(valueAttr)));
626            else
627                InputElement::updateValueIfNeeded(m_data, this);
628
629            if (wasPasswordField && !isPasswordField)
630                unregisterForActivationCallbackIfNeeded();
631            else if (!wasPasswordField && isPasswordField)
632                registerForActivationCallbackIfNeeded();
633
634            if (didRespectHeightAndWidth != willRespectHeightAndWidth) {
635                NamedMappedAttrMap* map = mappedAttributes();
636                ASSERT(map);
637                if (Attribute* height = map->getAttributeItem(heightAttr))
638                    attributeChanged(height, false);
639                if (Attribute* width = map->getAttributeItem(widthAttr))
640                    attributeChanged(width, false);
641                if (Attribute* align = map->getAttributeItem(alignAttr))
642                    attributeChanged(align, false);
643            }
644
645            if (wasAttached) {
646                attach();
647                if (document()->focusedNode() == this)
648                    updateFocusAppearance(true);
649            }
650
651            checkedRadioButtons(this).addButton(this);
652        }
653
654        InputElement::notifyFormStateChanged(this);
655        updateValidity();
656    }
657    m_haveType = true;
658
659    if (inputType() != IMAGE && m_imageLoader)
660        m_imageLoader.clear();
661}
662
663static const AtomicString* createFormControlTypes()
664{
665    AtomicString* types = new AtomicString[HTMLInputElement::numberOfTypes];
666    // The values must be lowercased because they will be the return values of
667    //  input.type and it must be lowercase according to DOM Level 2.
668    types[HTMLInputElement::BUTTON] = "button";
669    types[HTMLInputElement::CHECKBOX] = "checkbox";
670    types[HTMLInputElement::COLOR] = "color";
671    types[HTMLInputElement::DATE] = "date";
672    types[HTMLInputElement::DATETIME] = "datetime";
673    types[HTMLInputElement::DATETIMELOCAL] = "datetime-local";
674    types[HTMLInputElement::EMAIL] = "email";
675    types[HTMLInputElement::FILE] = "file";
676    types[HTMLInputElement::HIDDEN] = "hidden";
677    types[HTMLInputElement::IMAGE] = "image";
678    types[HTMLInputElement::ISINDEX] = emptyAtom;
679    types[HTMLInputElement::MONTH] = "month";
680    types[HTMLInputElement::NUMBER] = "number";
681    types[HTMLInputElement::PASSWORD] = "password";
682    types[HTMLInputElement::RADIO] = "radio";
683    types[HTMLInputElement::RANGE] = "range";
684    types[HTMLInputElement::RESET] = "reset";
685    types[HTMLInputElement::SEARCH] = "search";
686    types[HTMLInputElement::SUBMIT] = "submit";
687    types[HTMLInputElement::TELEPHONE] = "tel";
688    types[HTMLInputElement::TEXT] = "text";
689    types[HTMLInputElement::TIME] = "time";
690    types[HTMLInputElement::URL] = "url";
691    types[HTMLInputElement::WEEK] = "week";
692    return types;
693}
694
695const AtomicString& HTMLInputElement::formControlType() const
696{
697    static const AtomicString* formControlTypes = createFormControlTypes();
698    return formControlTypes[inputType()];
699}
700
701bool HTMLInputElement::saveFormControlState(String& result) const
702{
703    if (!autoComplete())
704        return false;
705
706    switch (inputType()) {
707        case BUTTON:
708        case COLOR:
709        case DATE:
710        case DATETIME:
711        case DATETIMELOCAL:
712        case EMAIL:
713        case FILE:
714        case HIDDEN:
715        case IMAGE:
716        case ISINDEX:
717        case MONTH:
718        case NUMBER:
719        case RANGE:
720        case RESET:
721        case SEARCH:
722        case SUBMIT:
723        case TELEPHONE:
724        case TEXT:
725        case TIME:
726        case URL:
727        case WEEK:
728            result = value();
729            return true;
730        case CHECKBOX:
731        case RADIO:
732            result = checked() ? "on" : "off";
733            return true;
734        case PASSWORD:
735            return false;
736    }
737    ASSERT_NOT_REACHED();
738    return false;
739}
740
741void HTMLInputElement::restoreFormControlState(const String& state)
742{
743    ASSERT(inputType() != PASSWORD); // should never save/restore password fields
744    switch (inputType()) {
745        case BUTTON:
746        case COLOR:
747        case DATE:
748        case DATETIME:
749        case DATETIMELOCAL:
750        case EMAIL:
751        case FILE:
752        case HIDDEN:
753        case IMAGE:
754        case ISINDEX:
755        case MONTH:
756        case NUMBER:
757        case RANGE:
758        case RESET:
759        case SEARCH:
760        case SUBMIT:
761        case TELEPHONE:
762        case TEXT:
763        case TIME:
764        case URL:
765        case WEEK:
766            setValue(state);
767            break;
768        case CHECKBOX:
769        case RADIO:
770            setChecked(state == "on");
771            break;
772        case PASSWORD:
773            break;
774    }
775}
776
777bool HTMLInputElement::canStartSelection() const
778{
779    if (!isTextField())
780        return false;
781    return HTMLFormControlElementWithState::canStartSelection();
782}
783
784bool HTMLInputElement::canHaveSelection() const
785{
786    return isTextField();
787}
788
789void HTMLInputElement::accessKeyAction(bool sendToAnyElement)
790{
791    switch (inputType()) {
792        case BUTTON:
793        case CHECKBOX:
794        case FILE:
795        case IMAGE:
796        case RADIO:
797        case RANGE:
798        case RESET:
799        case SUBMIT:
800            focus(false);
801            // send the mouse button events iff the caller specified sendToAnyElement
802            dispatchSimulatedClick(0, sendToAnyElement);
803            break;
804        case HIDDEN:
805            // a no-op for this type
806            break;
807        case COLOR:
808        case DATE:
809        case DATETIME:
810        case DATETIMELOCAL:
811        case EMAIL:
812        case ISINDEX:
813        case MONTH:
814        case NUMBER:
815        case PASSWORD:
816        case SEARCH:
817        case TELEPHONE:
818        case TEXT:
819        case TIME:
820        case URL:
821        case WEEK:
822            // should never restore previous selection here
823            focus(false);
824            break;
825    }
826}
827
828bool HTMLInputElement::mapToEntry(const QualifiedName& attrName, MappedAttributeEntry& result) const
829{
830    if (((attrName == heightAttr || attrName == widthAttr) && respectHeightAndWidthAttrs()) ||
831        attrName == vspaceAttr ||
832        attrName == hspaceAttr) {
833        result = eUniversal;
834        return false;
835    }
836
837    if (attrName == alignAttr) {
838        if (inputType() == IMAGE) {
839            // Share with <img> since the alignment behavior is the same.
840            result = eReplaced;
841            return false;
842        }
843    }
844
845    return HTMLElement::mapToEntry(attrName, result);
846}
847
848void HTMLInputElement::parseMappedAttribute(MappedAttribute *attr)
849{
850    if (attr->name() == nameAttr) {
851        checkedRadioButtons(this).removeButton(this);
852        m_data.setName(attr->value());
853        checkedRadioButtons(this).addButton(this);
854        HTMLFormControlElementWithState::parseMappedAttribute(attr);
855    } else if (attr->name() == autocompleteAttr) {
856        if (equalIgnoringCase(attr->value(), "off")) {
857            m_autocomplete = Off;
858            registerForActivationCallbackIfNeeded();
859        } else {
860            bool needsToUnregister = m_autocomplete == Off;
861
862            if (attr->isEmpty())
863                m_autocomplete = Uninitialized;
864            else
865                m_autocomplete = On;
866
867            if (needsToUnregister)
868                unregisterForActivationCallbackIfNeeded();
869        }
870    } else if (attr->name() == typeAttr) {
871        setInputType(attr->value());
872    } else if (attr->name() == valueAttr) {
873        // We only need to setChanged if the form is looking at the default value right now.
874        if (m_data.value().isNull())
875            setNeedsStyleRecalc();
876        setFormControlValueMatchesRenderer(false);
877        updateValidity();
878    } else if (attr->name() == checkedAttr) {
879        m_defaultChecked = !attr->isNull();
880        if (m_useDefaultChecked) {
881            setChecked(m_defaultChecked);
882            m_useDefaultChecked = true;
883        }
884        updateValidity();
885    } else if (attr->name() == maxlengthAttr)
886        InputElement::parseMaxLengthAttribute(m_data, this, this, attr);
887    else if (attr->name() == sizeAttr)
888        InputElement::parseSizeAttribute(m_data, this, attr);
889    else if (attr->name() == altAttr) {
890        if (renderer() && inputType() == IMAGE)
891            toRenderImage(renderer())->updateAltText();
892    } else if (attr->name() == srcAttr) {
893        if (renderer() && inputType() == IMAGE) {
894            if (!m_imageLoader)
895                m_imageLoader.set(new HTMLImageLoader(this));
896            m_imageLoader->updateFromElementIgnoringPreviousError();
897        }
898    } else if (attr->name() == usemapAttr ||
899               attr->name() == accesskeyAttr) {
900        // FIXME: ignore for the moment
901    } else if (attr->name() == vspaceAttr) {
902        addCSSLength(attr, CSSPropertyMarginTop, attr->value());
903        addCSSLength(attr, CSSPropertyMarginBottom, attr->value());
904    } else if (attr->name() == hspaceAttr) {
905        addCSSLength(attr, CSSPropertyMarginLeft, attr->value());
906        addCSSLength(attr, CSSPropertyMarginRight, attr->value());
907    } else if (attr->name() == alignAttr) {
908        if (inputType() == IMAGE)
909            addHTMLAlignment(attr);
910    } else if (attr->name() == widthAttr) {
911        if (respectHeightAndWidthAttrs())
912            addCSSLength(attr, CSSPropertyWidth, attr->value());
913    } else if (attr->name() == heightAttr) {
914        if (respectHeightAndWidthAttrs())
915            addCSSLength(attr, CSSPropertyHeight, attr->value());
916    }
917    // Search field and slider attributes all just cause updateFromElement to be called through style
918    // recalcing.
919    else if (attr->name() == onsearchAttr) {
920        setAttributeEventListener(eventNames().searchEvent, createAttributeEventListener(this, attr));
921    } else if (attr->name() == resultsAttr) {
922        int oldResults = m_maxResults;
923        m_maxResults = !attr->isNull() ? std::min(attr->value().toInt(), maxSavedResults) : -1;
924        // FIXME: Detaching just for maxResults change is not ideal.  We should figure out the right
925        // time to relayout for this change.
926        if (m_maxResults != oldResults && (m_maxResults <= 0 || oldResults <= 0) && attached()) {
927            detach();
928            attach();
929        }
930        setNeedsStyleRecalc();
931    } else if (attr->name() == autosaveAttr ||
932             attr->name() == incrementalAttr ||
933             attr->name() == minAttr ||
934             attr->name() == maxAttr ||
935             attr->name() == multipleAttr ||
936             attr->name() == precisionAttr)
937        setNeedsStyleRecalc();
938    else if (attr->name() == patternAttr)
939        updateValidity();
940#if ENABLE(DATALIST)
941    else if (attr->name() == listAttr)
942        m_hasNonEmptyList = !attr->isEmpty();
943        // FIXME: we need to tell this change to a renderer if the attribute affects the appearance.
944#endif
945    else
946        HTMLTextFormControlElement::parseMappedAttribute(attr);
947}
948
949bool HTMLInputElement::rendererIsNeeded(RenderStyle *style)
950{
951    if (inputType() == HIDDEN)
952        return false;
953    return HTMLFormControlElementWithState::rendererIsNeeded(style);
954}
955
956RenderObject *HTMLInputElement::createRenderer(RenderArena *arena, RenderStyle *style)
957{
958    switch (inputType()) {
959        case BUTTON:
960        case RESET:
961        case SUBMIT:
962            return new (arena) RenderButton(this);
963        case CHECKBOX:
964        case RADIO:
965            return RenderObject::createObject(this, style);
966        case FILE:
967            return new (arena) RenderFileUploadControl(this);
968        case HIDDEN:
969            break;
970        case IMAGE:
971            return new (arena) RenderImage(this);
972        case RANGE:
973            return new (arena) RenderSlider(this);
974        case COLOR:
975        case DATE:
976        case DATETIME:
977        case DATETIMELOCAL:
978        case EMAIL:
979        case ISINDEX:
980        case MONTH:
981        case NUMBER:
982        case PASSWORD:
983        case SEARCH:
984        case TELEPHONE:
985        case TEXT:
986        case TIME:
987        case URL:
988        case WEEK:
989            return new (arena) RenderTextControlSingleLine(this, placeholderShouldBeVisible());
990    }
991    ASSERT(false);
992    return 0;
993}
994
995void HTMLInputElement::attach()
996{
997    if (!m_inited) {
998        if (!m_haveType)
999            setInputType(getAttribute(typeAttr));
1000        m_inited = true;
1001    }
1002
1003    HTMLFormControlElementWithState::attach();
1004
1005    if (inputType() == IMAGE) {
1006        if (!m_imageLoader)
1007            m_imageLoader.set(new HTMLImageLoader(this));
1008        m_imageLoader->updateFromElement();
1009        if (renderer() && m_imageLoader->haveFiredBeforeLoadEvent()) {
1010            RenderImage* imageObj = toRenderImage(renderer());
1011            imageObj->setCachedImage(m_imageLoader->image());
1012
1013            // If we have no image at all because we have no src attribute, set
1014            // image height and width for the alt text instead.
1015            if (!m_imageLoader->image() && !imageObj->cachedImage())
1016                imageObj->setImageSizeForAltText();
1017        }
1018    }
1019}
1020
1021void HTMLInputElement::detach()
1022{
1023    HTMLFormControlElementWithState::detach();
1024    setFormControlValueMatchesRenderer(false);
1025}
1026
1027String HTMLInputElement::altText() const
1028{
1029    // http://www.w3.org/TR/1998/REC-html40-19980424/appendix/notes.html#altgen
1030    // also heavily discussed by Hixie on bugzilla
1031    // note this is intentionally different to HTMLImageElement::altText()
1032    String alt = getAttribute(altAttr);
1033    // fall back to title attribute
1034    if (alt.isNull())
1035        alt = getAttribute(titleAttr);
1036    if (alt.isNull())
1037        alt = getAttribute(valueAttr);
1038    if (alt.isEmpty())
1039        alt = inputElementAltText();
1040    return alt;
1041}
1042
1043bool HTMLInputElement::isSuccessfulSubmitButton() const
1044{
1045    // HTML spec says that buttons must have names to be considered successful.
1046    // However, other browsers do not impose this constraint. So we do likewise.
1047    return !disabled() && (inputType() == IMAGE || inputType() == SUBMIT);
1048}
1049
1050bool HTMLInputElement::isActivatedSubmit() const
1051{
1052    return m_activeSubmit;
1053}
1054
1055void HTMLInputElement::setActivatedSubmit(bool flag)
1056{
1057    m_activeSubmit = flag;
1058}
1059
1060bool HTMLInputElement::appendFormData(FormDataList& encoding, bool multipart)
1061{
1062    // image generates its own names, but for other types there is no form data unless there's a name
1063    if (name().isEmpty() && inputType() != IMAGE)
1064        return false;
1065
1066    switch (inputType()) {
1067        case COLOR:
1068        case DATE:
1069        case DATETIME:
1070        case DATETIMELOCAL:
1071        case EMAIL:
1072        case HIDDEN:
1073        case ISINDEX:
1074        case MONTH:
1075        case NUMBER:
1076        case PASSWORD:
1077        case RANGE:
1078        case SEARCH:
1079        case TELEPHONE:
1080        case TEXT:
1081        case TIME:
1082        case URL:
1083        case WEEK:
1084            // always successful
1085            encoding.appendData(name(), value());
1086            return true;
1087
1088        case CHECKBOX:
1089        case RADIO:
1090            if (checked()) {
1091                encoding.appendData(name(), value());
1092                return true;
1093            }
1094            break;
1095
1096        case BUTTON:
1097        case RESET:
1098            // these types of buttons are never successful
1099            return false;
1100
1101        case IMAGE:
1102            if (m_activeSubmit) {
1103                encoding.appendData(name().isEmpty() ? "x" : (name() + ".x"), m_xPos);
1104                encoding.appendData(name().isEmpty() ? "y" : (name() + ".y"), m_yPos);
1105                if (!name().isEmpty() && !value().isEmpty())
1106                    encoding.appendData(name(), value());
1107                return true;
1108            }
1109            break;
1110
1111        case SUBMIT:
1112            if (m_activeSubmit) {
1113                String enc_str = valueWithDefault();
1114                encoding.appendData(name(), enc_str);
1115                return true;
1116            }
1117            break;
1118
1119        case FILE: {
1120            unsigned numFiles = m_fileList->length();
1121            if (!multipart) {
1122                // Send only the basenames.
1123                // 4.10.16.4 and 4.10.16.6 sections in HTML5.
1124
1125                // Unlike the multipart case, we have no special
1126                // handling for the empty fileList because Netscape
1127                // doesn't support for non-multipart submission of
1128                // file inputs, and Firefox doesn't add "name=" query
1129                // parameter.
1130
1131                for (unsigned i = 0; i < numFiles; ++i) {
1132                    encoding.appendData(name(), m_fileList->item(i)->fileName());
1133                }
1134                return true;
1135            }
1136
1137            // If no filename at all is entered, return successful but empty.
1138            // Null would be more logical, but Netscape posts an empty file. Argh.
1139            if (!numFiles) {
1140                encoding.appendFile(name(), File::create(""));
1141                return true;
1142            }
1143
1144            for (unsigned i = 0; i < numFiles; ++i)
1145                encoding.appendFile(name(), m_fileList->item(i));
1146            return true;
1147        }
1148    }
1149    return false;
1150}
1151
1152void HTMLInputElement::reset()
1153{
1154    if (storesValueSeparateFromAttribute())
1155        setValue(String());
1156
1157    setChecked(m_defaultChecked);
1158    m_useDefaultChecked = true;
1159}
1160
1161bool HTMLInputElement::isTextField() const
1162{
1163    switch (inputType()) {
1164    case COLOR:
1165    case DATE:
1166    case DATETIME:
1167    case DATETIMELOCAL:
1168    case EMAIL:
1169    case ISINDEX:
1170    case MONTH:
1171    case NUMBER:
1172    case PASSWORD:
1173    case SEARCH:
1174    case TELEPHONE:
1175    case TEXT:
1176    case TIME:
1177    case URL:
1178    case WEEK:
1179        return true;
1180    case BUTTON:
1181    case CHECKBOX:
1182    case FILE:
1183    case HIDDEN:
1184    case IMAGE:
1185    case RADIO:
1186    case RANGE:
1187    case RESET:
1188    case SUBMIT:
1189        return false;
1190    }
1191    ASSERT_NOT_REACHED();
1192    return false;
1193}
1194
1195void HTMLInputElement::setChecked(bool nowChecked, bool sendChangeEvent)
1196{
1197    if (checked() == nowChecked)
1198        return;
1199
1200    checkedRadioButtons(this).removeButton(this);
1201
1202    m_useDefaultChecked = false;
1203    m_checked = nowChecked;
1204    setNeedsStyleRecalc();
1205
1206    checkedRadioButtons(this).addButton(this);
1207
1208    if (renderer() && renderer()->style()->hasAppearance())
1209        renderer()->theme()->stateChanged(renderer(), CheckedState);
1210
1211    // Ideally we'd do this from the render tree (matching
1212    // RenderTextView), but it's not possible to do it at the moment
1213    // because of the way the code is structured.
1214    if (renderer() && AXObjectCache::accessibilityEnabled())
1215        renderer()->document()->axObjectCache()->postNotification(renderer(), AXObjectCache::AXCheckedStateChanged, true);
1216
1217    // Only send a change event for items in the document (avoid firing during
1218    // parsing) and don't send a change event for a radio button that's getting
1219    // unchecked to match other browsers. DOM is not a useful standard for this
1220    // because it says only to fire change events at "lose focus" time, which is
1221    // definitely wrong in practice for these types of elements.
1222    if (sendChangeEvent && inDocument() && (inputType() != RADIO || nowChecked))
1223        dispatchFormControlChangeEvent();
1224}
1225
1226void HTMLInputElement::setIndeterminate(bool _indeterminate)
1227{
1228    // Only checkboxes honor indeterminate.
1229    if (inputType() != CHECKBOX || indeterminate() == _indeterminate)
1230        return;
1231
1232    m_indeterminate = _indeterminate;
1233
1234    setNeedsStyleRecalc();
1235
1236    if (renderer() && renderer()->style()->hasAppearance())
1237        renderer()->theme()->stateChanged(renderer(), CheckedState);
1238}
1239
1240int HTMLInputElement::size() const
1241{
1242    return m_data.size();
1243}
1244
1245void HTMLInputElement::copyNonAttributeProperties(const Element* source)
1246{
1247    const HTMLInputElement* sourceElement = static_cast<const HTMLInputElement*>(source);
1248
1249    m_data.setValue(sourceElement->m_data.value());
1250    m_checked = sourceElement->m_checked;
1251    m_indeterminate = sourceElement->m_indeterminate;
1252
1253    HTMLFormControlElementWithState::copyNonAttributeProperties(source);
1254}
1255
1256String HTMLInputElement::value() const
1257{
1258    // The HTML5 spec (as of the 10/24/08 working draft) says that the value attribute isn't applicable to the file upload control
1259    // but we don't want to break existing websites, who may be relying on being able to get the file name as a value.
1260    if (inputType() == FILE) {
1261        if (!m_fileList->isEmpty())
1262            return m_fileList->item(0)->fileName();
1263        return String();
1264    }
1265
1266    String value = m_data.value();
1267    if (value.isNull()) {
1268        value = sanitizeValue(getAttribute(valueAttr));
1269
1270        // If no attribute exists, then just use "on" or "" based off the checked() state of the control.
1271        if (value.isNull() && (inputType() == CHECKBOX || inputType() == RADIO))
1272            return checked() ? "on" : "";
1273    }
1274
1275    return value;
1276}
1277
1278String HTMLInputElement::valueWithDefault() const
1279{
1280    String v = value();
1281    if (v.isNull()) {
1282        switch (inputType()) {
1283            case BUTTON:
1284            case CHECKBOX:
1285            case COLOR:
1286            case DATE:
1287            case DATETIME:
1288            case DATETIMELOCAL:
1289            case EMAIL:
1290            case FILE:
1291            case HIDDEN:
1292            case IMAGE:
1293            case ISINDEX:
1294            case MONTH:
1295            case NUMBER:
1296            case PASSWORD:
1297            case RADIO:
1298            case RANGE:
1299            case SEARCH:
1300            case TELEPHONE:
1301            case TEXT:
1302            case TIME:
1303            case URL:
1304            case WEEK:
1305                break;
1306            case RESET:
1307                v = resetButtonDefaultLabel();
1308                break;
1309            case SUBMIT:
1310                v = submitButtonDefaultLabel();
1311                break;
1312        }
1313    }
1314    return v;
1315}
1316
1317void HTMLInputElement::setValueForUser(const String& value)
1318{
1319    // Call setValue and make it send a change event.
1320    setValue(value, true);
1321}
1322
1323void HTMLInputElement::setValue(const String& value, bool sendChangeEvent)
1324{
1325    // For security reasons, we don't allow setting the filename, but we do allow clearing it.
1326    // The HTML5 spec (as of the 10/24/08 working draft) says that the value attribute isn't applicable to the file upload control
1327    // but we don't want to break existing websites, who may be relying on this method to clear things.
1328    if (inputType() == FILE && !value.isEmpty())
1329        return;
1330
1331    setFormControlValueMatchesRenderer(false);
1332    if (storesValueSeparateFromAttribute()) {
1333        if (inputType() == FILE)
1334            m_fileList->clear();
1335        else {
1336            m_data.setValue(sanitizeValue(value));
1337            if (isTextField()) {
1338                updatePlaceholderVisibility(false);
1339                if (inDocument())
1340                    document()->updateStyleIfNeeded();
1341            }
1342        }
1343        if (renderer())
1344            renderer()->updateFromElement();
1345        setNeedsStyleRecalc();
1346    } else
1347        setAttribute(valueAttr, sanitizeValue(value));
1348
1349    if (isTextField()) {
1350        unsigned max = m_data.value().length();
1351#ifdef ANDROID_ACCEPT_CHANGES_TO_FOCUSED_TEXTFIELDS
1352        // Make sure our UI side textfield changes to match the RenderTextControl
1353        android::WebViewCore::getWebViewCore(document()->view())->updateTextfield(this, false, value);
1354#endif
1355        if (document()->focusedNode() == this)
1356            InputElement::updateSelectionRange(this, this, max, max);
1357        else
1358            cacheSelection(max, max);
1359    }
1360
1361    // Don't dispatch the change event when focused, it will be dispatched
1362    // when the control loses focus.
1363    if (sendChangeEvent && document()->focusedNode() != this)
1364        dispatchFormControlChangeEvent();
1365
1366    InputElement::notifyFormStateChanged(this);
1367    updateValidity();
1368}
1369
1370String HTMLInputElement::placeholder() const
1371{
1372    return getAttribute(placeholderAttr).string();
1373}
1374
1375void HTMLInputElement::setPlaceholder(const String& value)
1376{
1377    setAttribute(placeholderAttr, value);
1378}
1379
1380bool HTMLInputElement::searchEventsShouldBeDispatched() const
1381{
1382    return hasAttribute(incrementalAttr);
1383}
1384
1385void HTMLInputElement::setValueFromRenderer(const String& value)
1386{
1387    // File upload controls will always use setFileListFromRenderer.
1388    ASSERT(inputType() != FILE);
1389    updatePlaceholderVisibility(false);
1390    InputElement::setValueFromRenderer(m_data, this, this, value);
1391    updateValidity();
1392}
1393
1394void HTMLInputElement::setFileListFromRenderer(const Vector<String>& paths)
1395{
1396    m_fileList->clear();
1397    int size = paths.size();
1398    for (int i = 0; i < size; i++)
1399        m_fileList->append(File::create(paths[i]));
1400
1401    setFormControlValueMatchesRenderer(true);
1402    InputElement::notifyFormStateChanged(this);
1403    updateValidity();
1404}
1405
1406bool HTMLInputElement::storesValueSeparateFromAttribute() const
1407{
1408    switch (inputType()) {
1409        case BUTTON:
1410        case CHECKBOX:
1411        case HIDDEN:
1412        case IMAGE:
1413        case RADIO:
1414        case RESET:
1415        case SUBMIT:
1416            return false;
1417        case COLOR:
1418        case DATE:
1419        case DATETIME:
1420        case DATETIMELOCAL:
1421        case EMAIL:
1422        case FILE:
1423        case ISINDEX:
1424        case MONTH:
1425        case NUMBER:
1426        case PASSWORD:
1427        case RANGE:
1428        case SEARCH:
1429        case TELEPHONE:
1430        case TEXT:
1431        case TIME:
1432        case URL:
1433        case WEEK:
1434            return true;
1435    }
1436    return false;
1437}
1438
1439void* HTMLInputElement::preDispatchEventHandler(Event *evt)
1440{
1441    // preventDefault or "return false" are used to reverse the automatic checking/selection we do here.
1442    // This result gives us enough info to perform the "undo" in postDispatch of the action we take here.
1443    void* result = 0;
1444    if ((inputType() == CHECKBOX || inputType() == RADIO) && evt->isMouseEvent()
1445            && evt->type() == eventNames().clickEvent && static_cast<MouseEvent*>(evt)->button() == LeftButton) {
1446        if (inputType() == CHECKBOX) {
1447            // As a way to store the state, we return 0 if we were unchecked, 1 if we were checked, and 2 for
1448            // indeterminate.
1449            if (indeterminate()) {
1450                result = (void*)0x2;
1451                setIndeterminate(false);
1452            } else {
1453                if (checked())
1454                    result = (void*)0x1;
1455                setChecked(!checked(), true);
1456            }
1457        } else {
1458            // For radio buttons, store the current selected radio object.
1459            // We really want radio groups to end up in sane states, i.e., to have something checked.
1460            // Therefore if nothing is currently selected, we won't allow this action to be "undone", since
1461            // we want some object in the radio group to actually get selected.
1462            HTMLInputElement* currRadio = checkedRadioButtons(this).checkedButtonForGroup(name());
1463            if (currRadio) {
1464                // We have a radio button selected that is not us.  Cache it in our result field and ref it so
1465                // that it can't be destroyed.
1466                currRadio->ref();
1467                result = currRadio;
1468            }
1469            setChecked(true, true);
1470        }
1471    }
1472    return result;
1473}
1474
1475void HTMLInputElement::postDispatchEventHandler(Event *evt, void* data)
1476{
1477    if ((inputType() == CHECKBOX || inputType() == RADIO) && evt->isMouseEvent()
1478            && evt->type() == eventNames().clickEvent && static_cast<MouseEvent*>(evt)->button() == LeftButton) {
1479        if (inputType() == CHECKBOX) {
1480            // Reverse the checking we did in preDispatch.
1481            if (evt->defaultPrevented() || evt->defaultHandled()) {
1482                if (data == (void*)0x2)
1483                    setIndeterminate(true);
1484                else
1485                    setChecked(data);
1486            }
1487        } else if (data) {
1488            HTMLInputElement* input = static_cast<HTMLInputElement*>(data);
1489            if (evt->defaultPrevented() || evt->defaultHandled()) {
1490                // Restore the original selected radio button if possible.
1491                // Make sure it is still a radio button and only do the restoration if it still
1492                // belongs to our group.
1493
1494                if (input->form() == form() && input->inputType() == RADIO && input->name() == name()) {
1495                    // Ok, the old radio button is still in our form and in our group and is still a
1496                    // radio button, so it's safe to restore selection to it.
1497                    input->setChecked(true);
1498                }
1499            }
1500            input->deref();
1501        }
1502
1503        // Left clicks on radio buttons and check boxes already performed default actions in preDispatchEventHandler().
1504        evt->setDefaultHandled();
1505    }
1506}
1507
1508void HTMLInputElement::defaultEventHandler(Event* evt)
1509{
1510    // FIXME: It would be better to refactor this for the different types of input element.
1511    // Having them all in one giant function makes this hard to read, and almost all the handling is type-specific.
1512
1513    bool clickDefaultFormButton = false;
1514
1515    if (isTextField() && evt->type() == eventNames().textInputEvent && evt->isTextEvent() && static_cast<TextEvent*>(evt)->data() == "\n")
1516        clickDefaultFormButton = true;
1517
1518    if (inputType() == IMAGE && evt->isMouseEvent() && evt->type() == eventNames().clickEvent) {
1519        // record the mouse position for when we get the DOMActivate event
1520        MouseEvent* me = static_cast<MouseEvent*>(evt);
1521        // FIXME: We could just call offsetX() and offsetY() on the event,
1522        // but that's currently broken, so for now do the computation here.
1523        if (me->isSimulated() || !renderer()) {
1524            m_xPos = 0;
1525            m_yPos = 0;
1526        } else {
1527            // FIXME: This doesn't work correctly with transforms.
1528            // FIXME: pageX/pageY need adjusting for pageZoomFactor(). Use actualPageLocation()?
1529            IntPoint absOffset = roundedIntPoint(renderer()->localToAbsolute());
1530            m_xPos = me->pageX() - absOffset.x();
1531            m_yPos = me->pageY() - absOffset.y();
1532        }
1533    }
1534
1535    if (isTextField()
1536            && evt->type() == eventNames().keydownEvent
1537            && evt->isKeyboardEvent()
1538            && focused()
1539            && document()->frame()
1540            && document()->frame()->doTextFieldCommandFromEvent(this, static_cast<KeyboardEvent*>(evt))) {
1541        evt->setDefaultHandled();
1542        return;
1543    }
1544
1545    if (inputType() == RADIO
1546            && evt->isMouseEvent()
1547            && evt->type() == eventNames().clickEvent
1548            && static_cast<MouseEvent*>(evt)->button() == LeftButton) {
1549        evt->setDefaultHandled();
1550        return;
1551    }
1552
1553    // Call the base event handler before any of our own event handling for almost all events in text fields.
1554    // Makes editing keyboard handling take precedence over the keydown and keypress handling in this function.
1555    bool callBaseClassEarly = isTextField() && !clickDefaultFormButton
1556        && (evt->type() == eventNames().keydownEvent || evt->type() == eventNames().keypressEvent);
1557    if (callBaseClassEarly) {
1558        HTMLFormControlElementWithState::defaultEventHandler(evt);
1559        if (evt->defaultHandled())
1560            return;
1561    }
1562
1563    // DOMActivate events cause the input to be "activated" - in the case of image and submit inputs, this means
1564    // actually submitting the form. For reset inputs, the form is reset. These events are sent when the user clicks
1565    // on the element, or presses enter while it is the active element. JavaScript code wishing to activate the element
1566    // must dispatch a DOMActivate event - a click event will not do the job.
1567    if (evt->type() == eventNames().DOMActivateEvent && !disabled()) {
1568        if (inputType() == IMAGE || inputType() == SUBMIT || inputType() == RESET) {
1569            if (!form())
1570                return;
1571            if (inputType() == RESET)
1572                form()->reset();
1573            else {
1574                m_activeSubmit = true;
1575                // FIXME: Would be cleaner to get m_xPos and m_yPos out of the underlying mouse
1576                // event (if any) here instead of relying on the variables set above when
1577                // processing the click event. Even better, appendFormData could pass the
1578                // event in, and then we could get rid of m_xPos and m_yPos altogether!
1579                if (!form()->prepareSubmit(evt)) {
1580                    m_xPos = 0;
1581                    m_yPos = 0;
1582                }
1583                m_activeSubmit = false;
1584            }
1585        } else if (inputType() == FILE && renderer())
1586            toRenderFileUploadControl(renderer())->click();
1587    }
1588
1589    // Use key press event here since sending simulated mouse events
1590    // on key down blocks the proper sending of the key press event.
1591    if (evt->type() == eventNames().keypressEvent && evt->isKeyboardEvent()) {
1592        bool clickElement = false;
1593
1594        int charCode = static_cast<KeyboardEvent*>(evt)->charCode();
1595
1596        if (charCode == '\r') {
1597            switch (inputType()) {
1598                case CHECKBOX:
1599                case COLOR:
1600                case DATE:
1601                case DATETIME:
1602                case DATETIMELOCAL:
1603                case EMAIL:
1604                case HIDDEN:
1605                case ISINDEX:
1606                case MONTH:
1607                case NUMBER:
1608                case PASSWORD:
1609                case RANGE:
1610                case SEARCH:
1611                case TELEPHONE:
1612                case TEXT:
1613                case TIME:
1614                case URL:
1615                case WEEK:
1616                    // Simulate mouse click on the default form button for enter for these types of elements.
1617                    clickDefaultFormButton = true;
1618                    break;
1619                case BUTTON:
1620                case FILE:
1621                case IMAGE:
1622                case RESET:
1623                case SUBMIT:
1624                    // Simulate mouse click for enter for these types of elements.
1625                    clickElement = true;
1626                    break;
1627                case RADIO:
1628                    break; // Don't do anything for enter on a radio button.
1629            }
1630        } else if (charCode == ' ') {
1631            switch (inputType()) {
1632                case BUTTON:
1633                case CHECKBOX:
1634                case FILE:
1635                case IMAGE:
1636                case RESET:
1637                case SUBMIT:
1638                case RADIO:
1639                    // Prevent scrolling down the page.
1640                    evt->setDefaultHandled();
1641                    return;
1642                default:
1643                    break;
1644            }
1645        }
1646
1647        if (clickElement) {
1648            dispatchSimulatedClick(evt);
1649            evt->setDefaultHandled();
1650            return;
1651        }
1652    }
1653
1654    if (evt->type() == eventNames().keydownEvent && evt->isKeyboardEvent()) {
1655        String key = static_cast<KeyboardEvent*>(evt)->keyIdentifier();
1656
1657        if (key == "U+0020") {
1658            switch (inputType()) {
1659                case BUTTON:
1660                case CHECKBOX:
1661                case FILE:
1662                case IMAGE:
1663                case RESET:
1664                case SUBMIT:
1665                case RADIO:
1666                    setActive(true, true);
1667                    // No setDefaultHandled(), because IE dispatches a keypress in this case
1668                    // and the caller will only dispatch a keypress if we don't call setDefaultHandled.
1669                    return;
1670                default:
1671                    break;
1672            }
1673        }
1674
1675// allow enter to change state of radio
1676        if (inputType() == RADIO && (key == "Up" || key == "Down" || key == "Left" || key == "Right")) {
1677            // Left and up mean "previous radio button".
1678            // Right and down mean "next radio button".
1679            // Tested in WinIE, and even for RTL, left still means previous radio button (and so moves
1680            // to the right).  Seems strange, but we'll match it.
1681            bool forward = (key == "Down" || key == "Right");
1682
1683            // We can only stay within the form's children if the form hasn't been demoted to a leaf because
1684            // of malformed HTML.
1685            Node* n = this;
1686            while ((n = (forward ? n->traverseNextNode() : n->traversePreviousNode()))) {
1687                // Once we encounter a form element, we know we're through.
1688                if (n->hasTagName(formTag))
1689                    break;
1690
1691                // Look for more radio buttons.
1692                if (n->hasTagName(inputTag)) {
1693                    HTMLInputElement* elt = static_cast<HTMLInputElement*>(n);
1694                    if (elt->form() != form())
1695                        break;
1696                    if (n->hasTagName(inputTag)) {
1697                        HTMLInputElement* inputElt = static_cast<HTMLInputElement*>(n);
1698                        if (inputElt->inputType() == RADIO && inputElt->name() == name() && inputElt->isFocusable()) {
1699                            inputElt->setChecked(true);
1700                            document()->setFocusedNode(inputElt);
1701                            inputElt->dispatchSimulatedClick(evt, false, false);
1702                            evt->setDefaultHandled();
1703                            break;
1704                        }
1705                    }
1706                }
1707            }
1708        }
1709    }
1710
1711    if (evt->type() == eventNames().keyupEvent && evt->isKeyboardEvent()) {
1712        bool clickElement = false;
1713
1714        String key = static_cast<KeyboardEvent*>(evt)->keyIdentifier();
1715
1716        if (key == "U+0020") {
1717            switch (inputType()) {
1718                case BUTTON:
1719                case CHECKBOX:
1720                case FILE:
1721                case IMAGE:
1722                case RESET:
1723                case SUBMIT:
1724                    // Simulate mouse click for spacebar for these types of elements.
1725                    // The AppKit already does this for some, but not all, of them.
1726                    clickElement = true;
1727                    break;
1728                case RADIO:
1729                    // If an unselected radio is tabbed into (because the entire group has nothing
1730                    // checked, or because of some explicit .focus() call), then allow space to check it.
1731                    if (!checked())
1732                        clickElement = true;
1733                    break;
1734                case COLOR:
1735                case DATE:
1736                case DATETIME:
1737                case DATETIMELOCAL:
1738                case EMAIL:
1739                case HIDDEN:
1740                case ISINDEX:
1741                case MONTH:
1742                case NUMBER:
1743                case PASSWORD:
1744                case RANGE:
1745                case SEARCH:
1746                case TELEPHONE:
1747                case TEXT:
1748                case TIME:
1749                case URL:
1750                case WEEK:
1751                    break;
1752            }
1753        }
1754
1755        if (clickElement) {
1756            if (active())
1757                dispatchSimulatedClick(evt);
1758            evt->setDefaultHandled();
1759            return;
1760        }
1761    }
1762
1763    if (clickDefaultFormButton) {
1764        if (isSearchField()) {
1765            addSearchResult();
1766            onSearch();
1767        }
1768        // Fire onChange for text fields.
1769        RenderObject* r = renderer();
1770        if (r && r->isTextField() && toRenderTextControl(r)->wasChangedSinceLastChangeEvent()) {
1771            dispatchFormControlChangeEvent();
1772            // Refetch the renderer since arbitrary JS code run during onchange can do anything, including destroying it.
1773            r = renderer();
1774            if (r && r->isTextField())
1775                toRenderTextControl(r)->setChangedSinceLastChangeEvent(false);
1776        }
1777
1778        RefPtr<HTMLFormElement> formForSubmission = form();
1779        // If there is no form and the element is an <isindex>, then create a temporary form just to be used for submission.
1780        if (!formForSubmission && inputType() == ISINDEX)
1781            formForSubmission = createTemporaryFormForIsIndex();
1782
1783        // Form may never have been present, or may have been destroyed by code responding to the change event.
1784        if (formForSubmission)
1785            formForSubmission->submitClick(evt);
1786
1787        evt->setDefaultHandled();
1788        return;
1789    }
1790
1791    if (evt->isBeforeTextInsertedEvent())
1792        InputElement::handleBeforeTextInsertedEvent(m_data, this, this, evt);
1793
1794    if (isTextField() && renderer() && (evt->isMouseEvent() || evt->isDragEvent() || evt->isWheelEvent() || evt->type() == eventNames().blurEvent || evt->type() == eventNames().focusEvent))
1795        toRenderTextControlSingleLine(renderer())->forwardEvent(evt);
1796
1797    if (inputType() == RANGE && renderer() && (evt->isMouseEvent() || evt->isDragEvent() || evt->isWheelEvent()))
1798        toRenderSlider(renderer())->forwardEvent(evt);
1799
1800    if (!callBaseClassEarly && !evt->defaultHandled())
1801        HTMLFormControlElementWithState::defaultEventHandler(evt);
1802}
1803
1804PassRefPtr<HTMLFormElement> HTMLInputElement::createTemporaryFormForIsIndex()
1805{
1806    RefPtr<HTMLFormElement> form = new HTMLFormElement(formTag, document());
1807    form->registerFormElement(this);
1808    form->setMethod("GET");
1809    if (!document()->baseURL().isEmpty()) {
1810        // We treat the href property of the <base> element as the form action, as per section 7.5
1811        // "Queries and Indexes" of the HTML 2.0 spec. <http://www.w3.org/MarkUp/html-spec/html-spec_7.html#SEC7.5>.
1812        form->setAction(document()->baseURL().string());
1813    }
1814    return form.release();
1815}
1816
1817bool HTMLInputElement::isURLAttribute(Attribute *attr) const
1818{
1819    return (attr->name() == srcAttr);
1820}
1821
1822String HTMLInputElement::defaultValue() const
1823{
1824    return getAttribute(valueAttr);
1825}
1826
1827void HTMLInputElement::setDefaultValue(const String &value)
1828{
1829    setAttribute(valueAttr, value);
1830}
1831
1832bool HTMLInputElement::defaultChecked() const
1833{
1834    return !getAttribute(checkedAttr).isNull();
1835}
1836
1837void HTMLInputElement::setDefaultChecked(bool defaultChecked)
1838{
1839    setAttribute(checkedAttr, defaultChecked ? "" : 0);
1840}
1841
1842void HTMLInputElement::setDefaultName(const AtomicString& name)
1843{
1844    m_data.setName(name);
1845}
1846
1847String HTMLInputElement::accept() const
1848{
1849    return getAttribute(acceptAttr);
1850}
1851
1852void HTMLInputElement::setAccept(const String &value)
1853{
1854    setAttribute(acceptAttr, value);
1855}
1856
1857String HTMLInputElement::accessKey() const
1858{
1859    return getAttribute(accesskeyAttr);
1860}
1861
1862void HTMLInputElement::setAccessKey(const String &value)
1863{
1864    setAttribute(accesskeyAttr, value);
1865}
1866
1867String HTMLInputElement::align() const
1868{
1869    return getAttribute(alignAttr);
1870}
1871
1872void HTMLInputElement::setAlign(const String &value)
1873{
1874    setAttribute(alignAttr, value);
1875}
1876
1877String HTMLInputElement::alt() const
1878{
1879    return getAttribute(altAttr);
1880}
1881
1882void HTMLInputElement::setAlt(const String &value)
1883{
1884    setAttribute(altAttr, value);
1885}
1886
1887int HTMLInputElement::maxLength() const
1888{
1889    return m_data.maxLength();
1890}
1891
1892void HTMLInputElement::setMaxLength(int maxLength, ExceptionCode& ec)
1893{
1894    if (maxLength < 0)
1895        ec = INDEX_SIZE_ERR;
1896    else
1897        setAttribute(maxlengthAttr, String::number(maxLength));
1898}
1899
1900bool HTMLInputElement::multiple() const
1901{
1902    return !getAttribute(multipleAttr).isNull();
1903}
1904
1905void HTMLInputElement::setMultiple(bool multiple)
1906{
1907    setAttribute(multipleAttr, multiple ? "" : 0);
1908}
1909
1910void HTMLInputElement::setSize(unsigned _size)
1911{
1912    setAttribute(sizeAttr, String::number(_size));
1913}
1914
1915KURL HTMLInputElement::src() const
1916{
1917    return document()->completeURL(getAttribute(srcAttr));
1918}
1919
1920void HTMLInputElement::setSrc(const String &value)
1921{
1922    setAttribute(srcAttr, value);
1923}
1924
1925String HTMLInputElement::useMap() const
1926{
1927    return getAttribute(usemapAttr);
1928}
1929
1930void HTMLInputElement::setUseMap(const String &value)
1931{
1932    setAttribute(usemapAttr, value);
1933}
1934
1935void HTMLInputElement::setAutofilled(bool b)
1936{
1937    if (b == m_autofilled)
1938        return;
1939
1940    m_autofilled = b;
1941    setNeedsStyleRecalc();
1942}
1943
1944FileList* HTMLInputElement::files()
1945{
1946    if (inputType() != FILE)
1947        return 0;
1948    return m_fileList.get();
1949}
1950
1951String HTMLInputElement::sanitizeValue(const String& proposedValue) const
1952{
1953    if (isTextField())
1954        return InputElement::sanitizeValue(this, proposedValue);
1955    return proposedValue;
1956}
1957
1958bool HTMLInputElement::needsActivationCallback()
1959{
1960    return inputType() == PASSWORD || m_autocomplete == Off;
1961}
1962
1963void HTMLInputElement::registerForActivationCallbackIfNeeded()
1964{
1965    if (needsActivationCallback())
1966        document()->registerForDocumentActivationCallbacks(this);
1967}
1968
1969void HTMLInputElement::unregisterForActivationCallbackIfNeeded()
1970{
1971    if (!needsActivationCallback())
1972        document()->unregisterForDocumentActivationCallbacks(this);
1973}
1974
1975bool HTMLInputElement::isRequiredFormControl() const
1976{
1977    if (!required())
1978        return false;
1979
1980    switch (inputType()) {
1981        case CHECKBOX:
1982        case DATE:
1983        case DATETIME:
1984        case DATETIMELOCAL:
1985        case EMAIL:
1986        case FILE:
1987        case MONTH:
1988        case NUMBER:
1989        case PASSWORD:
1990        case RADIO:
1991        case SEARCH:
1992        case TELEPHONE:
1993        case TEXT:
1994        case TIME:
1995        case URL:
1996        case WEEK:
1997            return true;
1998        case BUTTON:
1999        case COLOR:
2000        case HIDDEN:
2001        case IMAGE:
2002        case ISINDEX:
2003        case RANGE:
2004        case RESET:
2005        case SUBMIT:
2006            return false;
2007    }
2008
2009    ASSERT_NOT_REACHED();
2010    return false;
2011}
2012
2013void HTMLInputElement::cacheSelection(int start, int end)
2014{
2015    m_data.setCachedSelectionStart(start);
2016    m_data.setCachedSelectionEnd(end);
2017}
2018
2019void HTMLInputElement::addSearchResult()
2020{
2021    ASSERT(isSearchField());
2022    if (renderer())
2023        toRenderTextControlSingleLine(renderer())->addSearchResult();
2024}
2025
2026void HTMLInputElement::onSearch()
2027{
2028    ASSERT(isSearchField());
2029    if (renderer())
2030        toRenderTextControlSingleLine(renderer())->stopSearchEventTimer();
2031    dispatchEvent(Event::create(eventNames().searchEvent, true, false));
2032}
2033
2034void HTMLInputElement::documentDidBecomeActive()
2035{
2036    ASSERT(needsActivationCallback());
2037    reset();
2038}
2039
2040void HTMLInputElement::willMoveToNewOwnerDocument()
2041{
2042    // Always unregister for cache callbacks when leaving a document, even if we would otherwise like to be registered
2043    if (needsActivationCallback())
2044        document()->unregisterForDocumentActivationCallbacks(this);
2045
2046    document()->checkedRadioButtons().removeButton(this);
2047
2048    HTMLFormControlElementWithState::willMoveToNewOwnerDocument();
2049}
2050
2051void HTMLInputElement::didMoveToNewOwnerDocument()
2052{
2053    registerForActivationCallbackIfNeeded();
2054
2055    HTMLFormControlElementWithState::didMoveToNewOwnerDocument();
2056}
2057
2058void HTMLInputElement::addSubresourceAttributeURLs(ListHashSet<KURL>& urls) const
2059{
2060    HTMLFormControlElementWithState::addSubresourceAttributeURLs(urls);
2061
2062    addSubresourceURL(urls, src());
2063}
2064
2065bool HTMLInputElement::willValidate() const
2066{
2067    // FIXME: This shall check for new WF2 input types too
2068    return HTMLFormControlElementWithState::willValidate() && inputType() != HIDDEN &&
2069           inputType() != BUTTON && inputType() != RESET;
2070}
2071
2072String HTMLInputElement::formStringFromDouble(double number)
2073{
2074    // According to HTML5, "the best representation of the number n as a floating
2075    // point number" is a string produced by applying ToString() to n.
2076    DtoaBuffer buffer;
2077    unsigned length;
2078    doubleToStringInJavaScriptFormat(number, buffer, &length);
2079    return String(buffer, length);
2080}
2081
2082bool HTMLInputElement::formStringToDouble(const String& src, double* out)
2083{
2084    // See HTML5 2.4.4.3 `Real numbers.'
2085
2086    if (src.isEmpty())
2087        return false;
2088    // String::toDouble() accepts leading + \t \n \v \f \r and SPACE, which are invalid in HTML5.
2089    // So, check the first character.
2090    if (src[0] != '-' && (src[0] < '0' || src[0] > '9'))
2091        return false;
2092
2093    bool valid = false;
2094    double value = src.toDouble(&valid);
2095    if (!valid)
2096        return false;
2097    // NaN and Infinity are not valid numbers according to the standard.
2098    if (isnan(value) || isinf(value))
2099        return false;
2100    if (out)
2101        *out = value;
2102    return true;
2103}
2104
2105bool HTMLInputElement::formStringToISODateTime(InputType type, const String& formString, ISODateTime* out)
2106{
2107    ISODateTime ignoredResult;
2108    if (!out)
2109        out = &ignoredResult;
2110    const UChar* characters = formString.characters();
2111    unsigned length = formString.length();
2112    unsigned end;
2113
2114    switch (type) {
2115    case DATE:
2116        return out->parseDate(characters, length, 0, end) && end == length;
2117    case DATETIME:
2118        return out->parseDateTime(characters, length, 0, end) && end == length;
2119    case DATETIMELOCAL:
2120        return out->parseDateTimeLocal(characters, length, 0, end) && end == length;
2121    case MONTH:
2122        return out->parseMonth(characters, length, 0, end) && end == length;
2123    case WEEK:
2124        return out->parseWeek(characters, length, 0, end) && end == length;
2125    case TIME:
2126        return out->parseTime(characters, length, 0, end) && end == length;
2127    default:
2128        ASSERT_NOT_REACHED();
2129        return false;
2130    }
2131}
2132
2133#if ENABLE(DATALIST)
2134HTMLElement* HTMLInputElement::list() const
2135{
2136    return dataList();
2137}
2138
2139HTMLDataListElement* HTMLInputElement::dataList() const
2140{
2141    if (!m_hasNonEmptyList)
2142        return 0;
2143
2144    switch (inputType()) {
2145    case COLOR:
2146    case DATE:
2147    case DATETIME:
2148    case DATETIMELOCAL:
2149    case EMAIL:
2150    case MONTH:
2151    case NUMBER:
2152    case RANGE:
2153    case SEARCH:
2154    case TELEPHONE:
2155    case TEXT:
2156    case TIME:
2157    case URL:
2158    case WEEK: {
2159        Element* element = document()->getElementById(getAttribute(listAttr));
2160        if (element && element->hasTagName(datalistTag))
2161            return static_cast<HTMLDataListElement*>(element);
2162        break;
2163    }
2164    case BUTTON:
2165    case CHECKBOX:
2166    case FILE:
2167    case HIDDEN:
2168    case IMAGE:
2169    case ISINDEX:
2170    case PASSWORD:
2171    case RADIO:
2172    case RESET:
2173    case SUBMIT:
2174        break;
2175    }
2176    return 0;
2177}
2178
2179HTMLOptionElement* HTMLInputElement::selectedOption() const
2180{
2181    String currentValue = value();
2182    // The empty value never matches to a datalist option because it
2183    // doesn't represent a suggestion according to the standard.
2184    if (currentValue.isEmpty())
2185        return 0;
2186
2187    HTMLDataListElement* sourceElement = dataList();
2188    if (!sourceElement)
2189        return 0;
2190    RefPtr<HTMLCollection> options = sourceElement->options();
2191    for (unsigned i = 0; options && i < options->length(); ++i) {
2192        HTMLOptionElement* option = static_cast<HTMLOptionElement*>(options->item(i));
2193        if (!option->disabled() && currentValue == option->value())
2194            return option;
2195    }
2196    return 0;
2197}
2198#endif  // ENABLE(DATALIST)
2199
2200} // namespace
2201