HTMLInputElement.cpp revision 5f1ab04193ad0130ca8204aadaceae083aca9881
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 "CSSPropertyNames.h"
30#include "ChromeClient.h"
31#include "Document.h"
32#include "Editor.h"
33#include "Event.h"
34#include "EventHandler.h"
35#include "EventNames.h"
36#include "File.h"
37#include "FileList.h"
38#include "FocusController.h"
39#include "FormDataList.h"
40#include "Frame.h"
41#include "HTMLFormElement.h"
42#include "HTMLImageLoader.h"
43#include "HTMLNames.h"
44#include "ScriptEventListener.h"
45#include "KeyboardEvent.h"
46#include "LocalizedStrings.h"
47#include "MappedAttribute.h"
48#include "MouseEvent.h"
49#include "Page.h"
50#include "RenderButton.h"
51#include "RenderFileUploadControl.h"
52#include "RenderImage.h"
53#include "RenderSlider.h"
54#include "RenderText.h"
55#include "RenderTextControlSingleLine.h"
56#include "RenderTheme.h"
57#include "TextEvent.h"
58#ifdef ANDROID_ACCEPT_CHANGES_TO_FOCUSED_TEXTFIELDS
59#include "WebViewCore.h"
60#endif
61#include <wtf/StdLibExtras.h>
62
63using namespace std;
64
65namespace WebCore {
66
67using namespace HTMLNames;
68
69const int maxSavedResults = 256;
70
71HTMLInputElement::HTMLInputElement(const QualifiedName& tagName, Document* doc, HTMLFormElement* f)
72    : HTMLFormControlElementWithState(tagName, doc, f)
73    , m_xPos(0)
74    , m_yPos(0)
75    , m_maxResults(-1)
76    , m_type(TEXT)
77    , m_checked(false)
78    , m_defaultChecked(false)
79    , m_useDefaultChecked(true)
80    , m_indeterminate(false)
81    , m_haveType(false)
82    , m_activeSubmit(false)
83    , m_autocomplete(Uninitialized)
84    , m_autofilled(false)
85    , m_inited(false)
86{
87    ASSERT(hasTagName(inputTag) || hasTagName(isindexTag));
88}
89
90HTMLInputElement::~HTMLInputElement()
91{
92    if (needsActivationCallback())
93        document()->unregisterForDocumentActivationCallbacks(this);
94
95    document()->checkedRadioButtons().removeButton(this);
96
97    // Need to remove this from the form while it is still an HTMLInputElement,
98    // so can't wait for the base class's destructor to do it.
99    removeFromForm();
100}
101
102const AtomicString& HTMLInputElement::formControlName() const
103{
104    return m_data.name();
105}
106
107bool HTMLInputElement::autoComplete() const
108{
109    if (m_autocomplete != Uninitialized)
110        return m_autocomplete == On;
111
112    // Assuming we're still in a Form, respect the Form's setting
113    if (HTMLFormElement* form = this->form())
114        return form->autoComplete();
115
116    // The default is true
117    return true;
118}
119
120static inline CheckedRadioButtons& checkedRadioButtons(const HTMLInputElement *element)
121{
122    if (HTMLFormElement* form = element->form())
123        return form->checkedRadioButtons();
124
125    return element->document()->checkedRadioButtons();
126}
127
128bool HTMLInputElement::isKeyboardFocusable(KeyboardEvent* event) const
129{
130    // If text fields can be focused, then they should always be keyboard focusable
131    if (isTextField())
132        return HTMLFormControlElementWithState::isFocusable();
133
134    // If the base class says we can't be focused, then we can stop now.
135    if (!HTMLFormControlElementWithState::isKeyboardFocusable(event))
136        return false;
137
138    if (inputType() == RADIO) {
139
140        // Never allow keyboard tabbing to leave you in the same radio group.  Always
141        // skip any other elements in the group.
142        Node* currentFocusedNode = document()->focusedNode();
143        if (currentFocusedNode && currentFocusedNode->hasTagName(inputTag)) {
144            HTMLInputElement* focusedInput = static_cast<HTMLInputElement*>(currentFocusedNode);
145            if (focusedInput->inputType() == RADIO && focusedInput->form() == form() &&
146                focusedInput->name() == name())
147                return false;
148        }
149
150        // Allow keyboard focus if we're checked or if nothing in the group is checked.
151        return checked() || !checkedRadioButtons(this).checkedButtonForGroup(name());
152    }
153
154    return true;
155}
156
157bool HTMLInputElement::isMouseFocusable() const
158{
159    if (isTextField())
160        return HTMLFormControlElementWithState::isFocusable();
161    return HTMLFormControlElementWithState::isMouseFocusable();
162}
163
164void HTMLInputElement::updateFocusAppearance(bool restorePreviousSelection)
165{
166    if (isTextField())
167        InputElement::updateFocusAppearance(m_data, this, this, restorePreviousSelection);
168    else
169        HTMLFormControlElementWithState::updateFocusAppearance(restorePreviousSelection);
170}
171
172void HTMLInputElement::aboutToUnload()
173{
174    InputElement::aboutToUnload(this, this);
175}
176
177bool HTMLInputElement::shouldUseInputMethod() const
178{
179    return m_type == TEXT || m_type == SEARCH || m_type == ISINDEX;
180}
181
182void HTMLInputElement::dispatchFocusEvent()
183{
184    InputElement::dispatchFocusEvent(m_data, this, this);
185
186    if (isTextField())
187        m_autofilled = false;
188
189    HTMLFormControlElementWithState::dispatchFocusEvent();
190}
191
192void HTMLInputElement::dispatchBlurEvent()
193{
194    InputElement::dispatchBlurEvent(m_data, this, this);
195    HTMLFormControlElementWithState::dispatchBlurEvent();
196}
197
198void HTMLInputElement::setType(const String& t)
199{
200    if (t.isEmpty()) {
201        int exccode;
202        removeAttribute(typeAttr, exccode);
203    } else
204        setAttribute(typeAttr, t);
205}
206
207void HTMLInputElement::setInputType(const String& t)
208{
209    InputType newType;
210
211    if (equalIgnoringCase(t, "password"))
212#ifdef ANDROID_ACCEPT_CHANGES_TO_FOCUSED_TEXTFIELDS
213    {
214        if (document()->focusedNode() == this)
215        {
216            android::WebViewCore::getWebViewCore(document()->view())->updateTextfield(this, true, String());
217        }
218#endif
219        newType = PASSWORD;
220#ifdef ANDROID_ACCEPT_CHANGES_TO_FOCUSED_TEXTFIELDS
221    }
222#endif
223    else if (equalIgnoringCase(t, "checkbox"))
224        newType = CHECKBOX;
225    else if (equalIgnoringCase(t, "radio"))
226        newType = RADIO;
227    else if (equalIgnoringCase(t, "submit"))
228        newType = SUBMIT;
229    else if (equalIgnoringCase(t, "reset"))
230        newType = RESET;
231    else if (equalIgnoringCase(t, "file"))
232        newType = FILE;
233    else if (equalIgnoringCase(t, "hidden"))
234        newType = HIDDEN;
235    else if (equalIgnoringCase(t, "image"))
236        newType = IMAGE;
237    else if (equalIgnoringCase(t, "button"))
238        newType = BUTTON;
239    else if (equalIgnoringCase(t, "khtml_isindex"))
240        newType = ISINDEX;
241    else if (equalIgnoringCase(t, "search"))
242        newType = SEARCH;
243    else if (equalIgnoringCase(t, "range"))
244        newType = RANGE;
245    else if (equalIgnoringCase(t, "email"))
246        newType = EMAIL;
247    else if (equalIgnoringCase(t, "number"))
248        newType = NUMBER;
249    else if (equalIgnoringCase(t, "tel"))
250        newType = TELEPHONE;
251    else if (equalIgnoringCase(t, "url"))
252        newType = URL;
253    else
254        newType = TEXT;
255
256    // IMPORTANT: Don't allow the type to be changed to FILE after the first
257    // type change, otherwise a JavaScript programmer would be able to set a text
258    // field's value to something like /etc/passwd and then change it to a file field.
259    if (inputType() != newType) {
260        if (newType == FILE && m_haveType)
261            // Set the attribute back to the old value.
262            // Useful in case we were called from inside parseMappedAttribute.
263            setAttribute(typeAttr, type());
264        else {
265            checkedRadioButtons(this).removeButton(this);
266
267            if (newType == FILE && !m_fileList)
268                m_fileList = FileList::create();
269
270            bool wasAttached = attached();
271            if (wasAttached)
272                detach();
273
274            bool didStoreValue = storesValueSeparateFromAttribute();
275            bool wasPasswordField = inputType() == PASSWORD;
276            bool didRespectHeightAndWidth = respectHeightAndWidthAttrs();
277            m_type = newType;
278            bool willStoreValue = storesValueSeparateFromAttribute();
279            bool isPasswordField = inputType() == PASSWORD;
280            bool willRespectHeightAndWidth = respectHeightAndWidthAttrs();
281
282            if (didStoreValue && !willStoreValue && !m_data.value().isNull()) {
283                setAttribute(valueAttr, m_data.value());
284                m_data.setValue(String());
285            }
286            if (!didStoreValue && willStoreValue)
287                m_data.setValue(constrainValue(getAttribute(valueAttr)));
288            else
289                InputElement::updateValueIfNeeded(m_data, this);
290
291            if (wasPasswordField && !isPasswordField)
292                unregisterForActivationCallbackIfNeeded();
293            else if (!wasPasswordField && isPasswordField)
294                registerForActivationCallbackIfNeeded();
295
296            if (didRespectHeightAndWidth != willRespectHeightAndWidth) {
297                NamedMappedAttrMap* map = mappedAttributes();
298                ASSERT(map);
299                if (Attribute* height = map->getAttributeItem(heightAttr))
300                    attributeChanged(height, false);
301                if (Attribute* width = map->getAttributeItem(widthAttr))
302                    attributeChanged(width, false);
303                if (Attribute* align = map->getAttributeItem(alignAttr))
304                    attributeChanged(align, false);
305            }
306
307            if (wasAttached) {
308                attach();
309                if (document()->focusedNode() == this)
310                    updateFocusAppearance(true);
311            }
312
313            checkedRadioButtons(this).addButton(this);
314        }
315
316        InputElement::notifyFormStateChanged(this);
317    }
318    m_haveType = true;
319
320    if (inputType() != IMAGE && m_imageLoader)
321        m_imageLoader.clear();
322}
323
324const AtomicString& HTMLInputElement::formControlType() const
325{
326    // needs to be lowercase according to DOM spec
327    switch (inputType()) {
328        case BUTTON: {
329            DEFINE_STATIC_LOCAL(const AtomicString, button, ("button"));
330            return button;
331        }
332        case CHECKBOX: {
333            DEFINE_STATIC_LOCAL(const AtomicString, checkbox, ("checkbox"));
334            return checkbox;
335        }
336        case EMAIL: {
337            DEFINE_STATIC_LOCAL(const AtomicString, email, ("email"));
338            return email;
339        }
340        case FILE: {
341            DEFINE_STATIC_LOCAL(const AtomicString, file, ("file"));
342            return file;
343        }
344        case HIDDEN: {
345            DEFINE_STATIC_LOCAL(const AtomicString, hidden, ("hidden"));
346            return hidden;
347        }
348        case IMAGE: {
349            DEFINE_STATIC_LOCAL(const AtomicString, image, ("image"));
350            return image;
351        }
352        case ISINDEX:
353            return emptyAtom;
354        case NUMBER: {
355            DEFINE_STATIC_LOCAL(const AtomicString, number, ("number"));
356            return number;
357        }
358        case PASSWORD: {
359            DEFINE_STATIC_LOCAL(const AtomicString, password, ("password"));
360            return password;
361        }
362        case RADIO: {
363            DEFINE_STATIC_LOCAL(const AtomicString, radio, ("radio"));
364            return radio;
365        }
366        case RANGE: {
367            DEFINE_STATIC_LOCAL(const AtomicString, range, ("range"));
368            return range;
369        }
370        case RESET: {
371            DEFINE_STATIC_LOCAL(const AtomicString, reset, ("reset"));
372            return reset;
373        }
374        case SEARCH: {
375            DEFINE_STATIC_LOCAL(const AtomicString, search, ("search"));
376            return search;
377        }
378        case SUBMIT: {
379            DEFINE_STATIC_LOCAL(const AtomicString, submit, ("submit"));
380            return submit;
381        }
382        case TELEPHONE: {
383            DEFINE_STATIC_LOCAL(const AtomicString, telephone, ("tel"));
384            return telephone;
385        }
386        case TEXT: {
387            DEFINE_STATIC_LOCAL(const AtomicString, text, ("text"));
388            return text;
389        }
390        case URL: {
391            DEFINE_STATIC_LOCAL(const AtomicString, url, ("url"));
392            return url;
393        }
394    }
395    return emptyAtom;
396}
397
398bool HTMLInputElement::saveFormControlState(String& result) const
399{
400    if (!autoComplete())
401        return false;
402
403    switch (inputType()) {
404        case BUTTON:
405        case EMAIL:
406        case FILE:
407        case HIDDEN:
408        case IMAGE:
409        case ISINDEX:
410        case NUMBER:
411        case RANGE:
412        case RESET:
413        case SEARCH:
414        case SUBMIT:
415        case TELEPHONE:
416        case TEXT:
417        case URL:
418            result = value();
419            return true;
420        case CHECKBOX:
421        case RADIO:
422            result = checked() ? "on" : "off";
423            return true;
424        case PASSWORD:
425            return false;
426    }
427    ASSERT_NOT_REACHED();
428    return false;
429}
430
431void HTMLInputElement::restoreFormControlState(const String& state)
432{
433    ASSERT(inputType() != PASSWORD); // should never save/restore password fields
434    switch (inputType()) {
435        case BUTTON:
436        case EMAIL:
437        case FILE:
438        case HIDDEN:
439        case IMAGE:
440        case ISINDEX:
441        case NUMBER:
442        case RANGE:
443        case RESET:
444        case SEARCH:
445        case SUBMIT:
446        case TELEPHONE:
447        case TEXT:
448        case URL:
449            setValue(state);
450            break;
451        case CHECKBOX:
452        case RADIO:
453            setChecked(state == "on");
454            break;
455        case PASSWORD:
456            break;
457    }
458}
459
460bool HTMLInputElement::canStartSelection() const
461{
462    if (!isTextField())
463        return false;
464    return HTMLFormControlElementWithState::canStartSelection();
465}
466
467bool HTMLInputElement::canHaveSelection() const
468{
469    return isTextField();
470}
471
472int HTMLInputElement::selectionStart() const
473{
474    if (!isTextField())
475        return 0;
476    if (document()->focusedNode() != this && m_data.cachedSelectionStart() != -1)
477        return m_data.cachedSelectionStart();
478    if (!renderer())
479        return 0;
480    return toRenderTextControl(renderer())->selectionStart();
481}
482
483int HTMLInputElement::selectionEnd() const
484{
485    if (!isTextField())
486        return 0;
487    if (document()->focusedNode() != this && m_data.cachedSelectionEnd() != -1)
488        return m_data.cachedSelectionEnd();
489    if (!renderer())
490        return 0;
491    return toRenderTextControl(renderer())->selectionEnd();
492}
493
494void HTMLInputElement::setSelectionStart(int start)
495{
496    if (!isTextField())
497        return;
498    if (!renderer())
499        return;
500    toRenderTextControl(renderer())->setSelectionStart(start);
501}
502
503void HTMLInputElement::setSelectionEnd(int end)
504{
505    if (!isTextField())
506        return;
507    if (!renderer())
508        return;
509    toRenderTextControl(renderer())->setSelectionEnd(end);
510}
511
512void HTMLInputElement::select()
513{
514    if (!isTextField())
515        return;
516    if (!renderer())
517        return;
518    toRenderTextControl(renderer())->select();
519}
520
521void HTMLInputElement::setSelectionRange(int start, int end)
522{
523    InputElement::updateSelectionRange(this, this, start, end);
524}
525
526void HTMLInputElement::accessKeyAction(bool sendToAnyElement)
527{
528    switch (inputType()) {
529        case BUTTON:
530        case CHECKBOX:
531        case FILE:
532        case IMAGE:
533        case RADIO:
534        case RANGE:
535        case RESET:
536        case SUBMIT:
537            focus(false);
538            // send the mouse button events iff the caller specified sendToAnyElement
539            dispatchSimulatedClick(0, sendToAnyElement);
540            break;
541        case HIDDEN:
542            // a no-op for this type
543            break;
544        case EMAIL:
545        case ISINDEX:
546        case NUMBER:
547        case PASSWORD:
548        case SEARCH:
549        case TELEPHONE:
550        case TEXT:
551        case URL:
552            // should never restore previous selection here
553            focus(false);
554            break;
555    }
556}
557
558bool HTMLInputElement::mapToEntry(const QualifiedName& attrName, MappedAttributeEntry& result) const
559{
560    if (((attrName == heightAttr || attrName == widthAttr) && respectHeightAndWidthAttrs()) ||
561        attrName == vspaceAttr ||
562        attrName == hspaceAttr) {
563        result = eUniversal;
564        return false;
565    }
566
567    if (attrName == alignAttr) {
568        if (inputType() == IMAGE) {
569            // Share with <img> since the alignment behavior is the same.
570            result = eReplaced;
571            return false;
572        }
573    }
574
575    return HTMLElement::mapToEntry(attrName, result);
576}
577
578void HTMLInputElement::parseMappedAttribute(MappedAttribute *attr)
579{
580    if (attr->name() == nameAttr) {
581        checkedRadioButtons(this).removeButton(this);
582        m_data.setName(attr->value());
583        checkedRadioButtons(this).addButton(this);
584    } else if (attr->name() == autocompleteAttr) {
585        if (equalIgnoringCase(attr->value(), "off")) {
586            m_autocomplete = Off;
587            registerForActivationCallbackIfNeeded();
588        } else {
589            if (m_autocomplete == Off)
590                unregisterForActivationCallbackIfNeeded();
591            if (attr->isEmpty())
592                m_autocomplete = Uninitialized;
593            else
594                m_autocomplete = On;
595        }
596    } else if (attr->name() == typeAttr) {
597        setInputType(attr->value());
598    } else if (attr->name() == valueAttr) {
599        // We only need to setChanged if the form is looking at the default value right now.
600        if (m_data.value().isNull())
601            setNeedsStyleRecalc();
602        setFormControlValueMatchesRenderer(false);
603    } else if (attr->name() == checkedAttr) {
604        m_defaultChecked = !attr->isNull();
605        if (m_useDefaultChecked) {
606            setChecked(m_defaultChecked);
607            m_useDefaultChecked = true;
608        }
609    } else if (attr->name() == maxlengthAttr)
610        InputElement::parseMaxLengthAttribute(m_data, this, this, attr);
611    else if (attr->name() == sizeAttr)
612        InputElement::parseSizeAttribute(m_data, this, attr);
613    else if (attr->name() == altAttr) {
614        if (renderer() && inputType() == IMAGE)
615            toRenderImage(renderer())->updateAltText();
616    } else if (attr->name() == srcAttr) {
617        if (renderer() && inputType() == IMAGE) {
618            if (!m_imageLoader)
619                m_imageLoader.set(new HTMLImageLoader(this));
620            m_imageLoader->updateFromElementIgnoringPreviousError();
621        }
622    } else if (attr->name() == usemapAttr ||
623               attr->name() == accesskeyAttr) {
624        // FIXME: ignore for the moment
625    } else if (attr->name() == vspaceAttr) {
626        addCSSLength(attr, CSSPropertyMarginTop, attr->value());
627        addCSSLength(attr, CSSPropertyMarginBottom, attr->value());
628    } else if (attr->name() == hspaceAttr) {
629        addCSSLength(attr, CSSPropertyMarginLeft, attr->value());
630        addCSSLength(attr, CSSPropertyMarginRight, attr->value());
631    } else if (attr->name() == alignAttr) {
632        if (inputType() == IMAGE)
633            addHTMLAlignment(attr);
634    } else if (attr->name() == widthAttr) {
635        if (respectHeightAndWidthAttrs())
636            addCSSLength(attr, CSSPropertyWidth, attr->value());
637    } else if (attr->name() == heightAttr) {
638        if (respectHeightAndWidthAttrs())
639            addCSSLength(attr, CSSPropertyHeight, attr->value());
640    } else if (attr->name() == onfocusAttr) {
641        setAttributeEventListener(eventNames().focusEvent, createAttributeEventListener(this, attr));
642    } else if (attr->name() == onblurAttr) {
643        setAttributeEventListener(eventNames().blurEvent, createAttributeEventListener(this, attr));
644    } else if (attr->name() == onselectAttr) {
645        setAttributeEventListener(eventNames().selectEvent, createAttributeEventListener(this, attr));
646    } else if (attr->name() == onchangeAttr) {
647        setAttributeEventListener(eventNames().changeEvent, createAttributeEventListener(this, attr));
648    } else if (attr->name() == oninputAttr) {
649        setAttributeEventListener(eventNames().inputEvent, createAttributeEventListener(this, attr));
650    }
651    // Search field and slider attributes all just cause updateFromElement to be called through style
652    // recalcing.
653    else if (attr->name() == onsearchAttr) {
654        setAttributeEventListener(eventNames().searchEvent, createAttributeEventListener(this, attr));
655    } else if (attr->name() == resultsAttr) {
656        int oldResults = m_maxResults;
657        m_maxResults = !attr->isNull() ? min(attr->value().toInt(), maxSavedResults) : -1;
658        // FIXME: Detaching just for maxResults change is not ideal.  We should figure out the right
659        // time to relayout for this change.
660        if (m_maxResults != oldResults && (m_maxResults <= 0 || oldResults <= 0) && attached()) {
661            detach();
662            attach();
663        }
664        setNeedsStyleRecalc();
665    } else if (attr->name() == placeholderAttr) {
666        if (isTextField())
667            updatePlaceholderVisibility();
668    } else if (attr->name() == autosaveAttr ||
669             attr->name() == incrementalAttr ||
670             attr->name() == minAttr ||
671             attr->name() == maxAttr ||
672             attr->name() == multipleAttr ||
673             attr->name() == precisionAttr)
674        setNeedsStyleRecalc();
675    else
676        HTMLFormControlElementWithState::parseMappedAttribute(attr);
677}
678
679bool HTMLInputElement::rendererIsNeeded(RenderStyle *style)
680{
681    switch (inputType()) {
682        case BUTTON:
683        case CHECKBOX:
684        case EMAIL:
685        case FILE:
686        case IMAGE:
687        case ISINDEX:
688        case NUMBER:
689        case PASSWORD:
690        case RADIO:
691        case RANGE:
692        case RESET:
693        case SEARCH:
694        case SUBMIT:
695        case TELEPHONE:
696        case TEXT:
697        case URL:
698            return HTMLFormControlElementWithState::rendererIsNeeded(style);
699        case HIDDEN:
700            return false;
701    }
702    ASSERT(false);
703    return false;
704}
705
706RenderObject *HTMLInputElement::createRenderer(RenderArena *arena, RenderStyle *style)
707{
708    switch (inputType()) {
709        case BUTTON:
710        case RESET:
711        case SUBMIT:
712            return new (arena) RenderButton(this);
713        case CHECKBOX:
714        case RADIO:
715            return RenderObject::createObject(this, style);
716        case FILE:
717            return new (arena) RenderFileUploadControl(this);
718        case HIDDEN:
719            break;
720        case IMAGE:
721            return new (arena) RenderImage(this);
722        case RANGE:
723            return new (arena) RenderSlider(this);
724        case EMAIL:
725        case ISINDEX:
726        case NUMBER:
727        case PASSWORD:
728        case SEARCH:
729        case TELEPHONE:
730        case TEXT:
731        case URL:
732            return new (arena) RenderTextControlSingleLine(this);
733    }
734    ASSERT(false);
735    return 0;
736}
737
738void HTMLInputElement::attach()
739{
740    if (!m_inited) {
741        if (!m_haveType)
742            setInputType(getAttribute(typeAttr));
743        m_inited = true;
744    }
745
746    HTMLFormControlElementWithState::attach();
747
748    if (inputType() == IMAGE) {
749        if (!m_imageLoader)
750            m_imageLoader.set(new HTMLImageLoader(this));
751        m_imageLoader->updateFromElement();
752        if (renderer()) {
753            RenderImage* imageObj = toRenderImage(renderer());
754            imageObj->setCachedImage(m_imageLoader->image());
755
756            // If we have no image at all because we have no src attribute, set
757            // image height and width for the alt text instead.
758            if (!m_imageLoader->image() && !imageObj->cachedImage())
759                imageObj->setImageSizeForAltText();
760        }
761    }
762}
763
764void HTMLInputElement::detach()
765{
766    HTMLFormControlElementWithState::detach();
767    setFormControlValueMatchesRenderer(false);
768}
769
770String HTMLInputElement::altText() const
771{
772    // http://www.w3.org/TR/1998/REC-html40-19980424/appendix/notes.html#altgen
773    // also heavily discussed by Hixie on bugzilla
774    // note this is intentionally different to HTMLImageElement::altText()
775    String alt = getAttribute(altAttr);
776    // fall back to title attribute
777    if (alt.isNull())
778        alt = getAttribute(titleAttr);
779    if (alt.isNull())
780        alt = getAttribute(valueAttr);
781    if (alt.isEmpty())
782        alt = inputElementAltText();
783    return alt;
784}
785
786bool HTMLInputElement::isSuccessfulSubmitButton() const
787{
788    // HTML spec says that buttons must have names to be considered successful.
789    // However, other browsers do not impose this constraint. So we do likewise.
790    return !disabled() && (inputType() == IMAGE || inputType() == SUBMIT);
791}
792
793bool HTMLInputElement::isActivatedSubmit() const
794{
795    return m_activeSubmit;
796}
797
798void HTMLInputElement::setActivatedSubmit(bool flag)
799{
800    m_activeSubmit = flag;
801}
802
803bool HTMLInputElement::appendFormData(FormDataList& encoding, bool multipart)
804{
805    // image generates its own names, but for other types there is no form data unless there's a name
806    if (name().isEmpty() && inputType() != IMAGE)
807        return false;
808
809    switch (inputType()) {
810        case EMAIL:
811        case HIDDEN:
812        case ISINDEX:
813        case NUMBER:
814        case PASSWORD:
815        case RANGE:
816        case SEARCH:
817        case TELEPHONE:
818        case TEXT:
819        case URL:
820            // always successful
821            encoding.appendData(name(), value());
822            return true;
823
824        case CHECKBOX:
825        case RADIO:
826            if (checked()) {
827                encoding.appendData(name(), value());
828                return true;
829            }
830            break;
831
832        case BUTTON:
833        case RESET:
834            // these types of buttons are never successful
835            return false;
836
837        case IMAGE:
838            if (m_activeSubmit) {
839                encoding.appendData(name().isEmpty() ? "x" : (name() + ".x"), m_xPos);
840                encoding.appendData(name().isEmpty() ? "y" : (name() + ".y"), m_yPos);
841                if (!name().isEmpty() && !value().isEmpty())
842                    encoding.appendData(name(), value());
843                return true;
844            }
845            break;
846
847        case SUBMIT:
848            if (m_activeSubmit) {
849                String enc_str = valueWithDefault();
850                encoding.appendData(name(), enc_str);
851                return true;
852            }
853            break;
854
855        case FILE: {
856            // Can't submit file on GET.
857            if (!multipart)
858                return false;
859
860            // If no filename at all is entered, return successful but empty.
861            // Null would be more logical, but Netscape posts an empty file. Argh.
862            unsigned numFiles = m_fileList->length();
863            if (!numFiles) {
864                encoding.appendFile(name(), File::create(""));
865                return true;
866            }
867
868            for (unsigned i = 0; i < numFiles; ++i)
869                encoding.appendFile(name(), m_fileList->item(i));
870            return true;
871        }
872    }
873    return false;
874}
875
876void HTMLInputElement::reset()
877{
878    if (storesValueSeparateFromAttribute())
879        setValue(String());
880
881    setChecked(m_defaultChecked);
882    m_useDefaultChecked = true;
883}
884
885void HTMLInputElement::setChecked(bool nowChecked, bool sendChangeEvent)
886{
887    if (checked() == nowChecked)
888        return;
889
890    checkedRadioButtons(this).removeButton(this);
891
892    m_useDefaultChecked = false;
893    m_checked = nowChecked;
894    setNeedsStyleRecalc();
895
896    checkedRadioButtons(this).addButton(this);
897
898    if (renderer() && renderer()->style()->hasAppearance())
899        theme()->stateChanged(renderer(), CheckedState);
900
901    // Only send a change event for items in the document (avoid firing during
902    // parsing) and don't send a change event for a radio button that's getting
903    // unchecked to match other browsers. DOM is not a useful standard for this
904    // because it says only to fire change events at "lose focus" time, which is
905    // definitely wrong in practice for these types of elements.
906    if (sendChangeEvent && inDocument() && (inputType() != RADIO || nowChecked))
907        dispatchFormControlChangeEvent();
908}
909
910void HTMLInputElement::setIndeterminate(bool _indeterminate)
911{
912    // Only checkboxes honor indeterminate.
913    if (inputType() != CHECKBOX || indeterminate() == _indeterminate)
914        return;
915
916    m_indeterminate = _indeterminate;
917
918    setNeedsStyleRecalc();
919
920    if (renderer() && renderer()->style()->hasAppearance())
921        theme()->stateChanged(renderer(), CheckedState);
922}
923
924int HTMLInputElement::size() const
925{
926    return m_data.size();
927}
928
929void HTMLInputElement::copyNonAttributeProperties(const Element* source)
930{
931    const HTMLInputElement* sourceElement = static_cast<const HTMLInputElement*>(source);
932
933    m_data.setValue(sourceElement->m_data.value());
934    m_checked = sourceElement->m_checked;
935    m_indeterminate = sourceElement->m_indeterminate;
936
937    HTMLFormControlElementWithState::copyNonAttributeProperties(source);
938}
939
940String HTMLInputElement::value() const
941{
942    // The HTML5 spec (as of the 10/24/08 working draft) says that the value attribute isn't applicable to the file upload control
943    // but we don't want to break existing websites, who may be relying on being able to get the file name as a value.
944    if (inputType() == FILE) {
945        if (!m_fileList->isEmpty())
946            return m_fileList->item(0)->fileName();
947        return String();
948    }
949
950    String value = m_data.value();
951    if (value.isNull()) {
952        value = constrainValue(getAttribute(valueAttr));
953
954        // If no attribute exists, then just use "on" or "" based off the checked() state of the control.
955        if (value.isNull() && (inputType() == CHECKBOX || inputType() == RADIO))
956            return checked() ? "on" : "";
957    }
958
959    return value;
960}
961
962String HTMLInputElement::valueWithDefault() const
963{
964    String v = value();
965    if (v.isNull()) {
966        switch (inputType()) {
967            case BUTTON:
968            case CHECKBOX:
969            case EMAIL:
970            case FILE:
971            case HIDDEN:
972            case IMAGE:
973            case ISINDEX:
974            case NUMBER:
975            case PASSWORD:
976            case RADIO:
977            case RANGE:
978            case SEARCH:
979            case TELEPHONE:
980            case TEXT:
981            case URL:
982                break;
983            case RESET:
984                v = resetButtonDefaultLabel();
985                break;
986            case SUBMIT:
987                v = submitButtonDefaultLabel();
988                break;
989        }
990    }
991    return v;
992}
993
994void HTMLInputElement::setValue(const String& value)
995{
996    // For security reasons, we don't allow setting the filename, but we do allow clearing it.
997    // The HTML5 spec (as of the 10/24/08 working draft) says that the value attribute isn't applicable to the file upload control
998    // but we don't want to break existing websites, who may be relying on this method to clear things.
999    if (inputType() == FILE && !value.isEmpty())
1000        return;
1001
1002    setFormControlValueMatchesRenderer(false);
1003    if (storesValueSeparateFromAttribute()) {
1004        if (inputType() == FILE)
1005            m_fileList->clear();
1006        else {
1007            m_data.setValue(constrainValue(value));
1008            if (isTextField()) {
1009                InputElement::updatePlaceholderVisibility(m_data, this, this);
1010                if (inDocument())
1011                    document()->updateStyleIfNeeded();
1012            }
1013        }
1014        if (renderer())
1015            renderer()->updateFromElement();
1016        setNeedsStyleRecalc();
1017    } else
1018        setAttribute(valueAttr, constrainValue(value));
1019
1020    if (isTextField()) {
1021        unsigned max = m_data.value().length();
1022        if (document()->focusedNode() == this)
1023#ifdef ANDROID_ACCEPT_CHANGES_TO_FOCUSED_TEXTFIELDS
1024        {
1025            // Make sure our UI side textfield changes to match the RenderTextControl
1026            android::WebViewCore::getWebViewCore(document()->view())->updateTextfield(this, false, value);
1027#endif
1028            InputElement::updateSelectionRange(this, this, max, max);
1029#ifdef ANDROID_ACCEPT_CHANGES_TO_FOCUSED_TEXTFIELDS
1030        }
1031#endif
1032        else
1033            cacheSelection(max, max);
1034    }
1035    InputElement::notifyFormStateChanged(this);
1036}
1037
1038String HTMLInputElement::placeholder() const
1039{
1040    return getAttribute(placeholderAttr).string();
1041}
1042
1043void HTMLInputElement::setPlaceholder(const String& value)
1044{
1045    setAttribute(placeholderAttr, value);
1046}
1047
1048bool HTMLInputElement::searchEventsShouldBeDispatched() const
1049{
1050    return hasAttribute(incrementalAttr);
1051}
1052
1053void HTMLInputElement::setValueFromRenderer(const String& value)
1054{
1055    // File upload controls will always use setFileListFromRenderer.
1056    ASSERT(inputType() != FILE);
1057    InputElement::setValueFromRenderer(m_data, this, this, value);
1058}
1059
1060void HTMLInputElement::setFileListFromRenderer(const Vector<String>& paths)
1061{
1062    m_fileList->clear();
1063    int size = paths.size();
1064    for (int i = 0; i < size; i++)
1065        m_fileList->append(File::create(paths[i]));
1066
1067    setFormControlValueMatchesRenderer(true);
1068    InputElement::notifyFormStateChanged(this);
1069}
1070
1071bool HTMLInputElement::storesValueSeparateFromAttribute() const
1072{
1073    switch (inputType()) {
1074        case BUTTON:
1075        case CHECKBOX:
1076        case HIDDEN:
1077        case IMAGE:
1078        case RADIO:
1079        case RESET:
1080        case SUBMIT:
1081            return false;
1082        case EMAIL:
1083        case FILE:
1084        case ISINDEX:
1085        case NUMBER:
1086        case PASSWORD:
1087        case RANGE:
1088        case SEARCH:
1089        case TELEPHONE:
1090        case TEXT:
1091        case URL:
1092            return true;
1093    }
1094    return false;
1095}
1096
1097void* HTMLInputElement::preDispatchEventHandler(Event *evt)
1098{
1099    // preventDefault or "return false" are used to reverse the automatic checking/selection we do here.
1100    // This result gives us enough info to perform the "undo" in postDispatch of the action we take here.
1101    void* result = 0;
1102    if ((inputType() == CHECKBOX || inputType() == RADIO) && evt->isMouseEvent()
1103            && evt->type() == eventNames().clickEvent && static_cast<MouseEvent*>(evt)->button() == LeftButton) {
1104        if (inputType() == CHECKBOX) {
1105            // As a way to store the state, we return 0 if we were unchecked, 1 if we were checked, and 2 for
1106            // indeterminate.
1107            if (indeterminate()) {
1108                result = (void*)0x2;
1109                setIndeterminate(false);
1110            } else {
1111                if (checked())
1112                    result = (void*)0x1;
1113                setChecked(!checked(), true);
1114            }
1115        } else {
1116            // For radio buttons, store the current selected radio object.
1117            // We really want radio groups to end up in sane states, i.e., to have something checked.
1118            // Therefore if nothing is currently selected, we won't allow this action to be "undone", since
1119            // we want some object in the radio group to actually get selected.
1120            HTMLInputElement* currRadio = checkedRadioButtons(this).checkedButtonForGroup(name());
1121            if (currRadio) {
1122                // We have a radio button selected that is not us.  Cache it in our result field and ref it so
1123                // that it can't be destroyed.
1124                currRadio->ref();
1125                result = currRadio;
1126            }
1127            setChecked(true, true);
1128        }
1129    }
1130    return result;
1131}
1132
1133void HTMLInputElement::postDispatchEventHandler(Event *evt, void* data)
1134{
1135    if ((inputType() == CHECKBOX || inputType() == RADIO) && evt->isMouseEvent()
1136            && evt->type() == eventNames().clickEvent && static_cast<MouseEvent*>(evt)->button() == LeftButton) {
1137        if (inputType() == CHECKBOX) {
1138            // Reverse the checking we did in preDispatch.
1139            if (evt->defaultPrevented() || evt->defaultHandled()) {
1140                if (data == (void*)0x2)
1141                    setIndeterminate(true);
1142                else
1143                    setChecked(data);
1144            }
1145        } else if (data) {
1146            HTMLInputElement* input = static_cast<HTMLInputElement*>(data);
1147            if (evt->defaultPrevented() || evt->defaultHandled()) {
1148                // Restore the original selected radio button if possible.
1149                // Make sure it is still a radio button and only do the restoration if it still
1150                // belongs to our group.
1151
1152                if (input->form() == form() && input->inputType() == RADIO && input->name() == name()) {
1153                    // Ok, the old radio button is still in our form and in our group and is still a
1154                    // radio button, so it's safe to restore selection to it.
1155                    input->setChecked(true);
1156                }
1157            }
1158            input->deref();
1159        }
1160
1161        // Left clicks on radio buttons and check boxes already performed default actions in preDispatchEventHandler().
1162        evt->setDefaultHandled();
1163    }
1164}
1165
1166void HTMLInputElement::defaultEventHandler(Event* evt)
1167{
1168    // FIXME: It would be better to refactor this for the different types of input element.
1169    // Having them all in one giant function makes this hard to read, and almost all the handling is type-specific.
1170
1171    bool clickDefaultFormButton = false;
1172
1173    if (isTextField() && evt->type() == eventNames().textInputEvent && evt->isTextEvent() && static_cast<TextEvent*>(evt)->data() == "\n")
1174        clickDefaultFormButton = true;
1175
1176    if (inputType() == IMAGE && evt->isMouseEvent() && evt->type() == eventNames().clickEvent) {
1177        // record the mouse position for when we get the DOMActivate event
1178        MouseEvent* me = static_cast<MouseEvent*>(evt);
1179        // FIXME: We could just call offsetX() and offsetY() on the event,
1180        // but that's currently broken, so for now do the computation here.
1181        if (me->isSimulated() || !renderer()) {
1182            m_xPos = 0;
1183            m_yPos = 0;
1184        } else {
1185            // FIXME: This doesn't work correctly with transforms.
1186            // FIXME: pageX/pageY need adjusting for pageZoomFactor(). Use actualPageLocation()?
1187            IntPoint absOffset = roundedIntPoint(renderer()->localToAbsolute());
1188            m_xPos = me->pageX() - absOffset.x();
1189            m_yPos = me->pageY() - absOffset.y();
1190        }
1191    }
1192
1193    if (isTextField()
1194            && evt->type() == eventNames().keydownEvent
1195            && evt->isKeyboardEvent()
1196            && focused()
1197            && document()->frame()
1198            && document()->frame()->doTextFieldCommandFromEvent(this, static_cast<KeyboardEvent*>(evt))) {
1199        evt->setDefaultHandled();
1200        return;
1201    }
1202
1203    if (inputType() == RADIO
1204            && evt->isMouseEvent()
1205            && evt->type() == eventNames().clickEvent
1206            && static_cast<MouseEvent*>(evt)->button() == LeftButton) {
1207        evt->setDefaultHandled();
1208        return;
1209    }
1210
1211    // Call the base event handler before any of our own event handling for almost all events in text fields.
1212    // Makes editing keyboard handling take precedence over the keydown and keypress handling in this function.
1213    bool callBaseClassEarly = isTextField() && !clickDefaultFormButton
1214        && (evt->type() == eventNames().keydownEvent || evt->type() == eventNames().keypressEvent);
1215    if (callBaseClassEarly) {
1216        HTMLFormControlElementWithState::defaultEventHandler(evt);
1217        if (evt->defaultHandled())
1218            return;
1219    }
1220
1221    // DOMActivate events cause the input to be "activated" - in the case of image and submit inputs, this means
1222    // actually submitting the form. For reset inputs, the form is reset. These events are sent when the user clicks
1223    // on the element, or presses enter while it is the active element. JavaScript code wishing to activate the element
1224    // must dispatch a DOMActivate event - a click event will not do the job.
1225    if (evt->type() == eventNames().DOMActivateEvent && !disabled()) {
1226        if (inputType() == IMAGE || inputType() == SUBMIT || inputType() == RESET) {
1227            if (!form())
1228                return;
1229            if (inputType() == RESET)
1230                form()->reset();
1231            else {
1232                m_activeSubmit = true;
1233                // FIXME: Would be cleaner to get m_xPos and m_yPos out of the underlying mouse
1234                // event (if any) here instead of relying on the variables set above when
1235                // processing the click event. Even better, appendFormData could pass the
1236                // event in, and then we could get rid of m_xPos and m_yPos altogether!
1237                if (!form()->prepareSubmit(evt)) {
1238                    m_xPos = 0;
1239                    m_yPos = 0;
1240                }
1241                m_activeSubmit = false;
1242            }
1243        } else if (inputType() == FILE && renderer())
1244            static_cast<RenderFileUploadControl*>(renderer())->click();
1245    }
1246
1247    // Use key press event here since sending simulated mouse events
1248    // on key down blocks the proper sending of the key press event.
1249    if (evt->type() == eventNames().keypressEvent && evt->isKeyboardEvent()) {
1250        bool clickElement = false;
1251
1252        int charCode = static_cast<KeyboardEvent*>(evt)->charCode();
1253
1254        if (charCode == '\r') {
1255            switch (inputType()) {
1256                case CHECKBOX:
1257                case EMAIL:
1258                case HIDDEN:
1259                case ISINDEX:
1260                case NUMBER:
1261                case PASSWORD:
1262                case RANGE:
1263                case SEARCH:
1264                case TELEPHONE:
1265                case TEXT:
1266                case URL:
1267                    // Simulate mouse click on the default form button for enter for these types of elements.
1268                    clickDefaultFormButton = true;
1269                    break;
1270                case BUTTON:
1271                case FILE:
1272                case IMAGE:
1273                case RESET:
1274                case SUBMIT:
1275                    // Simulate mouse click for enter for these types of elements.
1276                    clickElement = true;
1277                    break;
1278                case RADIO:
1279                    break; // Don't do anything for enter on a radio button.
1280            }
1281        } else if (charCode == ' ') {
1282            switch (inputType()) {
1283                case BUTTON:
1284                case CHECKBOX:
1285                case FILE:
1286                case IMAGE:
1287                case RESET:
1288                case SUBMIT:
1289                case RADIO:
1290                    // Prevent scrolling down the page.
1291                    evt->setDefaultHandled();
1292                    return;
1293                default:
1294                    break;
1295            }
1296        }
1297
1298        if (clickElement) {
1299            dispatchSimulatedClick(evt);
1300            evt->setDefaultHandled();
1301            return;
1302        }
1303    }
1304
1305    if (evt->type() == eventNames().keydownEvent && evt->isKeyboardEvent()) {
1306        String key = static_cast<KeyboardEvent*>(evt)->keyIdentifier();
1307
1308        if (key == "U+0020") {
1309            switch (inputType()) {
1310                case BUTTON:
1311                case CHECKBOX:
1312                case FILE:
1313                case IMAGE:
1314                case RESET:
1315                case SUBMIT:
1316                case RADIO:
1317                    setActive(true, true);
1318                    // No setDefaultHandled(), because IE dispatches a keypress in this case
1319                    // and the caller will only dispatch a keypress if we don't call setDefaultHandled.
1320                    return;
1321                default:
1322                    break;
1323            }
1324        }
1325
1326// allow enter to change state of radio
1327        if (inputType() == RADIO && (key == "Up" || key == "Down" || key == "Left" || key == "Right")) {
1328            // Left and up mean "previous radio button".
1329            // Right and down mean "next radio button".
1330            // Tested in WinIE, and even for RTL, left still means previous radio button (and so moves
1331            // to the right).  Seems strange, but we'll match it.
1332            bool forward = (key == "Down" || key == "Right");
1333
1334            // We can only stay within the form's children if the form hasn't been demoted to a leaf because
1335            // of malformed HTML.
1336            Node* n = this;
1337            while ((n = (forward ? n->traverseNextNode() : n->traversePreviousNode()))) {
1338                // Once we encounter a form element, we know we're through.
1339                if (n->hasTagName(formTag))
1340                    break;
1341
1342                // Look for more radio buttons.
1343                if (n->hasTagName(inputTag)) {
1344                    HTMLInputElement* elt = static_cast<HTMLInputElement*>(n);
1345                    if (elt->form() != form())
1346                        break;
1347                    if (n->hasTagName(inputTag)) {
1348                        HTMLInputElement* inputElt = static_cast<HTMLInputElement*>(n);
1349                        if (inputElt->inputType() == RADIO && inputElt->name() == name() && inputElt->isFocusable()) {
1350                            inputElt->setChecked(true);
1351                            document()->setFocusedNode(inputElt);
1352                            inputElt->dispatchSimulatedClick(evt, false, false);
1353                            evt->setDefaultHandled();
1354                            break;
1355                        }
1356                    }
1357                }
1358            }
1359        }
1360    }
1361
1362    if (evt->type() == eventNames().keyupEvent && evt->isKeyboardEvent()) {
1363        bool clickElement = false;
1364
1365        String key = static_cast<KeyboardEvent*>(evt)->keyIdentifier();
1366
1367        if (key == "U+0020") {
1368            switch (inputType()) {
1369                case BUTTON:
1370                case CHECKBOX:
1371                case FILE:
1372                case IMAGE:
1373                case RESET:
1374                case SUBMIT:
1375                    // Simulate mouse click for spacebar for these types of elements.
1376                    // The AppKit already does this for some, but not all, of them.
1377                    clickElement = true;
1378                    break;
1379                case RADIO:
1380                    // If an unselected radio is tabbed into (because the entire group has nothing
1381                    // checked, or because of some explicit .focus() call), then allow space to check it.
1382                    if (!checked())
1383                        clickElement = true;
1384                    break;
1385                case EMAIL:
1386                case HIDDEN:
1387                case ISINDEX:
1388                case NUMBER:
1389                case PASSWORD:
1390                case RANGE:
1391                case SEARCH:
1392                case TELEPHONE:
1393                case TEXT:
1394                case URL:
1395                    break;
1396            }
1397        }
1398
1399        if (clickElement) {
1400            if (active())
1401                dispatchSimulatedClick(evt);
1402            evt->setDefaultHandled();
1403            return;
1404        }
1405    }
1406
1407    if (clickDefaultFormButton) {
1408        if (isSearchField()) {
1409            addSearchResult();
1410            onSearch();
1411        }
1412        // Fire onChange for text fields.
1413        RenderObject* r = renderer();
1414        if (r && r->isTextField() && toRenderTextControl(r)->isEdited()) {
1415            dispatchFormControlChangeEvent();
1416            // Refetch the renderer since arbitrary JS code run during onchange can do anything, including destroying it.
1417            r = renderer();
1418            if (r && r->isTextField())
1419                toRenderTextControl(r)->setEdited(false);
1420        }
1421        // Form may never have been present, or may have been destroyed by the change event.
1422        if (form())
1423            form()->submitClick(evt);
1424        evt->setDefaultHandled();
1425        return;
1426    }
1427
1428    if (evt->isBeforeTextInsertedEvent())
1429        InputElement::handleBeforeTextInsertedEvent(m_data, this, document(), evt);
1430
1431    if (isTextField() && renderer() && (evt->isMouseEvent() || evt->isDragEvent() || evt->isWheelEvent() || evt->type() == eventNames().blurEvent || evt->type() == eventNames().focusEvent))
1432        static_cast<RenderTextControlSingleLine*>(renderer())->forwardEvent(evt);
1433
1434    if (inputType() == RANGE && renderer() && (evt->isMouseEvent() || evt->isDragEvent() || evt->isWheelEvent()))
1435        static_cast<RenderSlider*>(renderer())->forwardEvent(evt);
1436
1437    if (!callBaseClassEarly && !evt->defaultHandled())
1438        HTMLFormControlElementWithState::defaultEventHandler(evt);
1439}
1440
1441bool HTMLInputElement::isURLAttribute(Attribute *attr) const
1442{
1443    return (attr->name() == srcAttr);
1444}
1445
1446String HTMLInputElement::defaultValue() const
1447{
1448    return getAttribute(valueAttr);
1449}
1450
1451void HTMLInputElement::setDefaultValue(const String &value)
1452{
1453    setAttribute(valueAttr, value);
1454}
1455
1456bool HTMLInputElement::defaultChecked() const
1457{
1458    return !getAttribute(checkedAttr).isNull();
1459}
1460
1461void HTMLInputElement::setDefaultChecked(bool defaultChecked)
1462{
1463    setAttribute(checkedAttr, defaultChecked ? "" : 0);
1464}
1465
1466void HTMLInputElement::setDefaultName(const AtomicString& name)
1467{
1468    m_data.setName(name);
1469}
1470
1471String HTMLInputElement::accept() const
1472{
1473    return getAttribute(acceptAttr);
1474}
1475
1476void HTMLInputElement::setAccept(const String &value)
1477{
1478    setAttribute(acceptAttr, value);
1479}
1480
1481String HTMLInputElement::accessKey() const
1482{
1483    return getAttribute(accesskeyAttr);
1484}
1485
1486void HTMLInputElement::setAccessKey(const String &value)
1487{
1488    setAttribute(accesskeyAttr, value);
1489}
1490
1491String HTMLInputElement::align() const
1492{
1493    return getAttribute(alignAttr);
1494}
1495
1496void HTMLInputElement::setAlign(const String &value)
1497{
1498    setAttribute(alignAttr, value);
1499}
1500
1501String HTMLInputElement::alt() const
1502{
1503    return getAttribute(altAttr);
1504}
1505
1506void HTMLInputElement::setAlt(const String &value)
1507{
1508    setAttribute(altAttr, value);
1509}
1510
1511int HTMLInputElement::maxLength() const
1512{
1513    return m_data.maxLength();
1514}
1515
1516void HTMLInputElement::setMaxLength(int _maxLength)
1517{
1518    setAttribute(maxlengthAttr, String::number(_maxLength));
1519}
1520
1521bool HTMLInputElement::multiple() const
1522{
1523    return !getAttribute(multipleAttr).isNull();
1524}
1525
1526void HTMLInputElement::setMultiple(bool multiple)
1527{
1528    setAttribute(multipleAttr, multiple ? "" : 0);
1529}
1530
1531void HTMLInputElement::setSize(unsigned _size)
1532{
1533    setAttribute(sizeAttr, String::number(_size));
1534}
1535
1536KURL HTMLInputElement::src() const
1537{
1538    return document()->completeURL(getAttribute(srcAttr));
1539}
1540
1541void HTMLInputElement::setSrc(const String &value)
1542{
1543    setAttribute(srcAttr, value);
1544}
1545
1546String HTMLInputElement::useMap() const
1547{
1548    return getAttribute(usemapAttr);
1549}
1550
1551void HTMLInputElement::setUseMap(const String &value)
1552{
1553    setAttribute(usemapAttr, value);
1554}
1555
1556void HTMLInputElement::setAutofilled(bool b)
1557{
1558    if (b == m_autofilled)
1559        return;
1560
1561    m_autofilled = b;
1562    setNeedsStyleRecalc();
1563}
1564
1565FileList* HTMLInputElement::files()
1566{
1567    if (inputType() != FILE)
1568        return 0;
1569    return m_fileList.get();
1570}
1571
1572String HTMLInputElement::constrainValue(const String& proposedValue) const
1573{
1574    return InputElement::constrainValue(this, proposedValue, m_data.maxLength());
1575}
1576
1577bool HTMLInputElement::needsActivationCallback()
1578{
1579    return inputType() == PASSWORD || m_autocomplete == Off;
1580}
1581
1582void HTMLInputElement::registerForActivationCallbackIfNeeded()
1583{
1584    if (needsActivationCallback())
1585        document()->registerForDocumentActivationCallbacks(this);
1586}
1587
1588void HTMLInputElement::unregisterForActivationCallbackIfNeeded()
1589{
1590    if (!needsActivationCallback())
1591        document()->unregisterForDocumentActivationCallbacks(this);
1592}
1593
1594void HTMLInputElement::cacheSelection(int start, int end)
1595{
1596    m_data.setCachedSelectionStart(start);
1597    m_data.setCachedSelectionEnd(end);
1598}
1599
1600void HTMLInputElement::addSearchResult()
1601{
1602    ASSERT(isSearchField());
1603    if (renderer())
1604        static_cast<RenderTextControlSingleLine*>(renderer())->addSearchResult();
1605}
1606
1607void HTMLInputElement::onSearch()
1608{
1609    ASSERT(isSearchField());
1610    if (renderer())
1611        static_cast<RenderTextControlSingleLine*>(renderer())->stopSearchEventTimer();
1612    dispatchEvent(eventNames().searchEvent, true, false);
1613}
1614
1615VisibleSelection HTMLInputElement::selection() const
1616{
1617   if (!renderer() || !isTextField() || m_data.cachedSelectionStart() == -1 || m_data.cachedSelectionEnd() == -1)
1618        return VisibleSelection();
1619   return toRenderTextControl(renderer())->selection(m_data.cachedSelectionStart(), m_data.cachedSelectionEnd());
1620}
1621
1622void HTMLInputElement::documentDidBecomeActive()
1623{
1624    ASSERT(needsActivationCallback());
1625    reset();
1626}
1627
1628void HTMLInputElement::willMoveToNewOwnerDocument()
1629{
1630    // Always unregister for cache callbacks when leaving a document, even if we would otherwise like to be registered
1631    if (needsActivationCallback())
1632        document()->unregisterForDocumentActivationCallbacks(this);
1633
1634    document()->checkedRadioButtons().removeButton(this);
1635
1636    HTMLFormControlElementWithState::willMoveToNewOwnerDocument();
1637}
1638
1639void HTMLInputElement::didMoveToNewOwnerDocument()
1640{
1641    registerForActivationCallbackIfNeeded();
1642
1643    HTMLFormControlElementWithState::didMoveToNewOwnerDocument();
1644}
1645
1646void HTMLInputElement::addSubresourceAttributeURLs(ListHashSet<KURL>& urls) const
1647{
1648    HTMLFormControlElementWithState::addSubresourceAttributeURLs(urls);
1649
1650    addSubresourceURL(urls, src());
1651}
1652
1653bool HTMLInputElement::willValidate() const
1654{
1655    // FIXME: This shall check for new WF2 input types too
1656    return HTMLFormControlElementWithState::willValidate() && inputType() != HIDDEN &&
1657           inputType() != BUTTON && inputType() != RESET;
1658}
1659
1660bool HTMLInputElement::placeholderShouldBeVisible() const
1661{
1662    return m_data.placeholderShouldBeVisible();
1663}
1664
1665} // namespace
1666