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