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