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 "AXObjectCache.h"
30 #include "CSSPropertyNames.h"
31 #include "ChromeClient.h"
32 #include "DateComponents.h"
33 #include "Document.h"
34 #include "Editor.h"
35 #include "Event.h"
36 #include "EventHandler.h"
37 #include "EventNames.h"
38 #include "ExceptionCode.h"
39 #include "File.h"
40 #include "FileList.h"
41 #include "FocusController.h"
42 #include "FormDataList.h"
43 #include "Frame.h"
44 #include "HTMLDataListElement.h"
45 #include "HTMLFormElement.h"
46 #include "HTMLImageLoader.h"
47 #include "HTMLNames.h"
48 #include "HTMLOptionElement.h"
49 #include "ScriptEventListener.h"
50 #include "KeyboardEvent.h"
51 #include "LocalizedStrings.h"
52 #include "MappedAttribute.h"
53 #include "MouseEvent.h"
54 #include "Page.h"
55 #include "RegularExpression.h"
56 #include "RenderButton.h"
57 #include "RenderFileUploadControl.h"
58 #include "RenderImage.h"
59 #include "RenderSlider.h"
60 #include "RenderText.h"
61 #include "RenderTextControlSingleLine.h"
62 #include "RenderTheme.h"
63 #include "StringHash.h"
64 #include "TextEvent.h"
65 #ifdef ANDROID_ACCEPT_CHANGES_TO_FOCUSED_TEXTFIELDS
66 #include "WebViewCore.h"
67 #endif
68 #include <wtf/HashMap.h>
69 #include <wtf/MathExtras.h>
70 #include <wtf/StdLibExtras.h>
71 #include <wtf/dtoa.h>
72
73 using namespace std;
74
75 namespace WebCore {
76
77 using namespace HTMLNames;
78
79 const int maxSavedResults = 256;
80
81 // Constant values for getAllowedValueStep().
82 static const double dateDefaultStep = 1.0;
83 static const double dateStepScaleFactor = 86400000.0;
84 static const double dateTimeDefaultStep = 60.0;
85 static const double dateTimeStepScaleFactor = 1000.0;
86 static const double monthDefaultStep = 1.0;
87 static const double monthStepScaleFactor = 1.0;
88 static const double numberDefaultStep = 1.0;
89 static const double numberStepScaleFactor = 1.0;
90 static const double timeDefaultStep = 60.0;
91 static const double timeStepScaleFactor = 1000.0;
92 static const double weekDefaultStep = 1.0;
93 static const double weekStepScaleFactor = 604800000.0;
94
95 // Constant values for minimum().
96 static const double dateDefaultMinimum = -12219292800000.0; // This means 1582-10-15T00:00Z.
97 static const double dateTimeDefaultMinimum = -12219292800000.0; // ditto.
98 static const double monthDefaultMinimum = (1582.0 - 1970) * 12 + 10 - 1; // 1582-10
99 static const double numberDefaultMinimum = -DBL_MAX;
100 static const double rangeDefaultMinimum = 0.0;
101 static const double timeDefaultMinimum = 0.0; // 00:00:00.000
102 static const double weekDefaultMinimum = -12212380800000.0; // 1583-01-03, the first Monday of 1583.
103
104 // Constant values for maximum().
105 static const double dateDefaultMaximum = DBL_MAX;
106 static const double dateTimeDefaultMaximum = DBL_MAX;
107 // DateComponents::m_year can't represent a year greater than INT_MAX.
108 static const double monthDefaultMaximum = (INT_MAX - 1970) * 12.0 + 12 - 1;
109 static const double numberDefaultMaximum = DBL_MAX;
110 static const double rangeDefaultMaximum = 100.0;
111 static const double timeDefaultMaximum = 86399999.0; // 23:59:59.999
112 static const double weekDefaultMaximum = DBL_MAX;
113
114 static const double defaultStepBase = 0.0;
115 static const double weekDefaultStepBase = -259200000.0; // The first day of 1970-W01.
116
117 static const double msecPerMinute = 60 * 1000;
118 static const double msecPerSecond = 1000;
119
HTMLInputElement(const QualifiedName & tagName,Document * doc,HTMLFormElement * f)120 HTMLInputElement::HTMLInputElement(const QualifiedName& tagName, Document* doc, HTMLFormElement* f)
121 : HTMLTextFormControlElement(tagName, doc, f)
122 , m_xPos(0)
123 , m_yPos(0)
124 , m_maxResults(-1)
125 , m_type(TEXT)
126 , m_checked(false)
127 , m_defaultChecked(false)
128 , m_useDefaultChecked(true)
129 , m_indeterminate(false)
130 , m_haveType(false)
131 , m_activeSubmit(false)
132 , m_autocomplete(Uninitialized)
133 , m_autofilled(false)
134 , m_inited(false)
135 {
136 ASSERT(hasTagName(inputTag) || hasTagName(isindexTag));
137 }
138
~HTMLInputElement()139 HTMLInputElement::~HTMLInputElement()
140 {
141 if (needsActivationCallback())
142 document()->unregisterForDocumentActivationCallbacks(this);
143
144 document()->checkedRadioButtons().removeButton(this);
145
146 // Need to remove this from the form while it is still an HTMLInputElement,
147 // so can't wait for the base class's destructor to do it.
148 removeFromForm();
149 }
150
formControlName() const151 const AtomicString& HTMLInputElement::formControlName() const
152 {
153 return m_data.name();
154 }
155
autoComplete() const156 bool HTMLInputElement::autoComplete() const
157 {
158 if (m_autocomplete != Uninitialized)
159 return m_autocomplete == On;
160
161 // Assuming we're still in a Form, respect the Form's setting
162 if (HTMLFormElement* form = this->form())
163 return form->autoComplete();
164
165 // The default is true
166 return true;
167 }
168
valueMissing() const169 bool HTMLInputElement::valueMissing() const
170 {
171 if (!isRequiredFormControl() || readOnly() || disabled())
172 return false;
173
174 switch (inputType()) {
175 case DATE:
176 case DATETIME:
177 case DATETIMELOCAL:
178 case EMAIL:
179 case FILE:
180 case MONTH:
181 case NUMBER:
182 case PASSWORD:
183 case SEARCH:
184 case TELEPHONE:
185 case TEXT:
186 case TIME:
187 case URL:
188 case WEEK:
189 return value().isEmpty();
190 case CHECKBOX:
191 return !checked();
192 case RADIO:
193 return !document()->checkedRadioButtons().checkedButtonForGroup(name());
194 case COLOR:
195 return false;
196 case BUTTON:
197 case HIDDEN:
198 case IMAGE:
199 case ISINDEX:
200 case RANGE:
201 case RESET:
202 case SUBMIT:
203 break;
204 }
205
206 ASSERT_NOT_REACHED();
207 return false;
208 }
209
patternMismatch() const210 bool HTMLInputElement::patternMismatch() const
211 {
212 switch (inputType()) {
213 case BUTTON:
214 case CHECKBOX:
215 case COLOR:
216 case DATE:
217 case DATETIME:
218 case DATETIMELOCAL:
219 case FILE:
220 case HIDDEN:
221 case IMAGE:
222 case ISINDEX:
223 case MONTH:
224 case NUMBER:
225 case RADIO:
226 case RANGE:
227 case RESET:
228 case SUBMIT:
229 case TIME:
230 case WEEK:
231 return false;
232 case EMAIL:
233 case PASSWORD:
234 case SEARCH:
235 case TELEPHONE:
236 case TEXT:
237 case URL:
238 const AtomicString& pattern = getAttribute(patternAttr);
239 String value = this->value();
240
241 // Empty values can't be mismatched
242 if (pattern.isEmpty() || value.isEmpty())
243 return false;
244
245 RegularExpression patternRegExp(pattern, TextCaseSensitive);
246 int matchLength = 0;
247 int valueLength = value.length();
248 int matchOffset = patternRegExp.match(value, 0, &matchLength);
249
250 return matchOffset != 0 || matchLength != valueLength;
251 }
252
253 ASSERT_NOT_REACHED();
254 return false;
255 }
256
tooLong() const257 bool HTMLInputElement::tooLong() const
258 {
259 switch (inputType()) {
260 case EMAIL:
261 case PASSWORD:
262 case SEARCH:
263 case TELEPHONE:
264 case TEXT:
265 case URL: {
266 int max = maxLength();
267 if (max < 0)
268 return false;
269 // Return false for the default value even if it is longer than maxLength.
270 bool userEdited = !m_data.value().isNull();
271 if (!userEdited)
272 return false;
273 return value().numGraphemeClusters() > static_cast<unsigned>(max);
274 }
275 case BUTTON:
276 case CHECKBOX:
277 case COLOR:
278 case DATE:
279 case DATETIME:
280 case DATETIMELOCAL:
281 case FILE:
282 case HIDDEN:
283 case IMAGE:
284 case ISINDEX:
285 case MONTH:
286 case NUMBER:
287 case RADIO:
288 case RANGE:
289 case RESET:
290 case SUBMIT:
291 case TIME:
292 case WEEK:
293 return false;
294 }
295 ASSERT_NOT_REACHED();
296 return false;
297 }
298
rangeUnderflow() const299 bool HTMLInputElement::rangeUnderflow() const
300 {
301 const double nan = numeric_limits<double>::quiet_NaN();
302 switch (inputType()) {
303 case DATE:
304 case DATETIME:
305 case DATETIMELOCAL:
306 case MONTH:
307 case NUMBER:
308 case RANGE:
309 case TIME:
310 case WEEK: {
311 double doubleValue = parseToDouble(value(), nan);
312 return isfinite(doubleValue) && doubleValue < minimum();
313 }
314 case BUTTON:
315 case CHECKBOX:
316 case COLOR:
317 case EMAIL:
318 case FILE:
319 case HIDDEN:
320 case IMAGE:
321 case ISINDEX:
322 case PASSWORD:
323 case RADIO:
324 case RESET:
325 case SEARCH:
326 case SUBMIT:
327 case TELEPHONE:
328 case TEXT:
329 case URL:
330 break;
331 }
332 return false;
333 }
334
rangeOverflow() const335 bool HTMLInputElement::rangeOverflow() const
336 {
337 const double nan = numeric_limits<double>::quiet_NaN();
338 switch (inputType()) {
339 case DATE:
340 case DATETIME:
341 case DATETIMELOCAL:
342 case MONTH:
343 case NUMBER:
344 case RANGE:
345 case TIME:
346 case WEEK: {
347 double doubleValue = parseToDouble(value(), nan);
348 return isfinite(doubleValue) && doubleValue > maximum();
349 }
350 case BUTTON:
351 case CHECKBOX:
352 case COLOR:
353 case EMAIL:
354 case FILE:
355 case HIDDEN:
356 case IMAGE:
357 case ISINDEX:
358 case PASSWORD:
359 case RADIO:
360 case RESET:
361 case SEARCH:
362 case SUBMIT:
363 case TELEPHONE:
364 case TEXT:
365 case URL:
366 break;
367 }
368 return false;
369 }
370
minimum() const371 double HTMLInputElement::minimum() const
372 {
373 switch (inputType()) {
374 case DATE:
375 return parseToDouble(getAttribute(minAttr), dateDefaultMinimum);
376 case DATETIME:
377 case DATETIMELOCAL:
378 return parseToDouble(getAttribute(minAttr), dateTimeDefaultMinimum);
379 case MONTH:
380 return parseToDouble(getAttribute(minAttr), monthDefaultMinimum);
381 case NUMBER:
382 return parseToDouble(getAttribute(minAttr), numberDefaultMinimum);
383 case RANGE:
384 return parseToDouble(getAttribute(minAttr), rangeDefaultMinimum);
385 case TIME:
386 return parseToDouble(getAttribute(minAttr), timeDefaultMinimum);
387 case WEEK:
388 return parseToDouble(getAttribute(minAttr), weekDefaultMinimum);
389 case BUTTON:
390 case CHECKBOX:
391 case COLOR:
392 case EMAIL:
393 case FILE:
394 case HIDDEN:
395 case IMAGE:
396 case ISINDEX:
397 case PASSWORD:
398 case RADIO:
399 case RESET:
400 case SEARCH:
401 case SUBMIT:
402 case TELEPHONE:
403 case TEXT:
404 case URL:
405 break;
406 }
407 ASSERT_NOT_REACHED();
408 return 0;
409 }
410
maximum() const411 double HTMLInputElement::maximum() const
412 {
413 switch (inputType()) {
414 case DATE:
415 return parseToDouble(getAttribute(maxAttr), dateDefaultMaximum);
416 case DATETIME:
417 case DATETIMELOCAL:
418 return parseToDouble(getAttribute(maxAttr), dateTimeDefaultMaximum);
419 case MONTH:
420 return parseToDouble(getAttribute(maxAttr), monthDefaultMaximum);
421 case NUMBER:
422 return parseToDouble(getAttribute(maxAttr), numberDefaultMaximum);
423 case RANGE: {
424 double max = parseToDouble(getAttribute(maxAttr), rangeDefaultMaximum);
425 // A remedy for the inconsistent min/max values for RANGE.
426 // Sets the maximum to the default or the minimum value.
427 double min = minimum();
428 if (max < min)
429 max = std::max(min, rangeDefaultMaximum);
430 return max;
431 }
432 case TIME:
433 return parseToDouble(getAttribute(maxAttr), timeDefaultMaximum);
434 case WEEK:
435 return parseToDouble(getAttribute(maxAttr), weekDefaultMaximum);
436 case BUTTON:
437 case CHECKBOX:
438 case COLOR:
439 case EMAIL:
440 case FILE:
441 case HIDDEN:
442 case IMAGE:
443 case ISINDEX:
444 case PASSWORD:
445 case RADIO:
446 case RESET:
447 case SEARCH:
448 case SUBMIT:
449 case TELEPHONE:
450 case TEXT:
451 case URL:
452 break;
453 }
454 ASSERT_NOT_REACHED();
455 return 0;
456 }
457
stepBase() const458 double HTMLInputElement::stepBase() const
459 {
460 switch (inputType()) {
461 case RANGE:
462 return minimum();
463 case DATE:
464 case DATETIME:
465 case DATETIMELOCAL:
466 case MONTH:
467 case NUMBER:
468 case TIME:
469 return parseToDouble(getAttribute(minAttr), defaultStepBase);
470 case WEEK:
471 return parseToDouble(getAttribute(minAttr), weekDefaultStepBase);
472 case BUTTON:
473 case CHECKBOX:
474 case COLOR:
475 case EMAIL:
476 case FILE:
477 case HIDDEN:
478 case IMAGE:
479 case ISINDEX:
480 case PASSWORD:
481 case RADIO:
482 case RESET:
483 case SEARCH:
484 case SUBMIT:
485 case TELEPHONE:
486 case TEXT:
487 case URL:
488 break;
489 }
490 ASSERT_NOT_REACHED();
491 return 0.0;
492 }
493
stepMismatch() const494 bool HTMLInputElement::stepMismatch() const
495 {
496 double step;
497 if (!getAllowedValueStep(&step))
498 return false;
499 switch (inputType()) {
500 case RANGE:
501 // stepMismatch doesn't occur for RANGE. RenderSlider guarantees the
502 // value matches to step.
503 return false;
504 case NUMBER: {
505 double doubleValue;
506 if (!formStringToDouble(value(), &doubleValue))
507 return false;
508 doubleValue = fabs(doubleValue - stepBase());
509 if (isinf(doubleValue))
510 return false;
511 // double's fractional part size is DBL_MAN_DIG-bit. If the current
512 // value is greater than step*2^DBL_MANT_DIG, the following fmod() makes
513 // no sense.
514 if (doubleValue / pow(2.0, DBL_MANT_DIG) > step)
515 return false;
516 double remainder = fmod(doubleValue, step);
517 // Accepts errors in lower 7-bit.
518 double acceptableError = step / pow(2.0, DBL_MANT_DIG - 7);
519 return acceptableError < remainder && remainder < (step - acceptableError);
520 }
521 case DATE:
522 case DATETIME:
523 case DATETIMELOCAL:
524 case MONTH:
525 case TIME:
526 case WEEK: {
527 const double nan = numeric_limits<double>::quiet_NaN();
528 double doubleValue = parseToDouble(value(), nan);
529 doubleValue = fabs(doubleValue - stepBase());
530 if (!isfinite(doubleValue))
531 return false;
532 ASSERT(round(doubleValue) == doubleValue);
533 ASSERT(round(step) == step);
534 return fmod(doubleValue, step);
535 }
536 case BUTTON:
537 case CHECKBOX:
538 case COLOR:
539 case EMAIL:
540 case FILE:
541 case HIDDEN:
542 case IMAGE:
543 case ISINDEX:
544 case PASSWORD:
545 case RADIO:
546 case RESET:
547 case SEARCH:
548 case SUBMIT:
549 case TELEPHONE:
550 case TEXT:
551 case URL:
552 break;
553 }
554 // Non-supported types should be rejected by getAllowedValueStep().
555 ASSERT_NOT_REACHED();
556 return false;
557 }
558
getStepParameters(double * defaultStep,double * stepScaleFactor) const559 bool HTMLInputElement::getStepParameters(double* defaultStep, double* stepScaleFactor) const
560 {
561 ASSERT(defaultStep);
562 ASSERT(stepScaleFactor);
563 switch (inputType()) {
564 case NUMBER:
565 case RANGE:
566 *defaultStep = numberDefaultStep;
567 *stepScaleFactor = numberStepScaleFactor;
568 return true;
569 case DATE:
570 *defaultStep = dateDefaultStep;
571 *stepScaleFactor = dateStepScaleFactor;
572 return true;
573 case DATETIME:
574 case DATETIMELOCAL:
575 *defaultStep = dateTimeDefaultStep;
576 *stepScaleFactor = dateTimeStepScaleFactor;
577 return true;
578 case MONTH:
579 *defaultStep = monthDefaultStep;
580 *stepScaleFactor = monthStepScaleFactor;
581 return true;
582 case TIME:
583 *defaultStep = timeDefaultStep;
584 *stepScaleFactor = timeStepScaleFactor;
585 return true;
586 case WEEK:
587 *defaultStep = weekDefaultStep;
588 *stepScaleFactor = weekStepScaleFactor;
589 return true;
590 case BUTTON:
591 case CHECKBOX:
592 case COLOR:
593 case EMAIL:
594 case FILE:
595 case HIDDEN:
596 case IMAGE:
597 case ISINDEX:
598 case PASSWORD:
599 case RADIO:
600 case RESET:
601 case SEARCH:
602 case SUBMIT:
603 case TELEPHONE:
604 case TEXT:
605 case URL:
606 return false;
607 }
608 ASSERT_NOT_REACHED();
609 return false;
610 }
611
getAllowedValueStep(double * step) const612 bool HTMLInputElement::getAllowedValueStep(double* step) const
613 {
614 ASSERT(step);
615 double defaultStep;
616 double stepScaleFactor;
617 if (!getStepParameters(&defaultStep, &stepScaleFactor))
618 return false;
619 const AtomicString& stepString = getAttribute(stepAttr);
620 if (stepString.isEmpty()) {
621 *step = defaultStep * stepScaleFactor;
622 return true;
623 }
624 if (equalIgnoringCase(stepString, "any"))
625 return false;
626 double parsed;
627 if (!formStringToDouble(stepString, &parsed) || parsed <= 0.0) {
628 *step = defaultStep * stepScaleFactor;
629 return true;
630 }
631 // For DATE, MONTH, WEEK, the parsed value should be an integer.
632 if (inputType() == DATE || inputType() == MONTH || inputType() == WEEK)
633 parsed = max(round(parsed), 1.0);
634 double result = parsed * stepScaleFactor;
635 // For DATETIME, DATETIMELOCAL, TIME, the result should be an integer.
636 if (inputType() == DATETIME || inputType() == DATETIMELOCAL || inputType() == TIME)
637 result = max(round(result), 1.0);
638 ASSERT(result > 0);
639 *step = result;
640 return true;
641 }
642
applyStep(double count,ExceptionCode & ec)643 void HTMLInputElement::applyStep(double count, ExceptionCode& ec)
644 {
645 double step;
646 if (!getAllowedValueStep(&step)) {
647 ec = INVALID_STATE_ERR;
648 return;
649 }
650 const double nan = numeric_limits<double>::quiet_NaN();
651 double current = parseToDouble(value(), nan);
652 if (!isfinite(current)) {
653 ec = INVALID_STATE_ERR;
654 return;
655 }
656 double newValue = current + step * count;
657 if (isinf(newValue)) {
658 ec = INVALID_STATE_ERR;
659 return;
660 }
661 if (newValue < minimum()) {
662 ec = INVALID_STATE_ERR;
663 return;
664 }
665 double base = stepBase();
666 newValue = base + round((newValue - base) / step) * step;
667 if (newValue > maximum()) {
668 ec = INVALID_STATE_ERR;
669 return;
670 }
671 setValueAsNumber(newValue, ec);
672 }
673
stepUp(int n,ExceptionCode & ec)674 void HTMLInputElement::stepUp(int n, ExceptionCode& ec)
675 {
676 applyStep(n, ec);
677 }
678
stepDown(int n,ExceptionCode & ec)679 void HTMLInputElement::stepDown(int n, ExceptionCode& ec)
680 {
681 applyStep(-n, ec);
682 }
683
checkedRadioButtons(const HTMLInputElement * element)684 static inline CheckedRadioButtons& checkedRadioButtons(const HTMLInputElement *element)
685 {
686 if (HTMLFormElement* form = element->form())
687 return form->checkedRadioButtons();
688
689 return element->document()->checkedRadioButtons();
690 }
691
isKeyboardFocusable(KeyboardEvent * event) const692 bool HTMLInputElement::isKeyboardFocusable(KeyboardEvent* event) const
693 {
694 // If text fields can be focused, then they should always be keyboard focusable
695 if (isTextField())
696 return HTMLFormControlElementWithState::isFocusable();
697
698 // If the base class says we can't be focused, then we can stop now.
699 if (!HTMLFormControlElementWithState::isKeyboardFocusable(event))
700 return false;
701
702 if (inputType() == RADIO) {
703
704 // Never allow keyboard tabbing to leave you in the same radio group. Always
705 // skip any other elements in the group.
706 Node* currentFocusedNode = document()->focusedNode();
707 if (currentFocusedNode && currentFocusedNode->hasTagName(inputTag)) {
708 HTMLInputElement* focusedInput = static_cast<HTMLInputElement*>(currentFocusedNode);
709 if (focusedInput->inputType() == RADIO && focusedInput->form() == form() &&
710 focusedInput->name() == name())
711 return false;
712 }
713
714 // Allow keyboard focus if we're checked or if nothing in the group is checked.
715 return checked() || !checkedRadioButtons(this).checkedButtonForGroup(name());
716 }
717
718 return true;
719 }
720
isMouseFocusable() const721 bool HTMLInputElement::isMouseFocusable() const
722 {
723 if (isTextField())
724 return HTMLFormControlElementWithState::isFocusable();
725 return HTMLFormControlElementWithState::isMouseFocusable();
726 }
727
updateFocusAppearance(bool restorePreviousSelection)728 void HTMLInputElement::updateFocusAppearance(bool restorePreviousSelection)
729 {
730 if (isTextField())
731 InputElement::updateFocusAppearance(m_data, this, this, restorePreviousSelection);
732 else
733 HTMLFormControlElementWithState::updateFocusAppearance(restorePreviousSelection);
734 }
735
aboutToUnload()736 void HTMLInputElement::aboutToUnload()
737 {
738 InputElement::aboutToUnload(this, this);
739 }
740
shouldUseInputMethod() const741 bool HTMLInputElement::shouldUseInputMethod() const
742 {
743 return m_type == TEXT || m_type == SEARCH || m_type == ISINDEX;
744 }
745
handleFocusEvent()746 void HTMLInputElement::handleFocusEvent()
747 {
748 InputElement::dispatchFocusEvent(this, this);
749
750 if (isTextField())
751 m_autofilled = false;
752 }
753
handleBlurEvent()754 void HTMLInputElement::handleBlurEvent()
755 {
756 InputElement::dispatchBlurEvent(this, this);
757 }
758
setType(const String & t)759 void HTMLInputElement::setType(const String& t)
760 {
761 if (t.isEmpty()) {
762 int exccode;
763 removeAttribute(typeAttr, exccode);
764 } else
765 setAttribute(typeAttr, t);
766 }
767
768 typedef HashMap<String, HTMLInputElement::InputType, CaseFoldingHash> InputTypeMap;
createTypeMap()769 static const InputTypeMap* createTypeMap()
770 {
771 InputTypeMap* map = new InputTypeMap;
772 map->add("button", HTMLInputElement::BUTTON);
773 map->add("checkbox", HTMLInputElement::CHECKBOX);
774 map->add("color", HTMLInputElement::COLOR);
775 map->add("date", HTMLInputElement::DATE);
776 map->add("datetime", HTMLInputElement::DATETIME);
777 map->add("datetime-local", HTMLInputElement::DATETIMELOCAL);
778 map->add("email", HTMLInputElement::EMAIL);
779 map->add("file", HTMLInputElement::FILE);
780 map->add("hidden", HTMLInputElement::HIDDEN);
781 map->add("image", HTMLInputElement::IMAGE);
782 map->add("khtml_isindex", HTMLInputElement::ISINDEX);
783 map->add("month", HTMLInputElement::MONTH);
784 map->add("number", HTMLInputElement::NUMBER);
785 map->add("password", HTMLInputElement::PASSWORD);
786 map->add("radio", HTMLInputElement::RADIO);
787 map->add("range", HTMLInputElement::RANGE);
788 map->add("reset", HTMLInputElement::RESET);
789 map->add("search", HTMLInputElement::SEARCH);
790 map->add("submit", HTMLInputElement::SUBMIT);
791 map->add("tel", HTMLInputElement::TELEPHONE);
792 map->add("time", HTMLInputElement::TIME);
793 map->add("url", HTMLInputElement::URL);
794 map->add("week", HTMLInputElement::WEEK);
795 // No need to register "text" because it is the default type.
796 return map;
797 }
798
setInputType(const String & t)799 void HTMLInputElement::setInputType(const String& t)
800 {
801 static const InputTypeMap* typeMap = createTypeMap();
802 InputType newType = t.isNull() ? TEXT : typeMap->get(t);
803 #ifdef ANDROID_ACCEPT_CHANGES_TO_FOCUSED_TEXTFIELDS
804 if (newType == PASSWORD && document()->focusedNode() == this)
805 android::WebViewCore::getWebViewCore(document()->view())->updateTextfield(this, true, String());
806 #endif
807
808 // IMPORTANT: Don't allow the type to be changed to FILE after the first
809 // type change, otherwise a JavaScript programmer would be able to set a text
810 // field's value to something like /etc/passwd and then change it to a file field.
811 if (inputType() != newType) {
812 bool oldWillValidate = willValidate();
813 if (newType == FILE && m_haveType)
814 // Set the attribute back to the old value.
815 // Useful in case we were called from inside parseMappedAttribute.
816 setAttribute(typeAttr, type());
817 else {
818 checkedRadioButtons(this).removeButton(this);
819
820 if (newType == FILE && !m_fileList)
821 m_fileList = FileList::create();
822
823 bool wasAttached = attached();
824 if (wasAttached)
825 detach();
826
827 bool didStoreValue = storesValueSeparateFromAttribute();
828 bool wasPasswordField = inputType() == PASSWORD;
829 bool didRespectHeightAndWidth = respectHeightAndWidthAttrs();
830 m_type = newType;
831 bool willStoreValue = storesValueSeparateFromAttribute();
832 bool isPasswordField = inputType() == PASSWORD;
833 bool willRespectHeightAndWidth = respectHeightAndWidthAttrs();
834
835 if (didStoreValue && !willStoreValue && !m_data.value().isNull()) {
836 setAttribute(valueAttr, m_data.value());
837 m_data.setValue(String());
838 }
839 if (!didStoreValue && willStoreValue)
840 m_data.setValue(sanitizeValue(getAttribute(valueAttr)));
841 else
842 InputElement::updateValueIfNeeded(m_data, this);
843
844 if (wasPasswordField && !isPasswordField)
845 unregisterForActivationCallbackIfNeeded();
846 else if (!wasPasswordField && isPasswordField)
847 registerForActivationCallbackIfNeeded();
848
849 if (didRespectHeightAndWidth != willRespectHeightAndWidth) {
850 NamedMappedAttrMap* map = mappedAttributes();
851 ASSERT(map);
852 if (Attribute* height = map->getAttributeItem(heightAttr))
853 attributeChanged(height, false);
854 if (Attribute* width = map->getAttributeItem(widthAttr))
855 attributeChanged(width, false);
856 if (Attribute* align = map->getAttributeItem(alignAttr))
857 attributeChanged(align, false);
858 }
859
860 if (wasAttached) {
861 attach();
862 if (document()->focusedNode() == this)
863 updateFocusAppearance(true);
864 }
865
866 checkedRadioButtons(this).addButton(this);
867 }
868
869 setNeedsValidityCheck();
870 if (oldWillValidate != willValidate())
871 setNeedsWillValidateCheck();
872 InputElement::notifyFormStateChanged(this);
873 }
874 m_haveType = true;
875
876 if (inputType() != IMAGE && m_imageLoader)
877 m_imageLoader.clear();
878 }
879
createFormControlTypes()880 static const AtomicString* createFormControlTypes()
881 {
882 AtomicString* types = new AtomicString[HTMLInputElement::numberOfTypes];
883 // The values must be lowercased because they will be the return values of
884 // input.type and it must be lowercase according to DOM Level 2.
885 types[HTMLInputElement::BUTTON] = "button";
886 types[HTMLInputElement::CHECKBOX] = "checkbox";
887 types[HTMLInputElement::COLOR] = "color";
888 types[HTMLInputElement::DATE] = "date";
889 types[HTMLInputElement::DATETIME] = "datetime";
890 types[HTMLInputElement::DATETIMELOCAL] = "datetime-local";
891 types[HTMLInputElement::EMAIL] = "email";
892 types[HTMLInputElement::FILE] = "file";
893 types[HTMLInputElement::HIDDEN] = "hidden";
894 types[HTMLInputElement::IMAGE] = "image";
895 types[HTMLInputElement::ISINDEX] = emptyAtom;
896 types[HTMLInputElement::MONTH] = "month";
897 types[HTMLInputElement::NUMBER] = "number";
898 types[HTMLInputElement::PASSWORD] = "password";
899 types[HTMLInputElement::RADIO] = "radio";
900 types[HTMLInputElement::RANGE] = "range";
901 types[HTMLInputElement::RESET] = "reset";
902 types[HTMLInputElement::SEARCH] = "search";
903 types[HTMLInputElement::SUBMIT] = "submit";
904 types[HTMLInputElement::TELEPHONE] = "tel";
905 types[HTMLInputElement::TEXT] = "text";
906 types[HTMLInputElement::TIME] = "time";
907 types[HTMLInputElement::URL] = "url";
908 types[HTMLInputElement::WEEK] = "week";
909 return types;
910 }
911
formControlType() const912 const AtomicString& HTMLInputElement::formControlType() const
913 {
914 static const AtomicString* formControlTypes = createFormControlTypes();
915 return formControlTypes[inputType()];
916 }
917
saveFormControlState(String & result) const918 bool HTMLInputElement::saveFormControlState(String& result) const
919 {
920 if (!autoComplete())
921 return false;
922
923 switch (inputType()) {
924 case BUTTON:
925 case COLOR:
926 case DATE:
927 case DATETIME:
928 case DATETIMELOCAL:
929 case EMAIL:
930 case FILE:
931 case HIDDEN:
932 case IMAGE:
933 case ISINDEX:
934 case MONTH:
935 case NUMBER:
936 case RANGE:
937 case RESET:
938 case SEARCH:
939 case SUBMIT:
940 case TELEPHONE:
941 case TEXT:
942 case TIME:
943 case URL:
944 case WEEK:
945 result = value();
946 return true;
947 case CHECKBOX:
948 case RADIO:
949 result = checked() ? "on" : "off";
950 return true;
951 case PASSWORD:
952 return false;
953 }
954 ASSERT_NOT_REACHED();
955 return false;
956 }
957
restoreFormControlState(const String & state)958 void HTMLInputElement::restoreFormControlState(const String& state)
959 {
960 ASSERT(inputType() != PASSWORD); // should never save/restore password fields
961 switch (inputType()) {
962 case BUTTON:
963 case COLOR:
964 case DATE:
965 case DATETIME:
966 case DATETIMELOCAL:
967 case EMAIL:
968 case FILE:
969 case HIDDEN:
970 case IMAGE:
971 case ISINDEX:
972 case MONTH:
973 case NUMBER:
974 case RANGE:
975 case RESET:
976 case SEARCH:
977 case SUBMIT:
978 case TELEPHONE:
979 case TEXT:
980 case TIME:
981 case URL:
982 case WEEK:
983 setValue(state);
984 break;
985 case CHECKBOX:
986 case RADIO:
987 setChecked(state == "on");
988 break;
989 case PASSWORD:
990 break;
991 }
992 }
993
canStartSelection() const994 bool HTMLInputElement::canStartSelection() const
995 {
996 if (!isTextField())
997 return false;
998 return HTMLFormControlElementWithState::canStartSelection();
999 }
1000
canHaveSelection() const1001 bool HTMLInputElement::canHaveSelection() const
1002 {
1003 return isTextField();
1004 }
1005
accessKeyAction(bool sendToAnyElement)1006 void HTMLInputElement::accessKeyAction(bool sendToAnyElement)
1007 {
1008 switch (inputType()) {
1009 case BUTTON:
1010 case CHECKBOX:
1011 case FILE:
1012 case IMAGE:
1013 case RADIO:
1014 case RANGE:
1015 case RESET:
1016 case SUBMIT:
1017 focus(false);
1018 // send the mouse button events iff the caller specified sendToAnyElement
1019 dispatchSimulatedClick(0, sendToAnyElement);
1020 break;
1021 case HIDDEN:
1022 // a no-op for this type
1023 break;
1024 case COLOR:
1025 case DATE:
1026 case DATETIME:
1027 case DATETIMELOCAL:
1028 case EMAIL:
1029 case ISINDEX:
1030 case MONTH:
1031 case NUMBER:
1032 case PASSWORD:
1033 case SEARCH:
1034 case TELEPHONE:
1035 case TEXT:
1036 case TIME:
1037 case URL:
1038 case WEEK:
1039 // should never restore previous selection here
1040 focus(false);
1041 break;
1042 }
1043 }
1044
mapToEntry(const QualifiedName & attrName,MappedAttributeEntry & result) const1045 bool HTMLInputElement::mapToEntry(const QualifiedName& attrName, MappedAttributeEntry& result) const
1046 {
1047 if (((attrName == heightAttr || attrName == widthAttr) && respectHeightAndWidthAttrs()) ||
1048 attrName == vspaceAttr ||
1049 attrName == hspaceAttr) {
1050 result = eUniversal;
1051 return false;
1052 }
1053
1054 if (attrName == alignAttr) {
1055 if (inputType() == IMAGE) {
1056 // Share with <img> since the alignment behavior is the same.
1057 result = eReplaced;
1058 return false;
1059 }
1060 }
1061
1062 return HTMLElement::mapToEntry(attrName, result);
1063 }
1064
parseMappedAttribute(MappedAttribute * attr)1065 void HTMLInputElement::parseMappedAttribute(MappedAttribute *attr)
1066 {
1067 if (attr->name() == nameAttr) {
1068 checkedRadioButtons(this).removeButton(this);
1069 m_data.setName(attr->value());
1070 checkedRadioButtons(this).addButton(this);
1071 HTMLFormControlElementWithState::parseMappedAttribute(attr);
1072 } else if (attr->name() == autocompleteAttr) {
1073 if (equalIgnoringCase(attr->value(), "off")) {
1074 m_autocomplete = Off;
1075 registerForActivationCallbackIfNeeded();
1076 } else {
1077 bool needsToUnregister = m_autocomplete == Off;
1078
1079 if (attr->isEmpty())
1080 m_autocomplete = Uninitialized;
1081 else
1082 m_autocomplete = On;
1083
1084 if (needsToUnregister)
1085 unregisterForActivationCallbackIfNeeded();
1086 }
1087 } else if (attr->name() == typeAttr) {
1088 setInputType(attr->value());
1089 } else if (attr->name() == valueAttr) {
1090 // We only need to setChanged if the form is looking at the default value right now.
1091 if (m_data.value().isNull())
1092 setNeedsStyleRecalc();
1093 setFormControlValueMatchesRenderer(false);
1094 setNeedsValidityCheck();
1095 } else if (attr->name() == checkedAttr) {
1096 m_defaultChecked = !attr->isNull();
1097 if (m_useDefaultChecked) {
1098 setChecked(m_defaultChecked);
1099 m_useDefaultChecked = true;
1100 }
1101 setNeedsValidityCheck();
1102 } else if (attr->name() == maxlengthAttr) {
1103 InputElement::parseMaxLengthAttribute(m_data, this, this, attr);
1104 setNeedsValidityCheck();
1105 } else if (attr->name() == sizeAttr)
1106 InputElement::parseSizeAttribute(m_data, this, attr);
1107 else if (attr->name() == altAttr) {
1108 if (renderer() && inputType() == IMAGE)
1109 toRenderImage(renderer())->updateAltText();
1110 } else if (attr->name() == srcAttr) {
1111 if (renderer() && inputType() == IMAGE) {
1112 if (!m_imageLoader)
1113 m_imageLoader.set(new HTMLImageLoader(this));
1114 m_imageLoader->updateFromElementIgnoringPreviousError();
1115 }
1116 } else if (attr->name() == usemapAttr ||
1117 attr->name() == accesskeyAttr) {
1118 // FIXME: ignore for the moment
1119 } else if (attr->name() == vspaceAttr) {
1120 addCSSLength(attr, CSSPropertyMarginTop, attr->value());
1121 addCSSLength(attr, CSSPropertyMarginBottom, attr->value());
1122 } else if (attr->name() == hspaceAttr) {
1123 addCSSLength(attr, CSSPropertyMarginLeft, attr->value());
1124 addCSSLength(attr, CSSPropertyMarginRight, attr->value());
1125 } else if (attr->name() == alignAttr) {
1126 if (inputType() == IMAGE)
1127 addHTMLAlignment(attr);
1128 } else if (attr->name() == widthAttr) {
1129 if (respectHeightAndWidthAttrs())
1130 addCSSLength(attr, CSSPropertyWidth, attr->value());
1131 } else if (attr->name() == heightAttr) {
1132 if (respectHeightAndWidthAttrs())
1133 addCSSLength(attr, CSSPropertyHeight, attr->value());
1134 }
1135 // Search field and slider attributes all just cause updateFromElement to be called through style
1136 // recalcing.
1137 else if (attr->name() == onsearchAttr) {
1138 setAttributeEventListener(eventNames().searchEvent, createAttributeEventListener(this, attr));
1139 } else if (attr->name() == resultsAttr) {
1140 int oldResults = m_maxResults;
1141 m_maxResults = !attr->isNull() ? std::min(attr->value().toInt(), maxSavedResults) : -1;
1142 // FIXME: Detaching just for maxResults change is not ideal. We should figure out the right
1143 // time to relayout for this change.
1144 if (m_maxResults != oldResults && (m_maxResults <= 0 || oldResults <= 0) && attached()) {
1145 detach();
1146 attach();
1147 }
1148 setNeedsStyleRecalc();
1149 } else if (attr->name() == autosaveAttr
1150 || attr->name() == incrementalAttr)
1151 setNeedsStyleRecalc();
1152 else if (attr->name() == minAttr
1153 || attr->name() == maxAttr
1154 || attr->name() == multipleAttr
1155 || attr->name() == patternAttr
1156 || attr->name() == precisionAttr
1157 || attr->name() == stepAttr)
1158 setNeedsValidityCheck();
1159 #if ENABLE(DATALIST)
1160 else if (attr->name() == listAttr)
1161 m_hasNonEmptyList = !attr->isEmpty();
1162 // FIXME: we need to tell this change to a renderer if the attribute affects the appearance.
1163 #endif
1164 else
1165 HTMLTextFormControlElement::parseMappedAttribute(attr);
1166 }
1167
rendererIsNeeded(RenderStyle * style)1168 bool HTMLInputElement::rendererIsNeeded(RenderStyle *style)
1169 {
1170 if (inputType() == HIDDEN)
1171 return false;
1172 return HTMLFormControlElementWithState::rendererIsNeeded(style);
1173 }
1174
createRenderer(RenderArena * arena,RenderStyle * style)1175 RenderObject *HTMLInputElement::createRenderer(RenderArena *arena, RenderStyle *style)
1176 {
1177 switch (inputType()) {
1178 case BUTTON:
1179 case RESET:
1180 case SUBMIT:
1181 return new (arena) RenderButton(this);
1182 case CHECKBOX:
1183 case RADIO:
1184 return RenderObject::createObject(this, style);
1185 case FILE:
1186 return new (arena) RenderFileUploadControl(this);
1187 case HIDDEN:
1188 break;
1189 case IMAGE:
1190 return new (arena) RenderImage(this);
1191 case RANGE:
1192 return new (arena) RenderSlider(this);
1193 case COLOR:
1194 case DATE:
1195 case DATETIME:
1196 case DATETIMELOCAL:
1197 case EMAIL:
1198 case ISINDEX:
1199 case MONTH:
1200 case NUMBER:
1201 case PASSWORD:
1202 case SEARCH:
1203 case TELEPHONE:
1204 case TEXT:
1205 case TIME:
1206 case URL:
1207 case WEEK:
1208 return new (arena) RenderTextControlSingleLine(this, placeholderShouldBeVisible());
1209 }
1210 ASSERT(false);
1211 return 0;
1212 }
1213
attach()1214 void HTMLInputElement::attach()
1215 {
1216 if (!m_inited) {
1217 if (!m_haveType)
1218 setInputType(getAttribute(typeAttr));
1219 m_inited = true;
1220 }
1221
1222 HTMLFormControlElementWithState::attach();
1223
1224 if (inputType() == IMAGE) {
1225 if (!m_imageLoader)
1226 m_imageLoader.set(new HTMLImageLoader(this));
1227 m_imageLoader->updateFromElement();
1228 if (renderer() && m_imageLoader->haveFiredBeforeLoadEvent()) {
1229 RenderImage* imageObj = toRenderImage(renderer());
1230 imageObj->setCachedImage(m_imageLoader->image());
1231
1232 // If we have no image at all because we have no src attribute, set
1233 // image height and width for the alt text instead.
1234 if (!m_imageLoader->image() && !imageObj->cachedImage())
1235 imageObj->setImageSizeForAltText();
1236 }
1237 }
1238
1239 if (document()->focusedNode() == this)
1240 document()->updateFocusAppearanceSoon(true /* restore selection */);
1241 }
1242
detach()1243 void HTMLInputElement::detach()
1244 {
1245 HTMLFormControlElementWithState::detach();
1246 setFormControlValueMatchesRenderer(false);
1247 }
1248
altText() const1249 String HTMLInputElement::altText() const
1250 {
1251 // http://www.w3.org/TR/1998/REC-html40-19980424/appendix/notes.html#altgen
1252 // also heavily discussed by Hixie on bugzilla
1253 // note this is intentionally different to HTMLImageElement::altText()
1254 String alt = getAttribute(altAttr);
1255 // fall back to title attribute
1256 if (alt.isNull())
1257 alt = getAttribute(titleAttr);
1258 if (alt.isNull())
1259 alt = getAttribute(valueAttr);
1260 if (alt.isEmpty())
1261 alt = inputElementAltText();
1262 return alt;
1263 }
1264
isSuccessfulSubmitButton() const1265 bool HTMLInputElement::isSuccessfulSubmitButton() const
1266 {
1267 // HTML spec says that buttons must have names to be considered successful.
1268 // However, other browsers do not impose this constraint. So we do likewise.
1269 return !disabled() && (inputType() == IMAGE || inputType() == SUBMIT);
1270 }
1271
isActivatedSubmit() const1272 bool HTMLInputElement::isActivatedSubmit() const
1273 {
1274 return m_activeSubmit;
1275 }
1276
setActivatedSubmit(bool flag)1277 void HTMLInputElement::setActivatedSubmit(bool flag)
1278 {
1279 m_activeSubmit = flag;
1280 }
1281
appendFormData(FormDataList & encoding,bool multipart)1282 bool HTMLInputElement::appendFormData(FormDataList& encoding, bool multipart)
1283 {
1284 // image generates its own names, but for other types there is no form data unless there's a name
1285 if (name().isEmpty() && inputType() != IMAGE)
1286 return false;
1287
1288 switch (inputType()) {
1289 case COLOR:
1290 case DATE:
1291 case DATETIME:
1292 case DATETIMELOCAL:
1293 case EMAIL:
1294 case HIDDEN:
1295 case ISINDEX:
1296 case MONTH:
1297 case NUMBER:
1298 case PASSWORD:
1299 case RANGE:
1300 case SEARCH:
1301 case TELEPHONE:
1302 case TEXT:
1303 case TIME:
1304 case URL:
1305 case WEEK:
1306 // always successful
1307 encoding.appendData(name(), value());
1308 return true;
1309
1310 case CHECKBOX:
1311 case RADIO:
1312 if (checked()) {
1313 encoding.appendData(name(), value());
1314 return true;
1315 }
1316 break;
1317
1318 case BUTTON:
1319 case RESET:
1320 // these types of buttons are never successful
1321 return false;
1322
1323 case IMAGE:
1324 if (m_activeSubmit) {
1325 encoding.appendData(name().isEmpty() ? "x" : (name() + ".x"), m_xPos);
1326 encoding.appendData(name().isEmpty() ? "y" : (name() + ".y"), m_yPos);
1327 if (!name().isEmpty() && !value().isEmpty())
1328 encoding.appendData(name(), value());
1329 return true;
1330 }
1331 break;
1332
1333 case SUBMIT:
1334 if (m_activeSubmit) {
1335 String enc_str = valueWithDefault();
1336 encoding.appendData(name(), enc_str);
1337 return true;
1338 }
1339 break;
1340
1341 case FILE: {
1342 unsigned numFiles = m_fileList->length();
1343 if (!multipart) {
1344 // Send only the basenames.
1345 // 4.10.16.4 and 4.10.16.6 sections in HTML5.
1346
1347 // Unlike the multipart case, we have no special
1348 // handling for the empty fileList because Netscape
1349 // doesn't support for non-multipart submission of
1350 // file inputs, and Firefox doesn't add "name=" query
1351 // parameter.
1352
1353 for (unsigned i = 0; i < numFiles; ++i) {
1354 encoding.appendData(name(), m_fileList->item(i)->fileName());
1355 }
1356 return true;
1357 }
1358
1359 // If no filename at all is entered, return successful but empty.
1360 // Null would be more logical, but Netscape posts an empty file. Argh.
1361 if (!numFiles) {
1362 encoding.appendFile(name(), File::create(""));
1363 return true;
1364 }
1365
1366 for (unsigned i = 0; i < numFiles; ++i)
1367 encoding.appendFile(name(), m_fileList->item(i));
1368 return true;
1369 }
1370 }
1371 return false;
1372 }
1373
reset()1374 void HTMLInputElement::reset()
1375 {
1376 if (storesValueSeparateFromAttribute())
1377 setValue(String());
1378
1379 setChecked(m_defaultChecked);
1380 m_useDefaultChecked = true;
1381 }
1382
isTextField() const1383 bool HTMLInputElement::isTextField() const
1384 {
1385 switch (inputType()) {
1386 case COLOR:
1387 case DATE:
1388 case DATETIME:
1389 case DATETIMELOCAL:
1390 case EMAIL:
1391 case ISINDEX:
1392 case MONTH:
1393 case NUMBER:
1394 case PASSWORD:
1395 case SEARCH:
1396 case TELEPHONE:
1397 case TEXT:
1398 case TIME:
1399 case URL:
1400 case WEEK:
1401 return true;
1402 case BUTTON:
1403 case CHECKBOX:
1404 case FILE:
1405 case HIDDEN:
1406 case IMAGE:
1407 case RADIO:
1408 case RANGE:
1409 case RESET:
1410 case SUBMIT:
1411 return false;
1412 }
1413 ASSERT_NOT_REACHED();
1414 return false;
1415 }
1416
setChecked(bool nowChecked,bool sendChangeEvent)1417 void HTMLInputElement::setChecked(bool nowChecked, bool sendChangeEvent)
1418 {
1419 if (checked() == nowChecked)
1420 return;
1421
1422 checkedRadioButtons(this).removeButton(this);
1423
1424 m_useDefaultChecked = false;
1425 m_checked = nowChecked;
1426 setNeedsStyleRecalc();
1427
1428 checkedRadioButtons(this).addButton(this);
1429
1430 if (renderer() && renderer()->style()->hasAppearance())
1431 renderer()->theme()->stateChanged(renderer(), CheckedState);
1432
1433 // Ideally we'd do this from the render tree (matching
1434 // RenderTextView), but it's not possible to do it at the moment
1435 // because of the way the code is structured.
1436 if (renderer() && AXObjectCache::accessibilityEnabled())
1437 renderer()->document()->axObjectCache()->postNotification(renderer(), AXObjectCache::AXCheckedStateChanged, true);
1438
1439 // Only send a change event for items in the document (avoid firing during
1440 // parsing) and don't send a change event for a radio button that's getting
1441 // unchecked to match other browsers. DOM is not a useful standard for this
1442 // because it says only to fire change events at "lose focus" time, which is
1443 // definitely wrong in practice for these types of elements.
1444 if (sendChangeEvent && inDocument() && (inputType() != RADIO || nowChecked))
1445 dispatchFormControlChangeEvent();
1446 }
1447
setIndeterminate(bool _indeterminate)1448 void HTMLInputElement::setIndeterminate(bool _indeterminate)
1449 {
1450 // Only checkboxes honor indeterminate.
1451 if (inputType() != CHECKBOX || indeterminate() == _indeterminate)
1452 return;
1453
1454 m_indeterminate = _indeterminate;
1455
1456 setNeedsStyleRecalc();
1457
1458 if (renderer() && renderer()->style()->hasAppearance())
1459 renderer()->theme()->stateChanged(renderer(), CheckedState);
1460 }
1461
size() const1462 int HTMLInputElement::size() const
1463 {
1464 return m_data.size();
1465 }
1466
copyNonAttributeProperties(const Element * source)1467 void HTMLInputElement::copyNonAttributeProperties(const Element* source)
1468 {
1469 const HTMLInputElement* sourceElement = static_cast<const HTMLInputElement*>(source);
1470
1471 m_data.setValue(sourceElement->m_data.value());
1472 setChecked(sourceElement->m_checked);
1473 m_defaultChecked = sourceElement->m_defaultChecked;
1474 m_useDefaultChecked = sourceElement->m_useDefaultChecked;
1475 m_indeterminate = sourceElement->m_indeterminate;
1476
1477 HTMLFormControlElementWithState::copyNonAttributeProperties(source);
1478 }
1479
value() const1480 String HTMLInputElement::value() const
1481 {
1482 // The HTML5 spec (as of the 10/24/08 working draft) says that the value attribute isn't applicable to the file upload control
1483 // but we don't want to break existing websites, who may be relying on being able to get the file name as a value.
1484 if (inputType() == FILE) {
1485 if (!m_fileList->isEmpty())
1486 return m_fileList->item(0)->fileName();
1487 return String();
1488 }
1489
1490 String value = m_data.value();
1491 if (value.isNull()) {
1492 value = sanitizeValue(getAttribute(valueAttr));
1493
1494 // If no attribute exists, then just use "on" or "" based off the checked() state of the control.
1495 if (value.isNull() && (inputType() == CHECKBOX || inputType() == RADIO))
1496 return checked() ? "on" : "";
1497 }
1498
1499 return value;
1500 }
1501
valueWithDefault() const1502 String HTMLInputElement::valueWithDefault() const
1503 {
1504 String v = value();
1505 if (v.isNull()) {
1506 switch (inputType()) {
1507 case BUTTON:
1508 case CHECKBOX:
1509 case COLOR:
1510 case DATE:
1511 case DATETIME:
1512 case DATETIMELOCAL:
1513 case EMAIL:
1514 case FILE:
1515 case HIDDEN:
1516 case IMAGE:
1517 case ISINDEX:
1518 case MONTH:
1519 case NUMBER:
1520 case PASSWORD:
1521 case RADIO:
1522 case RANGE:
1523 case SEARCH:
1524 case TELEPHONE:
1525 case TEXT:
1526 case TIME:
1527 case URL:
1528 case WEEK:
1529 break;
1530 case RESET:
1531 v = resetButtonDefaultLabel();
1532 break;
1533 case SUBMIT:
1534 v = submitButtonDefaultLabel();
1535 break;
1536 }
1537 }
1538 return v;
1539 }
1540
setValueForUser(const String & value)1541 void HTMLInputElement::setValueForUser(const String& value)
1542 {
1543 // Call setValue and make it send a change event.
1544 setValue(value, true);
1545 }
1546
suggestedValue() const1547 const String& HTMLInputElement::suggestedValue() const
1548 {
1549 return m_data.suggestedValue();
1550 }
1551
setSuggestedValue(const String & value)1552 void HTMLInputElement::setSuggestedValue(const String& value)
1553 {
1554 if (inputType() != TEXT)
1555 return;
1556 setFormControlValueMatchesRenderer(false);
1557 m_data.setSuggestedValue(sanitizeValue(value));
1558 updatePlaceholderVisibility(false);
1559 if (renderer())
1560 renderer()->updateFromElement();
1561 setNeedsStyleRecalc();
1562 }
1563
setValue(const String & value,bool sendChangeEvent)1564 void HTMLInputElement::setValue(const String& value, bool sendChangeEvent)
1565 {
1566 // For security reasons, we don't allow setting the filename, but we do allow clearing it.
1567 // The HTML5 spec (as of the 10/24/08 working draft) says that the value attribute isn't applicable to the file upload control
1568 // but we don't want to break existing websites, who may be relying on this method to clear things.
1569 if (inputType() == FILE && !value.isEmpty())
1570 return;
1571
1572 setFormControlValueMatchesRenderer(false);
1573 if (storesValueSeparateFromAttribute()) {
1574 if (inputType() == FILE)
1575 m_fileList->clear();
1576 else {
1577 m_data.setValue(sanitizeValue(value));
1578 if (isTextField()) {
1579 updatePlaceholderVisibility(false);
1580 if (inDocument())
1581 document()->updateStyleIfNeeded();
1582 }
1583 }
1584 if (renderer())
1585 renderer()->updateFromElement();
1586 setNeedsStyleRecalc();
1587 } else
1588 setAttribute(valueAttr, sanitizeValue(value));
1589
1590 if (isTextField()) {
1591 unsigned max = m_data.value().length();
1592 #ifdef ANDROID_ACCEPT_CHANGES_TO_FOCUSED_TEXTFIELDS
1593 // Make sure our UI side textfield changes to match the RenderTextControl
1594 android::WebViewCore::getWebViewCore(document()->view())->updateTextfield(this, false, value);
1595 #endif
1596 if (document()->focusedNode() == this)
1597 InputElement::updateSelectionRange(this, this, max, max);
1598 else
1599 cacheSelection(max, max);
1600 m_data.setSuggestedValue(String());
1601 }
1602
1603 // Don't dispatch the change event when focused, it will be dispatched
1604 // when the control loses focus.
1605 if (sendChangeEvent && document()->focusedNode() != this)
1606 dispatchFormControlChangeEvent();
1607
1608 InputElement::notifyFormStateChanged(this);
1609 setNeedsValidityCheck();
1610 }
1611
parseToDouble(const String & src,double defaultValue) const1612 double HTMLInputElement::parseToDouble(const String& src, double defaultValue) const
1613 {
1614 switch (inputType()) {
1615 case DATE:
1616 case DATETIME:
1617 case DATETIMELOCAL:
1618 case TIME:
1619 case WEEK: {
1620 DateComponents date;
1621 if (!formStringToDateComponents(inputType(), src, &date))
1622 return defaultValue;
1623 double msec = date.millisecondsSinceEpoch();
1624 ASSERT(isfinite(msec));
1625 return msec;
1626 }
1627 case MONTH: {
1628 DateComponents date;
1629 if (!formStringToDateComponents(inputType(), src, &date))
1630 return defaultValue;
1631 double months = date.monthsSinceEpoch();
1632 ASSERT(isfinite(months));
1633 return months;
1634 }
1635 case NUMBER:
1636 case RANGE: {
1637 double numberValue;
1638 if (!formStringToDouble(src, &numberValue))
1639 return defaultValue;
1640 ASSERT(isfinite(numberValue));
1641 return numberValue;
1642 }
1643
1644 case BUTTON:
1645 case CHECKBOX:
1646 case COLOR:
1647 case EMAIL:
1648 case FILE:
1649 case HIDDEN:
1650 case IMAGE:
1651 case ISINDEX:
1652 case PASSWORD:
1653 case RADIO:
1654 case RESET:
1655 case SEARCH:
1656 case SUBMIT:
1657 case TELEPHONE:
1658 case TEXT:
1659 case URL:
1660 return defaultValue;
1661 }
1662 ASSERT_NOT_REACHED();
1663 return defaultValue;
1664 }
1665
valueAsDate() const1666 double HTMLInputElement::valueAsDate() const
1667 {
1668 switch (inputType()) {
1669 case DATE:
1670 case DATETIME:
1671 case TIME:
1672 case WEEK:
1673 return parseToDouble(value(), DateComponents::invalidMilliseconds());
1674 case MONTH: {
1675 DateComponents date;
1676 if (!formStringToDateComponents(inputType(), value(), &date))
1677 return DateComponents::invalidMilliseconds();
1678 double msec = date.millisecondsSinceEpoch();
1679 ASSERT(isfinite(msec));
1680 return msec;
1681 }
1682
1683 case BUTTON:
1684 case CHECKBOX:
1685 case COLOR:
1686 case DATETIMELOCAL: // valueAsDate doesn't work for the DATETIMELOCAL type according to the standard.
1687 case EMAIL:
1688 case FILE:
1689 case HIDDEN:
1690 case IMAGE:
1691 case ISINDEX:
1692 case NUMBER:
1693 case PASSWORD:
1694 case RADIO:
1695 case RANGE:
1696 case RESET:
1697 case SEARCH:
1698 case SUBMIT:
1699 case TELEPHONE:
1700 case TEXT:
1701 case URL:
1702 return DateComponents::invalidMilliseconds();
1703 }
1704 ASSERT_NOT_REACHED();
1705 return DateComponents::invalidMilliseconds();
1706 }
1707
setValueAsDate(double value,ExceptionCode & ec)1708 void HTMLInputElement::setValueAsDate(double value, ExceptionCode& ec)
1709 {
1710 DateComponents date;
1711 bool success;
1712 switch (inputType()) {
1713 case DATE:
1714 success = date.setMillisecondsSinceEpochForDate(value);
1715 break;
1716 case DATETIME:
1717 success = date.setMillisecondsSinceEpochForDateTime(value);
1718 break;
1719 case MONTH:
1720 success = date.setMillisecondsSinceEpochForMonth(value);
1721 break;
1722 case TIME:
1723 success = date.setMillisecondsSinceMidnight(value);
1724 break;
1725 case WEEK:
1726 success = date.setMillisecondsSinceEpochForWeek(value);
1727 break;
1728 case BUTTON:
1729 case CHECKBOX:
1730 case COLOR:
1731 case DATETIMELOCAL: // valueAsDate doesn't work for the DATETIMELOCAL type according to the standard.
1732 case EMAIL:
1733 case FILE:
1734 case HIDDEN:
1735 case IMAGE:
1736 case ISINDEX:
1737 case NUMBER:
1738 case PASSWORD:
1739 case RADIO:
1740 case RANGE:
1741 case RESET:
1742 case SEARCH:
1743 case SUBMIT:
1744 case TELEPHONE:
1745 case TEXT:
1746 case URL:
1747 ec = INVALID_STATE_ERR;
1748 return;
1749 default:
1750 ASSERT_NOT_REACHED();
1751 success = false;
1752 }
1753 if (!success) {
1754 setValue(String());
1755 return;
1756 }
1757 setDateValue(date);
1758 }
1759
setDateValue(const DateComponents & date)1760 void HTMLInputElement::setDateValue(const DateComponents& date)
1761 {
1762 double step;
1763 if (!getAllowedValueStep(&step)) {
1764 setValue(date.toString());
1765 return;
1766 }
1767 if (!fmod(step, msecPerMinute)) {
1768 setValue(date.toString(DateComponents::None));
1769 return;
1770 }
1771 if (!fmod(step, msecPerSecond)) {
1772 setValue(date.toString(DateComponents::Second));
1773 return;
1774 }
1775 setValue(date.toString(DateComponents::Millisecond));
1776 }
1777
valueAsNumber() const1778 double HTMLInputElement::valueAsNumber() const
1779 {
1780 const double nan = numeric_limits<double>::quiet_NaN();
1781 switch (inputType()) {
1782 case DATE:
1783 case DATETIME:
1784 case DATETIMELOCAL:
1785 case MONTH:
1786 case NUMBER:
1787 case RANGE:
1788 case TIME:
1789 case WEEK:
1790 return parseToDouble(value(), nan);
1791
1792 case BUTTON:
1793 case CHECKBOX:
1794 case COLOR:
1795 case EMAIL:
1796 case FILE:
1797 case HIDDEN:
1798 case IMAGE:
1799 case ISINDEX:
1800 case PASSWORD:
1801 case RADIO:
1802 case RESET:
1803 case SEARCH:
1804 case SUBMIT:
1805 case TELEPHONE:
1806 case TEXT:
1807 case URL:
1808 return nan;
1809 }
1810 ASSERT_NOT_REACHED();
1811 return nan;
1812 }
1813
setValueAsNumber(double newValue,ExceptionCode & ec)1814 void HTMLInputElement::setValueAsNumber(double newValue, ExceptionCode& ec)
1815 {
1816 if (!isfinite(newValue)) {
1817 ec = NOT_SUPPORTED_ERR;
1818 return;
1819 }
1820 switch (inputType()) {
1821 case DATE:
1822 case DATETIME:
1823 case TIME:
1824 case WEEK:
1825 setValueAsDate(newValue, ec);
1826 return;
1827 case MONTH: {
1828 DateComponents date;
1829 if (!date.setMonthsSinceEpoch(newValue)) {
1830 setValue(String());
1831 return;
1832 }
1833 setValue(date.toString());
1834 return;
1835 }
1836 case DATETIMELOCAL: {
1837 DateComponents date;
1838 if (!date.setMillisecondsSinceEpochForDateTimeLocal(newValue)) {
1839 setValue(String());
1840 return;
1841 }
1842 setDateValue(date);
1843 return;
1844 }
1845 case NUMBER:
1846 case RANGE:
1847 setValue(formStringFromDouble(newValue));
1848 return;
1849
1850 case BUTTON:
1851 case CHECKBOX:
1852 case COLOR:
1853 case EMAIL:
1854 case FILE:
1855 case HIDDEN:
1856 case IMAGE:
1857 case ISINDEX:
1858 case PASSWORD:
1859 case RADIO:
1860 case RESET:
1861 case SEARCH:
1862 case SUBMIT:
1863 case TELEPHONE:
1864 case TEXT:
1865 case URL:
1866 ec = INVALID_STATE_ERR;
1867 return;
1868 }
1869 ASSERT_NOT_REACHED();
1870 return;
1871 }
1872
placeholder() const1873 String HTMLInputElement::placeholder() const
1874 {
1875 return getAttribute(placeholderAttr).string();
1876 }
1877
setPlaceholder(const String & value)1878 void HTMLInputElement::setPlaceholder(const String& value)
1879 {
1880 setAttribute(placeholderAttr, value);
1881 }
1882
searchEventsShouldBeDispatched() const1883 bool HTMLInputElement::searchEventsShouldBeDispatched() const
1884 {
1885 return hasAttribute(incrementalAttr);
1886 }
1887
setValueFromRenderer(const String & value)1888 void HTMLInputElement::setValueFromRenderer(const String& value)
1889 {
1890 // File upload controls will always use setFileListFromRenderer.
1891 ASSERT(inputType() != FILE);
1892 m_data.setSuggestedValue(String());
1893 updatePlaceholderVisibility(false);
1894 InputElement::setValueFromRenderer(m_data, this, this, value);
1895 setNeedsValidityCheck();
1896 }
1897
setFileListFromRenderer(const Vector<String> & paths)1898 void HTMLInputElement::setFileListFromRenderer(const Vector<String>& paths)
1899 {
1900 m_fileList->clear();
1901 int size = paths.size();
1902 for (int i = 0; i < size; i++)
1903 m_fileList->append(File::create(paths[i]));
1904
1905 setFormControlValueMatchesRenderer(true);
1906 InputElement::notifyFormStateChanged(this);
1907 setNeedsValidityCheck();
1908 }
1909
storesValueSeparateFromAttribute() const1910 bool HTMLInputElement::storesValueSeparateFromAttribute() const
1911 {
1912 switch (inputType()) {
1913 case BUTTON:
1914 case CHECKBOX:
1915 case HIDDEN:
1916 case IMAGE:
1917 case RADIO:
1918 case RESET:
1919 case SUBMIT:
1920 return false;
1921 case COLOR:
1922 case DATE:
1923 case DATETIME:
1924 case DATETIMELOCAL:
1925 case EMAIL:
1926 case FILE:
1927 case ISINDEX:
1928 case MONTH:
1929 case NUMBER:
1930 case PASSWORD:
1931 case RANGE:
1932 case SEARCH:
1933 case TELEPHONE:
1934 case TEXT:
1935 case TIME:
1936 case URL:
1937 case WEEK:
1938 return true;
1939 }
1940 return false;
1941 }
1942
preDispatchEventHandler(Event * evt)1943 void* HTMLInputElement::preDispatchEventHandler(Event *evt)
1944 {
1945 // preventDefault or "return false" are used to reverse the automatic checking/selection we do here.
1946 // This result gives us enough info to perform the "undo" in postDispatch of the action we take here.
1947 void* result = 0;
1948 if ((inputType() == CHECKBOX || inputType() == RADIO) && evt->isMouseEvent()
1949 && evt->type() == eventNames().clickEvent && static_cast<MouseEvent*>(evt)->button() == LeftButton) {
1950 if (inputType() == CHECKBOX) {
1951 // As a way to store the state, we return 0 if we were unchecked, 1 if we were checked, and 2 for
1952 // indeterminate.
1953 if (indeterminate()) {
1954 result = (void*)0x2;
1955 setIndeterminate(false);
1956 } else {
1957 if (checked())
1958 result = (void*)0x1;
1959 setChecked(!checked(), true);
1960 }
1961 } else {
1962 // For radio buttons, store the current selected radio object.
1963 // We really want radio groups to end up in sane states, i.e., to have something checked.
1964 // Therefore if nothing is currently selected, we won't allow this action to be "undone", since
1965 // we want some object in the radio group to actually get selected.
1966 HTMLInputElement* currRadio = checkedRadioButtons(this).checkedButtonForGroup(name());
1967 if (currRadio) {
1968 // We have a radio button selected that is not us. Cache it in our result field and ref it so
1969 // that it can't be destroyed.
1970 currRadio->ref();
1971 result = currRadio;
1972 }
1973 setChecked(true, true);
1974 }
1975 }
1976 return result;
1977 }
1978
postDispatchEventHandler(Event * evt,void * data)1979 void HTMLInputElement::postDispatchEventHandler(Event *evt, void* data)
1980 {
1981 if ((inputType() == CHECKBOX || inputType() == RADIO) && evt->isMouseEvent()
1982 && evt->type() == eventNames().clickEvent && static_cast<MouseEvent*>(evt)->button() == LeftButton) {
1983 if (inputType() == CHECKBOX) {
1984 // Reverse the checking we did in preDispatch.
1985 if (evt->defaultPrevented() || evt->defaultHandled()) {
1986 if (data == (void*)0x2)
1987 setIndeterminate(true);
1988 else
1989 setChecked(data);
1990 }
1991 } else if (data) {
1992 HTMLInputElement* input = static_cast<HTMLInputElement*>(data);
1993 if (evt->defaultPrevented() || evt->defaultHandled()) {
1994 // Restore the original selected radio button if possible.
1995 // Make sure it is still a radio button and only do the restoration if it still
1996 // belongs to our group.
1997
1998 if (input->form() == form() && input->inputType() == RADIO && input->name() == name()) {
1999 // Ok, the old radio button is still in our form and in our group and is still a
2000 // radio button, so it's safe to restore selection to it.
2001 input->setChecked(true);
2002 }
2003 }
2004 input->deref();
2005 }
2006
2007 // Left clicks on radio buttons and check boxes already performed default actions in preDispatchEventHandler().
2008 evt->setDefaultHandled();
2009 }
2010 }
2011
defaultEventHandler(Event * evt)2012 void HTMLInputElement::defaultEventHandler(Event* evt)
2013 {
2014 // FIXME: It would be better to refactor this for the different types of input element.
2015 // Having them all in one giant function makes this hard to read, and almost all the handling is type-specific.
2016
2017 bool clickDefaultFormButton = false;
2018
2019 if (isTextField() && evt->type() == eventNames().textInputEvent && evt->isTextEvent() && static_cast<TextEvent*>(evt)->data() == "\n")
2020 clickDefaultFormButton = true;
2021
2022 if (inputType() == IMAGE && evt->isMouseEvent() && evt->type() == eventNames().clickEvent) {
2023 // record the mouse position for when we get the DOMActivate event
2024 MouseEvent* me = static_cast<MouseEvent*>(evt);
2025 // FIXME: We could just call offsetX() and offsetY() on the event,
2026 // but that's currently broken, so for now do the computation here.
2027 if (me->isSimulated() || !renderer()) {
2028 m_xPos = 0;
2029 m_yPos = 0;
2030 } else {
2031 // FIXME: This doesn't work correctly with transforms.
2032 // FIXME: pageX/pageY need adjusting for pageZoomFactor(). Use actualPageLocation()?
2033 IntPoint absOffset = roundedIntPoint(renderer()->localToAbsolute());
2034 m_xPos = me->pageX() - absOffset.x();
2035 m_yPos = me->pageY() - absOffset.y();
2036 }
2037 }
2038
2039 if (isTextField()
2040 && evt->type() == eventNames().keydownEvent
2041 && evt->isKeyboardEvent()
2042 && focused()
2043 && document()->frame()
2044 && document()->frame()->doTextFieldCommandFromEvent(this, static_cast<KeyboardEvent*>(evt))) {
2045 evt->setDefaultHandled();
2046 return;
2047 }
2048
2049 if (inputType() == RADIO
2050 && evt->isMouseEvent()
2051 && evt->type() == eventNames().clickEvent
2052 && static_cast<MouseEvent*>(evt)->button() == LeftButton) {
2053 evt->setDefaultHandled();
2054 return;
2055 }
2056
2057 // Call the base event handler before any of our own event handling for almost all events in text fields.
2058 // Makes editing keyboard handling take precedence over the keydown and keypress handling in this function.
2059 bool callBaseClassEarly = isTextField() && !clickDefaultFormButton
2060 && (evt->type() == eventNames().keydownEvent || evt->type() == eventNames().keypressEvent);
2061 if (callBaseClassEarly) {
2062 HTMLFormControlElementWithState::defaultEventHandler(evt);
2063 if (evt->defaultHandled())
2064 return;
2065 }
2066
2067 // DOMActivate events cause the input to be "activated" - in the case of image and submit inputs, this means
2068 // actually submitting the form. For reset inputs, the form is reset. These events are sent when the user clicks
2069 // on the element, or presses enter while it is the active element. JavaScript code wishing to activate the element
2070 // must dispatch a DOMActivate event - a click event will not do the job.
2071 if (evt->type() == eventNames().DOMActivateEvent && !disabled()) {
2072 if (inputType() == IMAGE || inputType() == SUBMIT || inputType() == RESET) {
2073 if (!form())
2074 return;
2075 if (inputType() == RESET)
2076 form()->reset();
2077 else {
2078 m_activeSubmit = true;
2079 // FIXME: Would be cleaner to get m_xPos and m_yPos out of the underlying mouse
2080 // event (if any) here instead of relying on the variables set above when
2081 // processing the click event. Even better, appendFormData could pass the
2082 // event in, and then we could get rid of m_xPos and m_yPos altogether!
2083 if (!form()->prepareSubmit(evt)) {
2084 m_xPos = 0;
2085 m_yPos = 0;
2086 }
2087 m_activeSubmit = false;
2088 }
2089 } else if (inputType() == FILE && renderer())
2090 toRenderFileUploadControl(renderer())->click();
2091 }
2092
2093 // Use key press event here since sending simulated mouse events
2094 // on key down blocks the proper sending of the key press event.
2095 if (evt->type() == eventNames().keypressEvent && evt->isKeyboardEvent()) {
2096 bool clickElement = false;
2097
2098 int charCode = static_cast<KeyboardEvent*>(evt)->charCode();
2099
2100 if (charCode == '\r') {
2101 switch (inputType()) {
2102 case CHECKBOX:
2103 case COLOR:
2104 case DATE:
2105 case DATETIME:
2106 case DATETIMELOCAL:
2107 case EMAIL:
2108 case HIDDEN:
2109 case ISINDEX:
2110 case MONTH:
2111 case NUMBER:
2112 case PASSWORD:
2113 case RANGE:
2114 case SEARCH:
2115 case TELEPHONE:
2116 case TEXT:
2117 case TIME:
2118 case URL:
2119 case WEEK:
2120 // Simulate mouse click on the default form button for enter for these types of elements.
2121 clickDefaultFormButton = true;
2122 break;
2123 case BUTTON:
2124 case FILE:
2125 case IMAGE:
2126 case RESET:
2127 case SUBMIT:
2128 // Simulate mouse click for enter for these types of elements.
2129 clickElement = true;
2130 break;
2131 case RADIO:
2132 break; // Don't do anything for enter on a radio button.
2133 }
2134 } else if (charCode == ' ') {
2135 switch (inputType()) {
2136 case BUTTON:
2137 case CHECKBOX:
2138 case FILE:
2139 case IMAGE:
2140 case RESET:
2141 case SUBMIT:
2142 case RADIO:
2143 // Prevent scrolling down the page.
2144 evt->setDefaultHandled();
2145 return;
2146 default:
2147 break;
2148 }
2149 }
2150
2151 if (clickElement) {
2152 dispatchSimulatedClick(evt);
2153 evt->setDefaultHandled();
2154 return;
2155 }
2156 }
2157
2158 if (evt->type() == eventNames().keydownEvent && evt->isKeyboardEvent()) {
2159 String key = static_cast<KeyboardEvent*>(evt)->keyIdentifier();
2160
2161 if (key == "U+0020") {
2162 switch (inputType()) {
2163 case BUTTON:
2164 case CHECKBOX:
2165 case FILE:
2166 case IMAGE:
2167 case RESET:
2168 case SUBMIT:
2169 case RADIO:
2170 setActive(true, true);
2171 // No setDefaultHandled(), because IE dispatches a keypress in this case
2172 // and the caller will only dispatch a keypress if we don't call setDefaultHandled.
2173 return;
2174 default:
2175 break;
2176 }
2177 }
2178
2179 // allow enter to change state of radio
2180 if (inputType() == RADIO && (key == "Up" || key == "Down" || key == "Left" || key == "Right")) {
2181 // Left and up mean "previous radio button".
2182 // Right and down mean "next radio button".
2183 // Tested in WinIE, and even for RTL, left still means previous radio button (and so moves
2184 // to the right). Seems strange, but we'll match it.
2185 bool forward = (key == "Down" || key == "Right");
2186
2187 // We can only stay within the form's children if the form hasn't been demoted to a leaf because
2188 // of malformed HTML.
2189 Node* n = this;
2190 while ((n = (forward ? n->traverseNextNode() : n->traversePreviousNode()))) {
2191 // Once we encounter a form element, we know we're through.
2192 if (n->hasTagName(formTag))
2193 break;
2194
2195 // Look for more radio buttons.
2196 if (n->hasTagName(inputTag)) {
2197 HTMLInputElement* elt = static_cast<HTMLInputElement*>(n);
2198 if (elt->form() != form())
2199 break;
2200 if (n->hasTagName(inputTag)) {
2201 HTMLInputElement* inputElt = static_cast<HTMLInputElement*>(n);
2202 if (inputElt->inputType() == RADIO && inputElt->name() == name() && inputElt->isFocusable()) {
2203 inputElt->setChecked(true);
2204 document()->setFocusedNode(inputElt);
2205 inputElt->dispatchSimulatedClick(evt, false, false);
2206 evt->setDefaultHandled();
2207 break;
2208 }
2209 }
2210 }
2211 }
2212 }
2213 }
2214
2215 if (evt->type() == eventNames().keyupEvent && evt->isKeyboardEvent()) {
2216 bool clickElement = false;
2217
2218 String key = static_cast<KeyboardEvent*>(evt)->keyIdentifier();
2219
2220 if (key == "U+0020") {
2221 switch (inputType()) {
2222 case BUTTON:
2223 case CHECKBOX:
2224 case FILE:
2225 case IMAGE:
2226 case RESET:
2227 case SUBMIT:
2228 // Simulate mouse click for spacebar for these types of elements.
2229 // The AppKit already does this for some, but not all, of them.
2230 clickElement = true;
2231 break;
2232 case RADIO:
2233 // If an unselected radio is tabbed into (because the entire group has nothing
2234 // checked, or because of some explicit .focus() call), then allow space to check it.
2235 if (!checked())
2236 clickElement = true;
2237 break;
2238 case COLOR:
2239 case DATE:
2240 case DATETIME:
2241 case DATETIMELOCAL:
2242 case EMAIL:
2243 case HIDDEN:
2244 case ISINDEX:
2245 case MONTH:
2246 case NUMBER:
2247 case PASSWORD:
2248 case RANGE:
2249 case SEARCH:
2250 case TELEPHONE:
2251 case TEXT:
2252 case TIME:
2253 case URL:
2254 case WEEK:
2255 break;
2256 }
2257 }
2258
2259 if (clickElement) {
2260 if (active())
2261 dispatchSimulatedClick(evt);
2262 evt->setDefaultHandled();
2263 return;
2264 }
2265 }
2266
2267 if (clickDefaultFormButton) {
2268 if (isSearchField()) {
2269 addSearchResult();
2270 onSearch();
2271 }
2272 // Fire onChange for text fields.
2273 RenderObject* r = renderer();
2274 if (r && r->isTextField() && toRenderTextControl(r)->wasChangedSinceLastChangeEvent()) {
2275 dispatchFormControlChangeEvent();
2276 // Refetch the renderer since arbitrary JS code run during onchange can do anything, including destroying it.
2277 r = renderer();
2278 if (r && r->isTextField())
2279 toRenderTextControl(r)->setChangedSinceLastChangeEvent(false);
2280 }
2281
2282 RefPtr<HTMLFormElement> formForSubmission = form();
2283 // If there is no form and the element is an <isindex>, then create a temporary form just to be used for submission.
2284 if (!formForSubmission && inputType() == ISINDEX)
2285 formForSubmission = createTemporaryFormForIsIndex();
2286
2287 // Form may never have been present, or may have been destroyed by code responding to the change event.
2288 if (formForSubmission)
2289 formForSubmission->submitClick(evt);
2290
2291 evt->setDefaultHandled();
2292 return;
2293 }
2294
2295 if (evt->isBeforeTextInsertedEvent())
2296 InputElement::handleBeforeTextInsertedEvent(m_data, this, this, evt);
2297
2298 if (isTextField() && renderer() && (evt->isMouseEvent() || evt->isDragEvent() || evt->isWheelEvent() || evt->type() == eventNames().blurEvent || evt->type() == eventNames().focusEvent))
2299 toRenderTextControlSingleLine(renderer())->forwardEvent(evt);
2300
2301 if (inputType() == RANGE && renderer() && (evt->isMouseEvent() || evt->isDragEvent() || evt->isWheelEvent()))
2302 toRenderSlider(renderer())->forwardEvent(evt);
2303
2304 if (!callBaseClassEarly && !evt->defaultHandled())
2305 HTMLFormControlElementWithState::defaultEventHandler(evt);
2306 }
2307
createTemporaryFormForIsIndex()2308 PassRefPtr<HTMLFormElement> HTMLInputElement::createTemporaryFormForIsIndex()
2309 {
2310 RefPtr<HTMLFormElement> form = new HTMLFormElement(formTag, document());
2311 form->registerFormElement(this);
2312 form->setMethod("GET");
2313 if (!document()->baseURL().isEmpty()) {
2314 // We treat the href property of the <base> element as the form action, as per section 7.5
2315 // "Queries and Indexes" of the HTML 2.0 spec. <http://www.w3.org/MarkUp/html-spec/html-spec_7.html#SEC7.5>.
2316 form->setAction(document()->baseURL().string());
2317 }
2318 return form.release();
2319 }
2320
isURLAttribute(Attribute * attr) const2321 bool HTMLInputElement::isURLAttribute(Attribute *attr) const
2322 {
2323 return (attr->name() == srcAttr);
2324 }
2325
defaultValue() const2326 String HTMLInputElement::defaultValue() const
2327 {
2328 return getAttribute(valueAttr);
2329 }
2330
setDefaultValue(const String & value)2331 void HTMLInputElement::setDefaultValue(const String &value)
2332 {
2333 setAttribute(valueAttr, value);
2334 }
2335
defaultChecked() const2336 bool HTMLInputElement::defaultChecked() const
2337 {
2338 return !getAttribute(checkedAttr).isNull();
2339 }
2340
setDefaultChecked(bool defaultChecked)2341 void HTMLInputElement::setDefaultChecked(bool defaultChecked)
2342 {
2343 setAttribute(checkedAttr, defaultChecked ? "" : 0);
2344 }
2345
setDefaultName(const AtomicString & name)2346 void HTMLInputElement::setDefaultName(const AtomicString& name)
2347 {
2348 m_data.setName(name);
2349 }
2350
accept() const2351 String HTMLInputElement::accept() const
2352 {
2353 return getAttribute(acceptAttr);
2354 }
2355
setAccept(const String & value)2356 void HTMLInputElement::setAccept(const String &value)
2357 {
2358 setAttribute(acceptAttr, value);
2359 }
2360
accessKey() const2361 String HTMLInputElement::accessKey() const
2362 {
2363 return getAttribute(accesskeyAttr);
2364 }
2365
setAccessKey(const String & value)2366 void HTMLInputElement::setAccessKey(const String &value)
2367 {
2368 setAttribute(accesskeyAttr, value);
2369 }
2370
align() const2371 String HTMLInputElement::align() const
2372 {
2373 return getAttribute(alignAttr);
2374 }
2375
setAlign(const String & value)2376 void HTMLInputElement::setAlign(const String &value)
2377 {
2378 setAttribute(alignAttr, value);
2379 }
2380
alt() const2381 String HTMLInputElement::alt() const
2382 {
2383 return getAttribute(altAttr);
2384 }
2385
setAlt(const String & value)2386 void HTMLInputElement::setAlt(const String &value)
2387 {
2388 setAttribute(altAttr, value);
2389 }
2390
maxLength() const2391 int HTMLInputElement::maxLength() const
2392 {
2393 return m_data.maxLength();
2394 }
2395
setMaxLength(int maxLength,ExceptionCode & ec)2396 void HTMLInputElement::setMaxLength(int maxLength, ExceptionCode& ec)
2397 {
2398 if (maxLength < 0)
2399 ec = INDEX_SIZE_ERR;
2400 else
2401 setAttribute(maxlengthAttr, String::number(maxLength));
2402 }
2403
multiple() const2404 bool HTMLInputElement::multiple() const
2405 {
2406 return !getAttribute(multipleAttr).isNull();
2407 }
2408
setMultiple(bool multiple)2409 void HTMLInputElement::setMultiple(bool multiple)
2410 {
2411 setAttribute(multipleAttr, multiple ? "" : 0);
2412 }
2413
setSize(unsigned _size)2414 void HTMLInputElement::setSize(unsigned _size)
2415 {
2416 setAttribute(sizeAttr, String::number(_size));
2417 }
2418
src() const2419 KURL HTMLInputElement::src() const
2420 {
2421 return document()->completeURL(getAttribute(srcAttr));
2422 }
2423
setSrc(const String & value)2424 void HTMLInputElement::setSrc(const String &value)
2425 {
2426 setAttribute(srcAttr, value);
2427 }
2428
useMap() const2429 String HTMLInputElement::useMap() const
2430 {
2431 return getAttribute(usemapAttr);
2432 }
2433
setUseMap(const String & value)2434 void HTMLInputElement::setUseMap(const String &value)
2435 {
2436 setAttribute(usemapAttr, value);
2437 }
2438
setAutofilled(bool b)2439 void HTMLInputElement::setAutofilled(bool b)
2440 {
2441 if (b == m_autofilled)
2442 return;
2443
2444 m_autofilled = b;
2445 setNeedsStyleRecalc();
2446 }
2447
files()2448 FileList* HTMLInputElement::files()
2449 {
2450 if (inputType() != FILE)
2451 return 0;
2452 return m_fileList.get();
2453 }
2454
sanitizeValue(const String & proposedValue) const2455 String HTMLInputElement::sanitizeValue(const String& proposedValue) const
2456 {
2457 if (isTextField())
2458 return InputElement::sanitizeValue(this, proposedValue);
2459 return proposedValue;
2460 }
2461
needsActivationCallback()2462 bool HTMLInputElement::needsActivationCallback()
2463 {
2464 return inputType() == PASSWORD || m_autocomplete == Off;
2465 }
2466
registerForActivationCallbackIfNeeded()2467 void HTMLInputElement::registerForActivationCallbackIfNeeded()
2468 {
2469 if (needsActivationCallback())
2470 document()->registerForDocumentActivationCallbacks(this);
2471 }
2472
unregisterForActivationCallbackIfNeeded()2473 void HTMLInputElement::unregisterForActivationCallbackIfNeeded()
2474 {
2475 if (!needsActivationCallback())
2476 document()->unregisterForDocumentActivationCallbacks(this);
2477 }
2478
isRequiredFormControl() const2479 bool HTMLInputElement::isRequiredFormControl() const
2480 {
2481 if (!required())
2482 return false;
2483
2484 switch (inputType()) {
2485 case CHECKBOX:
2486 case DATE:
2487 case DATETIME:
2488 case DATETIMELOCAL:
2489 case EMAIL:
2490 case FILE:
2491 case MONTH:
2492 case NUMBER:
2493 case PASSWORD:
2494 case RADIO:
2495 case SEARCH:
2496 case TELEPHONE:
2497 case TEXT:
2498 case TIME:
2499 case URL:
2500 case WEEK:
2501 return true;
2502 case BUTTON:
2503 case COLOR:
2504 case HIDDEN:
2505 case IMAGE:
2506 case ISINDEX:
2507 case RANGE:
2508 case RESET:
2509 case SUBMIT:
2510 return false;
2511 }
2512
2513 ASSERT_NOT_REACHED();
2514 return false;
2515 }
2516
cacheSelection(int start,int end)2517 void HTMLInputElement::cacheSelection(int start, int end)
2518 {
2519 m_data.setCachedSelectionStart(start);
2520 m_data.setCachedSelectionEnd(end);
2521 }
2522
addSearchResult()2523 void HTMLInputElement::addSearchResult()
2524 {
2525 ASSERT(isSearchField());
2526 if (renderer())
2527 toRenderTextControlSingleLine(renderer())->addSearchResult();
2528 }
2529
onSearch()2530 void HTMLInputElement::onSearch()
2531 {
2532 ASSERT(isSearchField());
2533 if (renderer())
2534 toRenderTextControlSingleLine(renderer())->stopSearchEventTimer();
2535 dispatchEvent(Event::create(eventNames().searchEvent, true, false));
2536 }
2537
documentDidBecomeActive()2538 void HTMLInputElement::documentDidBecomeActive()
2539 {
2540 ASSERT(needsActivationCallback());
2541 reset();
2542 }
2543
willMoveToNewOwnerDocument()2544 void HTMLInputElement::willMoveToNewOwnerDocument()
2545 {
2546 // Always unregister for cache callbacks when leaving a document, even if we would otherwise like to be registered
2547 if (needsActivationCallback())
2548 document()->unregisterForDocumentActivationCallbacks(this);
2549
2550 document()->checkedRadioButtons().removeButton(this);
2551
2552 HTMLFormControlElementWithState::willMoveToNewOwnerDocument();
2553 }
2554
didMoveToNewOwnerDocument()2555 void HTMLInputElement::didMoveToNewOwnerDocument()
2556 {
2557 registerForActivationCallbackIfNeeded();
2558
2559 HTMLFormControlElementWithState::didMoveToNewOwnerDocument();
2560 }
2561
addSubresourceAttributeURLs(ListHashSet<KURL> & urls) const2562 void HTMLInputElement::addSubresourceAttributeURLs(ListHashSet<KURL>& urls) const
2563 {
2564 HTMLFormControlElementWithState::addSubresourceAttributeURLs(urls);
2565
2566 addSubresourceURL(urls, src());
2567 }
2568
willValidate() const2569 bool HTMLInputElement::willValidate() const
2570 {
2571 // FIXME: This shall check for new WF2 input types too
2572 return HTMLFormControlElementWithState::willValidate() && inputType() != HIDDEN &&
2573 inputType() != BUTTON && inputType() != RESET;
2574 }
2575
formStringFromDouble(double number)2576 String HTMLInputElement::formStringFromDouble(double number)
2577 {
2578 // According to HTML5, "the best representation of the number n as a floating
2579 // point number" is a string produced by applying ToString() to n.
2580 DtoaBuffer buffer;
2581 unsigned length;
2582 doubleToStringInJavaScriptFormat(number, buffer, &length);
2583 return String(buffer, length);
2584 }
2585
formStringToDouble(const String & src,double * out)2586 bool HTMLInputElement::formStringToDouble(const String& src, double* out)
2587 {
2588 // See HTML5 2.4.4.3 `Real numbers.'
2589
2590 if (src.isEmpty())
2591 return false;
2592 // String::toDouble() accepts leading + \t \n \v \f \r and SPACE, which are invalid in HTML5.
2593 // So, check the first character.
2594 if (src[0] != '-' && (src[0] < '0' || src[0] > '9'))
2595 return false;
2596
2597 bool valid = false;
2598 double value = src.toDouble(&valid);
2599 if (!valid)
2600 return false;
2601 // NaN and Infinity are not valid numbers according to the standard.
2602 if (!isfinite(value))
2603 return false;
2604 // -0 -> 0
2605 if (!value)
2606 value = 0;
2607 if (out)
2608 *out = value;
2609 return true;
2610 }
2611
formStringToDateComponents(InputType type,const String & formString,DateComponents * out)2612 bool HTMLInputElement::formStringToDateComponents(InputType type, const String& formString, DateComponents* out)
2613 {
2614 if (formString.isEmpty())
2615 return false;
2616 DateComponents ignoredResult;
2617 if (!out)
2618 out = &ignoredResult;
2619 const UChar* characters = formString.characters();
2620 unsigned length = formString.length();
2621 unsigned end;
2622
2623 switch (type) {
2624 case DATE:
2625 return out->parseDate(characters, length, 0, end) && end == length;
2626 case DATETIME:
2627 return out->parseDateTime(characters, length, 0, end) && end == length;
2628 case DATETIMELOCAL:
2629 return out->parseDateTimeLocal(characters, length, 0, end) && end == length;
2630 case MONTH:
2631 return out->parseMonth(characters, length, 0, end) && end == length;
2632 case WEEK:
2633 return out->parseWeek(characters, length, 0, end) && end == length;
2634 case TIME:
2635 return out->parseTime(characters, length, 0, end) && end == length;
2636 default:
2637 ASSERT_NOT_REACHED();
2638 return false;
2639 }
2640 }
2641
2642 #if ENABLE(DATALIST)
list() const2643 HTMLElement* HTMLInputElement::list() const
2644 {
2645 return dataList();
2646 }
2647
dataList() const2648 HTMLDataListElement* HTMLInputElement::dataList() const
2649 {
2650 if (!m_hasNonEmptyList)
2651 return 0;
2652
2653 switch (inputType()) {
2654 case COLOR:
2655 case DATE:
2656 case DATETIME:
2657 case DATETIMELOCAL:
2658 case EMAIL:
2659 case MONTH:
2660 case NUMBER:
2661 case RANGE:
2662 case SEARCH:
2663 case TELEPHONE:
2664 case TEXT:
2665 case TIME:
2666 case URL:
2667 case WEEK: {
2668 Element* element = document()->getElementById(getAttribute(listAttr));
2669 if (element && element->hasTagName(datalistTag))
2670 return static_cast<HTMLDataListElement*>(element);
2671 break;
2672 }
2673 case BUTTON:
2674 case CHECKBOX:
2675 case FILE:
2676 case HIDDEN:
2677 case IMAGE:
2678 case ISINDEX:
2679 case PASSWORD:
2680 case RADIO:
2681 case RESET:
2682 case SUBMIT:
2683 break;
2684 }
2685 return 0;
2686 }
2687
selectedOption() const2688 HTMLOptionElement* HTMLInputElement::selectedOption() const
2689 {
2690 String currentValue = value();
2691 // The empty value never matches to a datalist option because it
2692 // doesn't represent a suggestion according to the standard.
2693 if (currentValue.isEmpty())
2694 return 0;
2695
2696 HTMLDataListElement* sourceElement = dataList();
2697 if (!sourceElement)
2698 return 0;
2699 RefPtr<HTMLCollection> options = sourceElement->options();
2700 for (unsigned i = 0; options && i < options->length(); ++i) {
2701 HTMLOptionElement* option = static_cast<HTMLOptionElement*>(options->item(i));
2702 if (!option->disabled() && currentValue == option->value())
2703 return option;
2704 }
2705 return 0;
2706 }
2707 #endif // ENABLE(DATALIST)
2708
2709 } // namespace
2710