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