2006-12-18 Kirby White <KWhiteRight@gmail.com>
[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         // Changes to hidden values don't require re-rendering.
1074         if (m_type != HIDDEN)
1075             setChanged();
1076     } else
1077         setAttribute(valueAttr, constrainValue(value));
1078     
1079     // Restore a caret at the starting point of the old selection.
1080     // This matches Safari 2.0 behavior.
1081     if (isTextField() && document()->focusedNode() == this && cachedSelStart >= 0) {
1082         ASSERT(cachedSelEnd >= 0);
1083         setSelectionRange(cachedSelStart, cachedSelStart);
1084     }
1085 }
1086
1087 void HTMLInputElement::setValueFromRenderer(const String& value)
1088 {
1089     // Renderer and our event handler are responsible for constraining values.
1090     ASSERT(value == constrainValue(value) || constrainValue(value).isEmpty());
1091
1092     // Workaround for bug where trailing \n is included in the result of textContent.
1093     // The assert macro above may also be simplified to:  value == constrainValue(value)
1094     // http://bugs.webkit.org/show_bug.cgi?id=9661
1095     if (value == "\n")
1096         m_value = "";
1097     else
1098         m_value = value;
1099
1100     setValueMatchesRenderer();
1101
1102     // Fire the "input" DOM event.
1103     dispatchHTMLEvent(inputEvent, true, false);
1104 }
1105
1106 bool HTMLInputElement::storesValueSeparateFromAttribute() const
1107 {
1108     switch (inputType()) {
1109         case BUTTON:
1110         case CHECKBOX:
1111         case FILE:
1112         case IMAGE:
1113         case RADIO:
1114         case RANGE:
1115         case RESET:
1116         case SUBMIT:
1117             return false;
1118         case HIDDEN:
1119         case ISINDEX:
1120         case PASSWORD:
1121         case SEARCH:
1122         case TEXT:
1123             return true;
1124     }
1125     return false;
1126 }
1127
1128 void* HTMLInputElement::preDispatchEventHandler(Event *evt)
1129 {
1130     // preventDefault or "return false" are used to reverse the automatic checking/selection we do here.
1131     // This result gives us enough info to perform the "undo" in postDispatch of the action we take here.
1132     void* result = 0; 
1133     if ((inputType() == CHECKBOX || inputType() == RADIO) && evt->isMouseEvent()
1134             && evt->type() == clickEvent && static_cast<MouseEvent*>(evt)->button() == 0) {
1135         if (inputType() == CHECKBOX) {
1136             // As a way to store the state, we return 0 if we were unchecked, 1 if we were checked, and 2 for
1137             // indeterminate.
1138             if (indeterminate()) {
1139                 result = (void*)0x2;
1140                 setIndeterminate(false);
1141             } else {
1142                 if (checked())
1143                     result = (void*)0x1;
1144                 setChecked(!checked(), true);
1145             }
1146         } else {
1147             // For radio buttons, store the current selected radio object.
1148             if (name().isEmpty() || checked())
1149                 return 0; // Unnamed radio buttons dont get checked. Checked buttons just stay checked.
1150                           // FIXME: Need to learn to work without a form.
1151
1152             // We really want radio groups to end up in sane states, i.e., to have something checked.
1153             // Therefore if nothing is currently selected, we won't allow this action to be "undone", since
1154             // we want some object in the radio group to actually get selected.
1155             HTMLInputElement* currRadio = document()->checkedRadioButtonForGroup(name().impl(), form());
1156             if (currRadio) {
1157                 // We have a radio button selected that is not us.  Cache it in our result field and ref it so
1158                 // that it can't be destroyed.
1159                 currRadio->ref();
1160                 result = currRadio;
1161             }
1162             setChecked(true, true);
1163         }
1164     }
1165     return result;
1166 }
1167
1168 void HTMLInputElement::postDispatchEventHandler(Event *evt, void* data)
1169 {
1170     if ((inputType() == CHECKBOX || inputType() == RADIO) && evt->isMouseEvent()
1171             && evt->type() == clickEvent && static_cast<MouseEvent*>(evt)->button() == 0) {
1172         if (inputType() == CHECKBOX) {
1173             // Reverse the checking we did in preDispatch.
1174             if (evt->defaultPrevented() || evt->defaultHandled()) {
1175                 if (data == (void*)0x2)
1176                     setIndeterminate(true);
1177                 else
1178                     setChecked(data);
1179             }
1180         } else if (data) {
1181             HTMLInputElement* input = static_cast<HTMLInputElement*>(data);
1182             if (evt->defaultPrevented() || evt->defaultHandled()) {
1183                 // Restore the original selected radio button if possible.
1184                 // Make sure it is still a radio button and only do the restoration if it still
1185                 // belongs to our group.
1186                 if (input->form() == form() && input->inputType() == RADIO && input->name() == name()) {
1187                     // Ok, the old radio button is still in our form and in our group and is still a 
1188                     // radio button, so it's safe to restore selection to it.
1189                     input->setChecked(true);
1190                 }
1191             }
1192             input->deref();
1193         }
1194     }
1195 }
1196
1197 void HTMLInputElement::defaultEventHandler(Event* evt)
1198 {
1199     if (inputType() == IMAGE && evt->isMouseEvent() && evt->type() == clickEvent) {
1200         // record the mouse position for when we get the DOMActivate event
1201         MouseEvent* me = static_cast<MouseEvent*>(evt);
1202         // FIXME: We could just call offsetX() and offsetY() on the event,
1203         // but that's currently broken, so for now do the computation here.
1204         if (me->isSimulated() || !renderer()) {
1205             xPos = 0;
1206             yPos = 0;
1207         } else {
1208             int offsetX, offsetY;
1209             renderer()->absolutePosition(offsetX, offsetY);
1210             xPos = me->pageX() - offsetX;
1211             yPos = me->pageY() - offsetY;
1212         }
1213         me->setDefaultHandled();
1214     }
1215
1216     // DOMActivate events cause the input to be "activated" - in the case of image and submit inputs, this means
1217     // actually submitting the form. For reset inputs, the form is reset. These events are sent when the user clicks
1218     // on the element, or presses enter while it is the active element. JavaScript code wishing to activate the element
1219     // must dispatch a DOMActivate event - a click event will not do the job.
1220     if (evt->type() == DOMActivateEvent && !disabled()) {
1221         if (inputType() == IMAGE || inputType() == SUBMIT || inputType() == RESET) {
1222             if (!form())
1223                 return;
1224             if (inputType() == RESET)
1225                 form()->reset();
1226             else {
1227                 m_activeSubmit = true;
1228                 if (!form()->prepareSubmit(evt)) {
1229                     xPos = 0;
1230                     yPos = 0;
1231                 }
1232                 m_activeSubmit = false;
1233             }
1234         } else if (inputType() == FILE && renderer())
1235             static_cast<RenderFileUploadControl*>(renderer())->click();
1236     }
1237
1238     // Use key press event here since sending simulated mouse events
1239     // on key down blocks the proper sending of the key press event.
1240     if (evt->type() == keypressEvent && evt->isKeyboardEvent()) {
1241         bool clickElement = false;
1242         bool clickDefaultFormButton = false;
1243     
1244         if (isTextField() && document()->frame()
1245                 && document()->frame()->doTextFieldCommandFromEvent(this, static_cast<KeyboardEvent*>(evt))) {
1246             evt->setDefaultHandled();
1247             return;
1248         }
1249
1250         String key = static_cast<KeyboardEvent *>(evt)->keyIdentifier();
1251
1252         if (key == "U+000020") {
1253             switch (inputType()) {
1254                 case BUTTON:
1255                 case CHECKBOX:
1256                 case FILE:
1257                 case IMAGE:
1258                 case RESET:
1259                 case SUBMIT:
1260                     // Simulate mouse click for spacebar for these types of elements.
1261                     // The AppKit already does this for some, but not all, of them.
1262                     clickElement = true;
1263                     break;
1264                 case RADIO:
1265                     // If an unselected radio is tabbed into (because the entire group has nothing
1266                     // checked, or because of some explicit .focus() call), then allow space to check it.
1267                     if (!checked())
1268                         clickElement = true;
1269                     break;
1270                 case HIDDEN:
1271                 case ISINDEX:
1272                 case PASSWORD:
1273                 case RANGE:
1274                 case SEARCH:
1275                 case TEXT:
1276                     break;
1277             }
1278         }
1279
1280         if (key == "Enter") {
1281             switch (inputType()) {
1282                 case BUTTON:
1283                 case CHECKBOX:
1284                 case HIDDEN:
1285                 case RANGE:
1286                     // Simulate mouse click on the default form button for enter for these types of elements.
1287                     clickDefaultFormButton = true;
1288                 case ISINDEX:
1289                 case PASSWORD:
1290                 case SEARCH:
1291                 case TEXT:
1292                     if (!document()->frame()->eventHandler()->inputManagerHasMarkedText())
1293                         // Simulate mouse click on the default form button for enter for these types of elements.
1294                         clickDefaultFormButton = true;
1295                     break;
1296                 case FILE:
1297                 case IMAGE:
1298                 case RESET:
1299                 case SUBMIT:
1300                     // Simulate mouse click for enter for these types of elements.
1301                     clickElement = true;
1302                     break;
1303                 case RADIO:
1304                     break; // Don't do anything for enter on a radio button.
1305             }
1306         }
1307
1308         if (inputType() == RADIO && (key == "Up" || key == "Down" || key == "Left" || key == "Right")) {
1309             // Left and up mean "previous radio button".
1310             // Right and down mean "next radio button".
1311             // Tested in WinIE, and even for RTL, left still means previous radio button (and so moves
1312             // to the right).  Seems strange, but we'll match it.
1313             bool forward = (key == "Down" || key == "Right");
1314             
1315             // We can only stay within the form's children if the form hasn't been demoted to a leaf because
1316             // of malformed HTML.
1317             Node* n = this;
1318             while ((n = (forward ? n->traverseNextNode() : n->traversePreviousNode()))) {
1319                 // Once we encounter a form element, we know we're through.
1320                 if (n->hasTagName(formTag))
1321                     break;
1322                     
1323                 // Look for more radio buttons.
1324                 if (n->hasTagName(inputTag)) {
1325                     HTMLInputElement* elt = static_cast<HTMLInputElement*>(n);
1326                     if (elt->form() != form())
1327                         break;
1328                     if (n->hasTagName(inputTag)) {
1329                         HTMLInputElement* inputElt = static_cast<HTMLInputElement*>(n);
1330                         if (inputElt->inputType() == RADIO && inputElt->name() == name() &&
1331                             inputElt->isFocusable()) {
1332                             inputElt->setChecked(true);
1333                             document()->setFocusedNode(inputElt);
1334                             inputElt->dispatchSimulatedClick(evt, false, false);
1335                             evt->setDefaultHandled();
1336                             break;
1337                         }
1338                     }
1339                 }
1340             }
1341         }
1342
1343         if (clickElement) {
1344             dispatchSimulatedClick(evt);
1345             evt->setDefaultHandled();
1346         } else if (clickDefaultFormButton) {
1347             if (isSearchField())
1348                 addSearchResult();
1349             blur();
1350             // Form may never have been present, or may have been destroyed by the blur event.
1351             if (form()) {
1352                 form()->submitClick(evt);
1353                 evt->setDefaultHandled();
1354             } else if (inputType() != SEARCH) {
1355                 evt->setDefaultHandled();
1356             }
1357         }
1358     }
1359
1360     if (evt->isBeforeTextInsertedEvent()) {
1361         // Make sure that the text to be inserted will not violate the maxLength.
1362         int oldLen = numGraphemeClusters(value().impl());
1363         ASSERT(oldLen <= maxLength());
1364         int selectionLen = numGraphemeClusters(document()->frame()->selectionController()->toString().impl());
1365         ASSERT(oldLen >= selectionLen);
1366         int maxNewLen = maxLength() - (oldLen - selectionLen);
1367
1368         // Truncate the inserted text to avoid violating the maxLength and other constraints.
1369         BeforeTextInsertedEvent* textEvent = static_cast<BeforeTextInsertedEvent*>(evt);
1370         textEvent->setText(constrainValue(textEvent->text(), maxNewLen));
1371     }
1372     
1373     if (isTextField() && renderer() && (evt->isMouseEvent() || evt->isDragEvent() || evt->isWheelEvent() || evt->type() == blurEvent || evt->type() == focusEvent))
1374         static_cast<RenderTextControl*>(renderer())->forwardEvent(evt);
1375
1376     if (inputType() == RANGE && renderer()) {
1377         RenderSlider* slider = static_cast<RenderSlider*>(renderer());
1378         if (evt->isMouseEvent() && evt->type() == mousedownEvent) {
1379             MouseEvent* mEvt = static_cast<MouseEvent*>(evt);
1380             if (!slider->mouseEventIsInThumb(mEvt)) {
1381                 slider->setValueForPosition(slider->positionForOffset(IntPoint(mEvt->offsetX(), mEvt->offsetY())));
1382             }
1383         }
1384         if (evt->isMouseEvent() || evt->isDragEvent() || evt->isWheelEvent())
1385             slider->forwardEvent(evt);
1386     }
1387
1388     if (!evt->defaultHandled())
1389         HTMLGenericFormElement::defaultEventHandler(evt);
1390 }
1391
1392 bool HTMLInputElement::isURLAttribute(Attribute *attr) const
1393 {
1394     return (attr->name() == srcAttr);
1395 }
1396
1397 String HTMLInputElement::defaultValue() const
1398 {
1399     return getAttribute(valueAttr);
1400 }
1401
1402 void HTMLInputElement::setDefaultValue(const String &value)
1403 {
1404     setAttribute(valueAttr, value);
1405 }
1406
1407 bool HTMLInputElement::defaultChecked() const
1408 {
1409     return !getAttribute(checkedAttr).isNull();
1410 }
1411
1412 void HTMLInputElement::setDefaultChecked(bool defaultChecked)
1413 {
1414     setAttribute(checkedAttr, defaultChecked ? "" : 0);
1415 }
1416
1417 String HTMLInputElement::accept() const
1418 {
1419     return getAttribute(acceptAttr);
1420 }
1421
1422 void HTMLInputElement::setAccept(const String &value)
1423 {
1424     setAttribute(acceptAttr, value);
1425 }
1426
1427 String HTMLInputElement::accessKey() const
1428 {
1429     return getAttribute(accesskeyAttr);
1430 }
1431
1432 void HTMLInputElement::setAccessKey(const String &value)
1433 {
1434     setAttribute(accesskeyAttr, value);
1435 }
1436
1437 String HTMLInputElement::align() const
1438 {
1439     return getAttribute(alignAttr);
1440 }
1441
1442 void HTMLInputElement::setAlign(const String &value)
1443 {
1444     setAttribute(alignAttr, value);
1445 }
1446
1447 String HTMLInputElement::alt() const
1448 {
1449     return getAttribute(altAttr);
1450 }
1451
1452 void HTMLInputElement::setAlt(const String &value)
1453 {
1454     setAttribute(altAttr, value);
1455 }
1456
1457 void HTMLInputElement::setMaxLength(int _maxLength)
1458 {
1459     setAttribute(maxlengthAttr, String::number(_maxLength));
1460 }
1461
1462 void HTMLInputElement::setSize(unsigned _size)
1463 {
1464     setAttribute(sizeAttr, String::number(_size));
1465 }
1466
1467 String HTMLInputElement::src() const
1468 {
1469     return document()->completeURL(getAttribute(srcAttr));
1470 }
1471
1472 void HTMLInputElement::setSrc(const String &value)
1473 {
1474     setAttribute(srcAttr, value);
1475 }
1476
1477 String HTMLInputElement::useMap() const
1478 {
1479     return getAttribute(usemapAttr);
1480 }
1481
1482 void HTMLInputElement::setUseMap(const String &value)
1483 {
1484     setAttribute(usemapAttr, value);
1485 }
1486
1487 String HTMLInputElement::constrainValue(const String& proposedValue) const
1488 {
1489     return constrainValue(proposedValue, m_maxLen);
1490 }
1491
1492 void HTMLInputElement::recheckValue()
1493 {
1494     String oldValue = value();
1495     String newValue = constrainValue(oldValue);
1496     if (newValue != oldValue)
1497         setValue(newValue);
1498 }
1499
1500 String HTMLInputElement::constrainValue(const String& proposedValue, int maxLen) const
1501 {
1502     if (isTextField()) {
1503         StringImpl* s = proposedValue.impl();
1504         int newLen = numCharactersInGraphemeClusters(s, maxLen);
1505         for (int i = 0; i < newLen; ++i)
1506             if ((*s)[i] < ' ') {
1507                 newLen = i;
1508                 break;
1509             }
1510         if (newLen < static_cast<int>(proposedValue.length()))
1511             return proposedValue.substring(0, newLen);
1512     }
1513     return proposedValue;
1514 }
1515
1516 void HTMLInputElement::addSearchResult()
1517 {
1518     ASSERT(isSearchField());
1519     if (renderer())
1520         static_cast<RenderTextControl*>(renderer())->addSearchResult();
1521 }
1522     
1523 } // namespace