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