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