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