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