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