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