1 /* 2 * Copyright (C) 1999 Lars Knoll (knoll (at) kde.org) 3 * (C) 1999 Antti Koivisto (koivisto (at) kde.org) 4 * (C) 2001 Dirk Mueller (mueller (at) kde.org) 5 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved. 6 * (C) 2006 Alexey Proskuryakov (ap (at) nypop.com) 7 * Copyright (C) 2007 Samuel Weinig (sam (at) webkit.org) 8 * Copyright (C) 2010 Google Inc. All rights reserved. 9 * 10 * This library is free software; you can redistribute it and/or 11 * modify it under the terms of the GNU Library General Public 12 * License as published by the Free Software Foundation; either 13 * version 2 of the License, or (at your option) any later version. 14 * 15 * This library is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18 * Library General Public License for more details. 19 * 20 * You should have received a copy of the GNU Library General Public License 21 * along with this library; see the file COPYING.LIB. If not, write to 22 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 23 * Boston, MA 02110-1301, USA. 24 * 25 */ 26 27 #include "config.h" 28 #include "HTMLInputElement.h" 29 30 #include "AXObjectCache.h" 31 #include "Attribute.h" 32 #include "BeforeTextInsertedEvent.h" 33 #include "CSSPropertyNames.h" 34 #include "Document.h" 35 #include "EventNames.h" 36 #include "ExceptionCode.h" 37 #include "FileList.h" 38 #include "HTMLCollection.h" 39 #include "HTMLDataListElement.h" 40 #include "HTMLFormElement.h" 41 #include "HTMLNames.h" 42 #include "HTMLOptionElement.h" 43 #include "HTMLParserIdioms.h" 44 #include "InputType.h" 45 #include "KeyboardEvent.h" 46 #include "LocalizedStrings.h" 47 #include "MouseEvent.h" 48 #include "PlatformMouseEvent.h" 49 #include "RenderTextControlSingleLine.h" 50 #include "RenderTheme.h" 51 #include "RuntimeEnabledFeatures.h" 52 #include "ScriptEventListener.h" 53 #include "WheelEvent.h" 54 #include <wtf/MathExtras.h> 55 #include <wtf/StdLibExtras.h> 56 57 #ifdef ANDROID_ACCEPT_CHANGES_TO_FOCUSED_TEXTFIELDS 58 #include "PlatformBridge.h" 59 #endif 60 61 #if PLATFORM(ANDROID) && ENABLE(TOUCH_EVENTS) 62 #include "TouchEvent.h" 63 #endif 64 65 using namespace std; 66 67 namespace WebCore { 68 69 using namespace HTMLNames; 70 71 const int maxSavedResults = 256; 72 73 HTMLInputElement::HTMLInputElement(const QualifiedName& tagName, Document* document, HTMLFormElement* form, bool createdByParser) 74 : HTMLTextFormControlElement(tagName, document, form) 75 , m_maxResults(-1) 76 , m_isChecked(false) 77 , m_reflectsCheckedAttribute(true) 78 , m_isIndeterminate(false) 79 , m_hasType(false) 80 , m_isActivatedSubmit(false) 81 , m_autocomplete(Uninitialized) 82 , m_isAutofilled(false) 83 , m_stateRestored(false) 84 , m_parsingInProgress(createdByParser) 85 , m_inputType(InputType::createText(this)) 86 { 87 ASSERT(hasTagName(inputTag) || hasTagName(isindexTag)); 88 } 89 90 PassRefPtr<HTMLInputElement> HTMLInputElement::create(const QualifiedName& tagName, Document* document, HTMLFormElement* form, bool createdByParser) 91 { 92 return adoptRef(new HTMLInputElement(tagName, document, form, createdByParser)); 93 } 94 95 HTMLInputElement::~HTMLInputElement() 96 { 97 if (needsActivationCallback()) 98 document()->unregisterForDocumentActivationCallbacks(this); 99 100 document()->checkedRadioButtons().removeButton(this); 101 102 // Need to remove this from the form while it is still an HTMLInputElement, 103 // so can't wait for the base class's destructor to do it. 104 removeFromForm(); 105 } 106 107 const AtomicString& HTMLInputElement::formControlName() const 108 { 109 return m_data.name(); 110 } 111 112 bool HTMLInputElement::autoComplete() const 113 { 114 if (m_autocomplete != Uninitialized) 115 return m_autocomplete == On; 116 return HTMLTextFormControlElement::autoComplete(); 117 } 118 119 void HTMLInputElement::updateCheckedRadioButtons() 120 { 121 if (attached() && checked()) 122 checkedRadioButtons().addButton(this); 123 124 if (form()) { 125 const Vector<FormAssociatedElement*>& controls = form()->associatedElements(); 126 for (unsigned i = 0; i < controls.size(); ++i) { 127 if (!controls[i]->isFormControlElement()) 128 continue; 129 HTMLFormControlElement* control = static_cast<HTMLFormControlElement*>(controls[i]); 130 if (control->name() != name()) 131 continue; 132 if (control->type() != type()) 133 continue; 134 control->setNeedsValidityCheck(); 135 } 136 } else { 137 // FIXME: Traversing the document is inefficient. 138 for (Node* node = document()->body(); node; node = node->traverseNextNode()) { 139 if (!node->isElementNode()) 140 continue; 141 Element* element = static_cast<Element*>(node); 142 if (element->formControlName() != name()) 143 continue; 144 if (element->formControlType() != type()) 145 continue; 146 HTMLFormControlElement* control = static_cast<HTMLFormControlElement*>(element); 147 if (control->form()) 148 continue; 149 control->setNeedsValidityCheck(); 150 } 151 } 152 153 if (renderer() && renderer()->style()->hasAppearance()) 154 renderer()->theme()->stateChanged(renderer(), CheckedState); 155 } 156 157 bool HTMLInputElement::lastChangeWasUserEdit() const 158 { 159 if (!isTextField()) 160 return false; 161 162 if (!renderer()) 163 return false; 164 165 return toRenderTextControl(renderer())->lastChangeWasUserEdit(); 166 } 167 168 bool HTMLInputElement::isValidValue(const String& value) const 169 { 170 if (!m_inputType->canSetStringValue()) { 171 ASSERT_NOT_REACHED(); 172 return false; 173 } 174 return !m_inputType->typeMismatchFor(value) 175 && !stepMismatch(value) 176 && !rangeUnderflow(value) 177 && !rangeOverflow(value) 178 && !tooLong(value, IgnoreDirtyFlag) 179 && !patternMismatch(value) 180 && !valueMissing(value); 181 } 182 183 bool HTMLInputElement::typeMismatch() const 184 { 185 return m_inputType->typeMismatch(); 186 } 187 188 bool HTMLInputElement::valueMissing(const String& value) const 189 { 190 if (!isRequiredFormControl() || readOnly() || disabled()) 191 return false; 192 return m_inputType->valueMissing(value); 193 } 194 195 bool HTMLInputElement::patternMismatch(const String& value) const 196 { 197 return m_inputType->patternMismatch(value); 198 } 199 200 bool HTMLInputElement::tooLong(const String& value, NeedsToCheckDirtyFlag check) const 201 { 202 // We use isTextType() instead of supportsMaxLength() because of the 203 // 'virtual' overhead. 204 if (!isTextType()) 205 return false; 206 int max = maxLength(); 207 if (max < 0) 208 return false; 209 if (check == CheckDirtyFlag) { 210 // Return false for the default value even if it is longer than maxLength. 211 bool userEdited = !m_data.value().isNull(); 212 if (!userEdited) 213 return false; 214 } 215 return numGraphemeClusters(value) > static_cast<unsigned>(max); 216 } 217 218 bool HTMLInputElement::rangeUnderflow(const String& value) const 219 { 220 return m_inputType->rangeUnderflow(value); 221 } 222 223 bool HTMLInputElement::rangeOverflow(const String& value) const 224 { 225 return m_inputType->rangeOverflow(value); 226 } 227 228 double HTMLInputElement::minimum() const 229 { 230 return m_inputType->minimum(); 231 } 232 233 double HTMLInputElement::maximum() const 234 { 235 return m_inputType->maximum(); 236 } 237 238 bool HTMLInputElement::stepMismatch(const String& value) const 239 { 240 double step; 241 if (!getAllowedValueStep(&step)) 242 return false; 243 return m_inputType->stepMismatch(value, step); 244 } 245 246 String HTMLInputElement::minimumString() const 247 { 248 return m_inputType->serialize(minimum()); 249 } 250 251 String HTMLInputElement::maximumString() const 252 { 253 return m_inputType->serialize(maximum()); 254 } 255 256 String HTMLInputElement::stepBaseString() const 257 { 258 return m_inputType->serialize(m_inputType->stepBase()); 259 } 260 261 String HTMLInputElement::stepString() const 262 { 263 double step; 264 if (!getAllowedValueStep(&step)) { 265 // stepString() should be called only if stepMismatch() can be true. 266 ASSERT_NOT_REACHED(); 267 return String(); 268 } 269 return serializeForNumberType(step / m_inputType->stepScaleFactor()); 270 } 271 272 String HTMLInputElement::typeMismatchText() const 273 { 274 return m_inputType->typeMismatchText(); 275 } 276 277 String HTMLInputElement::valueMissingText() const 278 { 279 return m_inputType->valueMissingText(); 280 } 281 282 bool HTMLInputElement::getAllowedValueStep(double* step) const 283 { 284 return getAllowedValueStepWithDecimalPlaces(step, 0); 285 } 286 287 bool HTMLInputElement::getAllowedValueStepWithDecimalPlaces(double* step, unsigned* decimalPlaces) const 288 { 289 ASSERT(step); 290 double defaultStep = m_inputType->defaultStep(); 291 double stepScaleFactor = m_inputType->stepScaleFactor(); 292 if (!isfinite(defaultStep) || !isfinite(stepScaleFactor)) 293 return false; 294 const AtomicString& stepString = fastGetAttribute(stepAttr); 295 if (stepString.isEmpty()) { 296 *step = defaultStep * stepScaleFactor; 297 if (decimalPlaces) 298 *decimalPlaces = 0; 299 return true; 300 } 301 if (equalIgnoringCase(stepString, "any")) 302 return false; 303 double parsed; 304 if (!decimalPlaces) { 305 if (!parseToDoubleForNumberType(stepString, &parsed) || parsed <= 0.0) { 306 *step = defaultStep * stepScaleFactor; 307 return true; 308 } 309 } else { 310 if (!parseToDoubleForNumberTypeWithDecimalPlaces(stepString, &parsed, decimalPlaces) || parsed <= 0.0) { 311 *step = defaultStep * stepScaleFactor; 312 *decimalPlaces = 0; 313 return true; 314 } 315 } 316 // For date, month, week, the parsed value should be an integer for some types. 317 if (m_inputType->parsedStepValueShouldBeInteger()) 318 parsed = max(round(parsed), 1.0); 319 double result = parsed * stepScaleFactor; 320 // For datetime, datetime-local, time, the result should be an integer. 321 if (m_inputType->scaledStepValueShouldBeInteger()) 322 result = max(round(result), 1.0); 323 ASSERT(result > 0); 324 *step = result; 325 return true; 326 } 327 328 void HTMLInputElement::applyStep(double count, ExceptionCode& ec) 329 { 330 double step; 331 unsigned stepDecimalPlaces, currentDecimalPlaces; 332 if (!getAllowedValueStepWithDecimalPlaces(&step, &stepDecimalPlaces)) { 333 ec = INVALID_STATE_ERR; 334 return; 335 } 336 const double nan = numeric_limits<double>::quiet_NaN(); 337 double current = m_inputType->parseToDoubleWithDecimalPlaces(value(), nan, ¤tDecimalPlaces); 338 if (!isfinite(current)) { 339 ec = INVALID_STATE_ERR; 340 return; 341 } 342 double newValue = current + step * count; 343 if (isinf(newValue)) { 344 ec = INVALID_STATE_ERR; 345 return; 346 } 347 double acceptableError = m_inputType->acceptableError(step); 348 if (newValue - m_inputType->minimum() < -acceptableError) { 349 ec = INVALID_STATE_ERR; 350 return; 351 } 352 if (newValue < m_inputType->minimum()) 353 newValue = m_inputType->minimum(); 354 unsigned baseDecimalPlaces; 355 double base = m_inputType->stepBaseWithDecimalPlaces(&baseDecimalPlaces); 356 baseDecimalPlaces = min(baseDecimalPlaces, 16u); 357 if (newValue < pow(10.0, 21.0)) { 358 if (stepMismatch(value())) { 359 double scale = pow(10.0, static_cast<double>(max(stepDecimalPlaces, currentDecimalPlaces))); 360 newValue = round(newValue * scale) / scale; 361 } else { 362 double scale = pow(10.0, static_cast<double>(max(stepDecimalPlaces, baseDecimalPlaces))); 363 newValue = round((base + round((newValue - base) / step) * step) * scale) / scale; 364 } 365 } 366 if (newValue - m_inputType->maximum() > acceptableError) { 367 ec = INVALID_STATE_ERR; 368 return; 369 } 370 if (newValue > m_inputType->maximum()) 371 newValue = m_inputType->maximum(); 372 setValueAsNumber(newValue, ec); 373 374 if (AXObjectCache::accessibilityEnabled()) 375 document()->axObjectCache()->postNotification(renderer(), AXObjectCache::AXValueChanged, true); 376 } 377 378 void HTMLInputElement::stepUp(int n, ExceptionCode& ec) 379 { 380 applyStep(n, ec); 381 } 382 383 void HTMLInputElement::stepDown(int n, ExceptionCode& ec) 384 { 385 applyStep(-n, ec); 386 } 387 388 bool HTMLInputElement::isKeyboardFocusable(KeyboardEvent* event) const 389 { 390 if (isTextField()) 391 return HTMLFormControlElementWithState::isFocusable(); 392 return HTMLFormControlElementWithState::isKeyboardFocusable(event) && m_inputType->isKeyboardFocusable(); 393 } 394 395 bool HTMLInputElement::isMouseFocusable() const 396 { 397 if (isTextField()) 398 return HTMLFormControlElementWithState::isFocusable(); 399 return HTMLFormControlElementWithState::isMouseFocusable(); 400 } 401 402 void HTMLInputElement::updateFocusAppearance(bool restorePreviousSelection) 403 { 404 if (isTextField()) 405 InputElement::updateFocusAppearance(m_data, this, this, restorePreviousSelection); 406 else 407 HTMLFormControlElementWithState::updateFocusAppearance(restorePreviousSelection); 408 } 409 410 void HTMLInputElement::aboutToUnload() 411 { 412 InputElement::aboutToUnload(this, this); 413 } 414 415 bool HTMLInputElement::shouldUseInputMethod() const 416 { 417 return m_inputType->shouldUseInputMethod(); 418 } 419 420 void HTMLInputElement::handleFocusEvent() 421 { 422 InputElement::dispatchFocusEvent(this, this); 423 } 424 425 void HTMLInputElement::handleBlurEvent() 426 { 427 m_inputType->handleBlurEvent(); 428 InputElement::dispatchBlurEvent(this, this); 429 } 430 431 void HTMLInputElement::setType(const String& type) 432 { 433 // FIXME: This should just call setAttribute. No reason to handle the empty string specially. 434 // We should write a test case to show that setting to the empty string does not remove the 435 // attribute in other browsers and then fix this. Note that setting to null *does* remove 436 // the attribute and setAttribute implements that. 437 if (type.isEmpty()) { 438 ExceptionCode ec; 439 removeAttribute(typeAttr, ec); 440 } else 441 setAttribute(typeAttr, type); 442 } 443 444 void HTMLInputElement::updateType() 445 { 446 OwnPtr<InputType> newType = InputType::create(this, fastGetAttribute(typeAttr)); 447 bool hadType = m_hasType; 448 m_hasType = true; 449 if (m_inputType->formControlType() == newType->formControlType()) 450 return; 451 452 if (hadType && !newType->canChangeFromAnotherType()) { 453 // Set the attribute back to the old value. 454 // Useful in case we were called from inside parseMappedAttribute. 455 setAttribute(typeAttr, type()); 456 return; 457 } 458 459 checkedRadioButtons().removeButton(this); 460 461 bool wasAttached = attached(); 462 if (wasAttached) 463 detach(); 464 465 bool didStoreValue = m_inputType->storesValueSeparateFromAttribute(); 466 bool neededActivationCallback = needsActivationCallback(); 467 bool didRespectHeightAndWidth = m_inputType->shouldRespectHeightAndWidthAttributes(); 468 469 m_inputType->destroyShadowSubtree(); 470 m_inputType = newType.release(); 471 m_inputType->createShadowSubtree(); 472 473 setNeedsWillValidateCheck(); 474 475 bool willStoreValue = m_inputType->storesValueSeparateFromAttribute(); 476 477 if (didStoreValue && !willStoreValue && !m_data.value().isNull()) { 478 setAttribute(valueAttr, m_data.value()); 479 m_data.setValue(String()); 480 } 481 if (!didStoreValue && willStoreValue) 482 m_data.setValue(sanitizeValue(fastGetAttribute(valueAttr))); 483 else 484 InputElement::updateValueIfNeeded(m_data, this); 485 486 if (neededActivationCallback) 487 unregisterForActivationCallbackIfNeeded(); 488 else 489 registerForActivationCallbackIfNeeded(); 490 491 if (didRespectHeightAndWidth != m_inputType->shouldRespectHeightAndWidthAttributes()) { 492 NamedNodeMap* map = attributeMap(); 493 ASSERT(map); 494 if (Attribute* height = map->getAttributeItem(heightAttr)) 495 attributeChanged(height, false); 496 if (Attribute* width = map->getAttributeItem(widthAttr)) 497 attributeChanged(width, false); 498 if (Attribute* align = map->getAttributeItem(alignAttr)) 499 attributeChanged(align, false); 500 } 501 502 if (wasAttached) { 503 attach(); 504 if (document()->focusedNode() == this) 505 updateFocusAppearance(true); 506 } 507 508 setChangedSinceLastFormControlChangeEvent(false); 509 510 checkedRadioButtons().addButton(this); 511 512 setNeedsValidityCheck(); 513 InputElement::notifyFormStateChanged(this); 514 } 515 516 const AtomicString& HTMLInputElement::formControlType() const 517 { 518 return m_inputType->formControlType(); 519 } 520 521 bool HTMLInputElement::saveFormControlState(String& result) const 522 { 523 return m_inputType->saveFormControlState(result); 524 } 525 526 void HTMLInputElement::restoreFormControlState(const String& state) 527 { 528 m_inputType->restoreFormControlState(state); 529 m_stateRestored = true; 530 } 531 532 bool HTMLInputElement::canStartSelection() const 533 { 534 if (!isTextField()) 535 return false; 536 return HTMLFormControlElementWithState::canStartSelection(); 537 } 538 539 bool HTMLInputElement::canHaveSelection() const 540 { 541 return isTextField(); 542 } 543 544 void HTMLInputElement::accessKeyAction(bool sendToAnyElement) 545 { 546 m_inputType->accessKeyAction(sendToAnyElement); 547 } 548 549 bool HTMLInputElement::mapToEntry(const QualifiedName& attrName, MappedAttributeEntry& result) const 550 { 551 if (((attrName == heightAttr || attrName == widthAttr) && m_inputType->shouldRespectHeightAndWidthAttributes()) 552 || attrName == vspaceAttr 553 || attrName == hspaceAttr) { 554 result = eUniversal; 555 return false; 556 } 557 558 if (attrName == alignAttr && m_inputType->shouldRespectAlignAttribute()) { 559 // Share with <img> since the alignment behavior is the same. 560 result = eReplaced; 561 return false; 562 } 563 564 return HTMLElement::mapToEntry(attrName, result); 565 } 566 567 void HTMLInputElement::parseMappedAttribute(Attribute* attr) 568 { 569 if (attr->name() == nameAttr) { 570 checkedRadioButtons().removeButton(this); 571 m_data.setName(attr->value()); 572 checkedRadioButtons().addButton(this); 573 HTMLFormControlElementWithState::parseMappedAttribute(attr); 574 } else if (attr->name() == autocompleteAttr) { 575 if (equalIgnoringCase(attr->value(), "off")) { 576 m_autocomplete = Off; 577 registerForActivationCallbackIfNeeded(); 578 } else { 579 bool needsToUnregister = m_autocomplete == Off; 580 581 if (attr->isEmpty()) 582 m_autocomplete = Uninitialized; 583 else 584 m_autocomplete = On; 585 586 if (needsToUnregister) 587 unregisterForActivationCallbackIfNeeded(); 588 } 589 } else if (attr->name() == typeAttr) { 590 updateType(); 591 } else if (attr->name() == valueAttr) { 592 // We only need to setChanged if the form is looking at the default value right now. 593 if (m_data.value().isNull()) 594 setNeedsStyleRecalc(); 595 setFormControlValueMatchesRenderer(false); 596 setNeedsValidityCheck(); 597 } else if (attr->name() == checkedAttr) { 598 // Another radio button in the same group might be checked by state 599 // restore. We shouldn't call setChecked() even if this has the checked 600 // attribute. So, delay the setChecked() call until 601 // finishParsingChildren() is called if parsing is in progress. 602 if (!m_parsingInProgress && m_reflectsCheckedAttribute) { 603 setChecked(!attr->isNull()); 604 m_reflectsCheckedAttribute = true; 605 } 606 } else if (attr->name() == maxlengthAttr) { 607 InputElement::parseMaxLengthAttribute(m_data, this, this, attr); 608 setNeedsValidityCheck(); 609 } else if (attr->name() == sizeAttr) 610 InputElement::parseSizeAttribute(m_data, this, attr); 611 else if (attr->name() == altAttr) 612 m_inputType->altAttributeChanged(); 613 else if (attr->name() == srcAttr) 614 m_inputType->srcAttributeChanged(); 615 else if (attr->name() == usemapAttr || attr->name() == accesskeyAttr) { 616 // FIXME: ignore for the moment 617 } else if (attr->name() == vspaceAttr) { 618 addCSSLength(attr, CSSPropertyMarginTop, attr->value()); 619 addCSSLength(attr, CSSPropertyMarginBottom, attr->value()); 620 } else if (attr->name() == hspaceAttr) { 621 addCSSLength(attr, CSSPropertyMarginLeft, attr->value()); 622 addCSSLength(attr, CSSPropertyMarginRight, attr->value()); 623 } else if (attr->name() == alignAttr) { 624 if (m_inputType->shouldRespectAlignAttribute()) 625 addHTMLAlignment(attr); 626 } else if (attr->name() == widthAttr) { 627 if (m_inputType->shouldRespectHeightAndWidthAttributes()) 628 addCSSLength(attr, CSSPropertyWidth, attr->value()); 629 } else if (attr->name() == heightAttr) { 630 if (m_inputType->shouldRespectHeightAndWidthAttributes()) 631 addCSSLength(attr, CSSPropertyHeight, attr->value()); 632 } else if (attr->name() == onsearchAttr) { 633 // Search field and slider attributes all just cause updateFromElement to be called through style recalcing. 634 setAttributeEventListener(eventNames().searchEvent, createAttributeEventListener(this, attr)); 635 } else if (attr->name() == resultsAttr) { 636 int oldResults = m_maxResults; 637 m_maxResults = !attr->isNull() ? std::min(attr->value().toInt(), maxSavedResults) : -1; 638 // FIXME: Detaching just for maxResults change is not ideal. We should figure out the right 639 // time to relayout for this change. 640 if (m_maxResults != oldResults && (m_maxResults <= 0 || oldResults <= 0) && attached()) { 641 detach(); 642 attach(); 643 } 644 setNeedsStyleRecalc(); 645 } else if (attr->name() == autosaveAttr || attr->name() == incrementalAttr) 646 setNeedsStyleRecalc(); 647 else if (attr->name() == minAttr || attr->name() == maxAttr) { 648 m_inputType->minOrMaxAttributeChanged(); 649 setNeedsValidityCheck(); 650 } else if (attr->name() == multipleAttr || attr->name() == patternAttr || attr->name() == precisionAttr || attr->name() == stepAttr) 651 setNeedsValidityCheck(); 652 #if ENABLE(DATALIST) 653 else if (attr->name() == listAttr) 654 m_hasNonEmptyList = !attr->isEmpty(); 655 // FIXME: we need to tell this change to a renderer if the attribute affects the appearance. 656 #endif 657 #if ENABLE(INPUT_SPEECH) 658 else if (attr->name() == webkitspeechAttr) { 659 if (renderer()) { 660 // This renderer and its children have quite different layouts and styles depending on 661 // whether the speech button is visible or not. So we reset the whole thing and recreate 662 // to get the right styles and layout. 663 detach(); 664 attach(); 665 } 666 setNeedsStyleRecalc(); 667 } else if (attr->name() == onwebkitspeechchangeAttr) 668 setAttributeEventListener(eventNames().webkitspeechchangeEvent, createAttributeEventListener(this, attr)); 669 #endif 670 else 671 HTMLTextFormControlElement::parseMappedAttribute(attr); 672 } 673 674 void HTMLInputElement::finishParsingChildren() 675 { 676 m_parsingInProgress = false; 677 HTMLFormControlElementWithState::finishParsingChildren(); 678 if (!m_stateRestored) { 679 bool checked = hasAttribute(checkedAttr); 680 if (checked) 681 setChecked(checked); 682 m_reflectsCheckedAttribute = true; 683 } 684 } 685 686 bool HTMLInputElement::rendererIsNeeded(RenderStyle* style) 687 { 688 return m_inputType->rendererIsNeeded() && HTMLFormControlElementWithState::rendererIsNeeded(style); 689 } 690 691 RenderObject* HTMLInputElement::createRenderer(RenderArena* arena, RenderStyle* style) 692 { 693 return m_inputType->createRenderer(arena, style); 694 } 695 696 void HTMLInputElement::attach() 697 { 698 suspendPostAttachCallbacks(); 699 700 if (!m_hasType) 701 updateType(); 702 703 HTMLFormControlElementWithState::attach(); 704 705 m_inputType->attach(); 706 707 if (document()->focusedNode() == this) 708 document()->updateFocusAppearanceSoon(true /* restore selection */); 709 710 resumePostAttachCallbacks(); 711 } 712 713 void HTMLInputElement::detach() 714 { 715 HTMLFormControlElementWithState::detach(); 716 setFormControlValueMatchesRenderer(false); 717 } 718 719 String HTMLInputElement::altText() const 720 { 721 // http://www.w3.org/TR/1998/REC-html40-19980424/appendix/notes.html#altgen 722 // also heavily discussed by Hixie on bugzilla 723 // note this is intentionally different to HTMLImageElement::altText() 724 String alt = fastGetAttribute(altAttr); 725 // fall back to title attribute 726 if (alt.isNull()) 727 alt = getAttribute(titleAttr); 728 if (alt.isNull()) 729 alt = getAttribute(valueAttr); 730 if (alt.isEmpty()) 731 alt = inputElementAltText(); 732 return alt; 733 } 734 735 bool HTMLInputElement::isSuccessfulSubmitButton() const 736 { 737 // HTML spec says that buttons must have names to be considered successful. 738 // However, other browsers do not impose this constraint. So we do not. 739 return !disabled() && m_inputType->canBeSuccessfulSubmitButton(); 740 } 741 742 bool HTMLInputElement::isActivatedSubmit() const 743 { 744 return m_isActivatedSubmit; 745 } 746 747 void HTMLInputElement::setActivatedSubmit(bool flag) 748 { 749 m_isActivatedSubmit = flag; 750 } 751 752 bool HTMLInputElement::appendFormData(FormDataList& encoding, bool multipart) 753 { 754 return m_inputType->isFormDataAppendable() && m_inputType->appendFormData(encoding, multipart); 755 } 756 757 void HTMLInputElement::reset() 758 { 759 if (m_inputType->storesValueSeparateFromAttribute()) 760 setValue(String()); 761 762 setAutofilled(false); 763 setChecked(hasAttribute(checkedAttr)); 764 m_reflectsCheckedAttribute = true; 765 } 766 767 bool HTMLInputElement::isTextField() const 768 { 769 return m_inputType->isTextField(); 770 } 771 772 bool HTMLInputElement::isTextType() const 773 { 774 return m_inputType->isTextType(); 775 } 776 777 void HTMLInputElement::setChecked(bool nowChecked, bool sendChangeEvent) 778 { 779 if (checked() == nowChecked) 780 return; 781 782 checkedRadioButtons().removeButton(this); 783 784 m_reflectsCheckedAttribute = false; 785 m_isChecked = nowChecked; 786 setNeedsStyleRecalc(); 787 788 updateCheckedRadioButtons(); 789 setNeedsValidityCheck(); 790 791 // Ideally we'd do this from the render tree (matching 792 // RenderTextView), but it's not possible to do it at the moment 793 // because of the way the code is structured. 794 if (renderer() && AXObjectCache::accessibilityEnabled()) 795 renderer()->document()->axObjectCache()->postNotification(renderer(), AXObjectCache::AXCheckedStateChanged, true); 796 797 // Only send a change event for items in the document (avoid firing during 798 // parsing) and don't send a change event for a radio button that's getting 799 // unchecked to match other browsers. DOM is not a useful standard for this 800 // because it says only to fire change events at "lose focus" time, which is 801 // definitely wrong in practice for these types of elements. 802 if (sendChangeEvent && inDocument() && m_inputType->shouldSendChangeEventAfterCheckedChanged()) { 803 setTextAsOfLastFormControlChangeEvent(String()); 804 dispatchFormControlChangeEvent(); 805 } 806 } 807 808 void HTMLInputElement::setIndeterminate(bool newValue) 809 { 810 if (!m_inputType->isCheckable() || indeterminate() == newValue) 811 return; 812 813 m_isIndeterminate = newValue; 814 815 setNeedsStyleRecalc(); 816 817 if (renderer() && renderer()->style()->hasAppearance()) 818 renderer()->theme()->stateChanged(renderer(), CheckedState); 819 } 820 821 int HTMLInputElement::size() const 822 { 823 return m_data.size(); 824 } 825 826 void HTMLInputElement::copyNonAttributeProperties(const Element* source) 827 { 828 const HTMLInputElement* sourceElement = static_cast<const HTMLInputElement*>(source); 829 830 m_data.setValue(sourceElement->m_data.value()); 831 setChecked(sourceElement->m_isChecked); 832 m_reflectsCheckedAttribute = sourceElement->m_reflectsCheckedAttribute; 833 m_isIndeterminate = sourceElement->m_isIndeterminate; 834 835 HTMLFormControlElementWithState::copyNonAttributeProperties(source); 836 } 837 838 String HTMLInputElement::value() const 839 { 840 String value; 841 if (m_inputType->getTypeSpecificValue(value)) 842 return value; 843 844 value = m_data.value(); 845 if (!value.isNull()) 846 return value; 847 848 value = sanitizeValue(fastGetAttribute(valueAttr)); 849 if (!value.isNull()) 850 return value; 851 852 return m_inputType->fallbackValue(); 853 } 854 855 String HTMLInputElement::valueWithDefault() const 856 { 857 String value = this->value(); 858 if (!value.isNull()) 859 return value; 860 861 return m_inputType->defaultValue(); 862 } 863 864 void HTMLInputElement::setValueForUser(const String& value) 865 { 866 // Call setValue and make it send a change event. 867 setValue(value, true); 868 } 869 870 const String& HTMLInputElement::suggestedValue() const 871 { 872 return m_data.suggestedValue(); 873 } 874 875 void HTMLInputElement::setSuggestedValue(const String& value) 876 { 877 if (!m_inputType->canSetSuggestedValue()) 878 return; 879 setFormControlValueMatchesRenderer(false); 880 m_data.setSuggestedValue(sanitizeValue(value)); 881 updatePlaceholderVisibility(false); 882 if (renderer()) 883 renderer()->updateFromElement(); 884 setNeedsStyleRecalc(); 885 } 886 887 void HTMLInputElement::setValue(const String& value, bool sendChangeEvent) 888 { 889 if (!m_inputType->canSetValue(value)) 890 return; 891 892 setFormControlValueMatchesRenderer(false); 893 if (m_inputType->storesValueSeparateFromAttribute()) { 894 if (files()) 895 files()->clear(); 896 else { 897 m_data.setValue(sanitizeValue(value)); 898 if (isTextField()) 899 updatePlaceholderVisibility(false); 900 } 901 setNeedsStyleRecalc(); 902 } else 903 setAttribute(valueAttr, sanitizeValue(value)); 904 905 setNeedsValidityCheck(); 906 907 if (isTextField()) { 908 unsigned max = m_data.value().length(); 909 #ifdef ANDROID_ACCEPT_CHANGES_TO_FOCUSED_TEXTFIELDS 910 // Make sure our UI side textfield changes to match the RenderTextControl 911 PlatformBridge::updateTextfield(document()->view(), this, value); 912 #endif 913 if (document()->focusedNode() == this) 914 InputElement::updateSelectionRange(this, this, max, max); 915 else 916 cacheSelection(max, max); 917 m_data.setSuggestedValue(String()); 918 } 919 m_inputType->valueChanged(); 920 921 if (sendChangeEvent) { 922 // If the user is still editing this field, dispatch an input event rather than a change event. 923 // The change event will be dispatched when editing finishes. 924 if (isTextField() && focused()) 925 dispatchFormControlInputEvent(); 926 else 927 dispatchFormControlChangeEvent(); 928 } 929 930 if (isText() && (!focused() || !sendChangeEvent)) 931 setTextAsOfLastFormControlChangeEvent(value); 932 933 InputElement::notifyFormStateChanged(this); 934 } 935 936 double HTMLInputElement::valueAsDate() const 937 { 938 return m_inputType->valueAsDate(); 939 } 940 941 void HTMLInputElement::setValueAsDate(double value, ExceptionCode& ec) 942 { 943 m_inputType->setValueAsDate(value, ec); 944 } 945 946 double HTMLInputElement::valueAsNumber() const 947 { 948 return m_inputType->valueAsNumber(); 949 } 950 951 void HTMLInputElement::setValueAsNumber(double newValue, ExceptionCode& ec) 952 { 953 if (!isfinite(newValue)) { 954 ec = NOT_SUPPORTED_ERR; 955 return; 956 } 957 m_inputType->setValueAsNumber(newValue, ec); 958 } 959 960 String HTMLInputElement::placeholder() const 961 { 962 return fastGetAttribute(placeholderAttr).string(); 963 } 964 965 void HTMLInputElement::setPlaceholder(const String& value) 966 { 967 setAttribute(placeholderAttr, value); 968 } 969 970 bool HTMLInputElement::searchEventsShouldBeDispatched() const 971 { 972 return hasAttribute(incrementalAttr); 973 } 974 975 void HTMLInputElement::setValueFromRenderer(const String& value) 976 { 977 // File upload controls will always use setFileListFromRenderer. 978 ASSERT(!isFileUpload()); 979 980 m_data.setSuggestedValue(String()); 981 InputElement::setValueFromRenderer(m_data, this, this, value); 982 updatePlaceholderVisibility(false); 983 setNeedsValidityCheck(); 984 985 // Clear autofill flag (and yellow background) on user edit. 986 setAutofilled(false); 987 } 988 989 void HTMLInputElement::setFileListFromRenderer(const Vector<String>& paths) 990 { 991 m_inputType->setFileList(paths); 992 993 setFormControlValueMatchesRenderer(true); 994 InputElement::notifyFormStateChanged(this); 995 setNeedsValidityCheck(); 996 } 997 998 void* HTMLInputElement::preDispatchEventHandler(Event* event) 999 { 1000 if (event->type() == eventNames().textInputEvent && m_inputType->shouldSubmitImplicitly(event)) { 1001 event->stopPropagation(); 1002 return 0; 1003 } 1004 if (event->type() != eventNames().clickEvent) 1005 return 0; 1006 if (!event->isMouseEvent() || static_cast<MouseEvent*>(event)->button() != LeftButton) 1007 return 0; 1008 // FIXME: Check whether there are any cases where this actually ends up leaking. 1009 return m_inputType->willDispatchClick().leakPtr(); 1010 } 1011 1012 void HTMLInputElement::postDispatchEventHandler(Event* event, void* dataFromPreDispatch) 1013 { 1014 OwnPtr<ClickHandlingState> state = adoptPtr(static_cast<ClickHandlingState*>(dataFromPreDispatch)); 1015 if (!state) 1016 return; 1017 m_inputType->didDispatchClick(event, *state); 1018 } 1019 1020 void HTMLInputElement::defaultEventHandler(Event* evt) 1021 { 1022 if (evt->isMouseEvent() && evt->type() == eventNames().clickEvent && static_cast<MouseEvent*>(evt)->button() == LeftButton) { 1023 m_inputType->handleClickEvent(static_cast<MouseEvent*>(evt)); 1024 if (evt->defaultHandled()) 1025 return; 1026 } 1027 1028 if (evt->isKeyboardEvent() && evt->type() == eventNames().keydownEvent) { 1029 m_inputType->handleKeydownEvent(static_cast<KeyboardEvent*>(evt)); 1030 if (evt->defaultHandled()) 1031 return; 1032 } 1033 1034 // Call the base event handler before any of our own event handling for almost all events in text fields. 1035 // Makes editing keyboard handling take precedence over the keydown and keypress handling in this function. 1036 bool callBaseClassEarly = isTextField() && (evt->type() == eventNames().keydownEvent || evt->type() == eventNames().keypressEvent); 1037 if (callBaseClassEarly) { 1038 HTMLFormControlElementWithState::defaultEventHandler(evt); 1039 if (evt->defaultHandled()) 1040 return; 1041 } 1042 1043 // DOMActivate events cause the input to be "activated" - in the case of image and submit inputs, this means 1044 // actually submitting the form. For reset inputs, the form is reset. These events are sent when the user clicks 1045 // on the element, or presses enter while it is the active element. JavaScript code wishing to activate the element 1046 // must dispatch a DOMActivate event - a click event will not do the job. 1047 if (evt->type() == eventNames().DOMActivateEvent) { 1048 m_inputType->handleDOMActivateEvent(evt); 1049 if (evt->defaultHandled()) 1050 return; 1051 } 1052 1053 // Use key press event here since sending simulated mouse events 1054 // on key down blocks the proper sending of the key press event. 1055 if (evt->isKeyboardEvent() && evt->type() == eventNames().keypressEvent) { 1056 m_inputType->handleKeypressEvent(static_cast<KeyboardEvent*>(evt)); 1057 if (evt->defaultHandled()) 1058 return; 1059 } 1060 1061 if (evt->isKeyboardEvent() && evt->type() == eventNames().keyupEvent) { 1062 m_inputType->handleKeyupEvent(static_cast<KeyboardEvent*>(evt)); 1063 if (evt->defaultHandled()) 1064 return; 1065 } 1066 1067 if (m_inputType->shouldSubmitImplicitly(evt)) { 1068 if (isSearchField()) { 1069 addSearchResult(); 1070 onSearch(); 1071 } 1072 // Form submission finishes editing, just as loss of focus does. 1073 // If there was a change, send the event now. 1074 if (wasChangedSinceLastFormControlChangeEvent()) 1075 dispatchFormControlChangeEvent(); 1076 1077 RefPtr<HTMLFormElement> formForSubmission = m_inputType->formForSubmission(); 1078 // Form may never have been present, or may have been destroyed by code responding to the change event. 1079 if (formForSubmission) 1080 formForSubmission->submitImplicitly(evt, canTriggerImplicitSubmission()); 1081 1082 evt->setDefaultHandled(); 1083 return; 1084 } 1085 1086 if (evt->isBeforeTextInsertedEvent()) 1087 m_inputType->handleBeforeTextInsertedEvent(static_cast<BeforeTextInsertedEvent*>(evt)); 1088 1089 if (evt->isWheelEvent()) { 1090 m_inputType->handleWheelEvent(static_cast<WheelEvent*>(evt)); 1091 if (evt->defaultHandled()) 1092 return; 1093 } 1094 1095 if (evt->isMouseEvent() && evt->type() == eventNames().mousedownEvent) { 1096 m_inputType->handleMouseDownEvent(static_cast<MouseEvent*>(evt)); 1097 if (evt->defaultHandled()) 1098 return; 1099 } 1100 1101 #if PLATFORM(ANDROID) && ENABLE(TOUCH_EVENTS) 1102 if (evt->isTouchEvent() && evt->type() == eventNames().touchstartEvent) { 1103 m_inputType->handleTouchStartEvent(static_cast<TouchEvent*>(evt)); 1104 if (evt->defaultHandled()) 1105 return; 1106 } 1107 #endif 1108 1109 m_inputType->forwardEvent(evt); 1110 1111 if (!callBaseClassEarly && !evt->defaultHandled()) 1112 HTMLFormControlElementWithState::defaultEventHandler(evt); 1113 } 1114 1115 bool HTMLInputElement::isURLAttribute(Attribute *attr) const 1116 { 1117 return (attr->name() == srcAttr || attr->name() == formactionAttr); 1118 } 1119 1120 String HTMLInputElement::defaultValue() const 1121 { 1122 return fastGetAttribute(valueAttr); 1123 } 1124 1125 void HTMLInputElement::setDefaultValue(const String &value) 1126 { 1127 setAttribute(valueAttr, value); 1128 } 1129 1130 void HTMLInputElement::setDefaultName(const AtomicString& name) 1131 { 1132 m_data.setName(name); 1133 } 1134 1135 String HTMLInputElement::accept() const 1136 { 1137 return fastGetAttribute(acceptAttr); 1138 } 1139 1140 String HTMLInputElement::alt() const 1141 { 1142 return fastGetAttribute(altAttr); 1143 } 1144 1145 int HTMLInputElement::maxLength() const 1146 { 1147 return m_data.maxLength(); 1148 } 1149 1150 void HTMLInputElement::setMaxLength(int maxLength, ExceptionCode& ec) 1151 { 1152 if (maxLength < 0) 1153 ec = INDEX_SIZE_ERR; 1154 else 1155 setAttribute(maxlengthAttr, String::number(maxLength)); 1156 } 1157 1158 bool HTMLInputElement::multiple() const 1159 { 1160 return fastHasAttribute(multipleAttr); 1161 } 1162 1163 void HTMLInputElement::setSize(unsigned size) 1164 { 1165 setAttribute(sizeAttr, String::number(size)); 1166 } 1167 1168 KURL HTMLInputElement::src() const 1169 { 1170 return document()->completeURL(fastGetAttribute(srcAttr)); 1171 } 1172 1173 void HTMLInputElement::setAutofilled(bool autofilled) 1174 { 1175 if (autofilled == m_isAutofilled) 1176 return; 1177 1178 m_isAutofilled = autofilled; 1179 setNeedsStyleRecalc(); 1180 } 1181 1182 FileList* HTMLInputElement::files() 1183 { 1184 return m_inputType->files(); 1185 } 1186 1187 String HTMLInputElement::visibleValue() const 1188 { 1189 return m_inputType->visibleValue(); 1190 } 1191 1192 String HTMLInputElement::convertFromVisibleValue(const String& visibleValue) const 1193 { 1194 return m_inputType->convertFromVisibleValue(visibleValue); 1195 } 1196 1197 bool HTMLInputElement::isAcceptableValue(const String& proposedValue) const 1198 { 1199 return m_inputType->isAcceptableValue(proposedValue); 1200 } 1201 1202 String HTMLInputElement::sanitizeValue(const String& proposedValue) const 1203 { 1204 return m_inputType->sanitizeValue(proposedValue); 1205 } 1206 1207 bool HTMLInputElement::hasUnacceptableValue() const 1208 { 1209 return m_inputType->hasUnacceptableValue(); 1210 } 1211 1212 bool HTMLInputElement::isInRange() const 1213 { 1214 return m_inputType->supportsRangeLimitation() && !rangeUnderflow(value()) && !rangeOverflow(value()); 1215 } 1216 1217 bool HTMLInputElement::isOutOfRange() const 1218 { 1219 return m_inputType->supportsRangeLimitation() && (rangeUnderflow(value()) || rangeOverflow(value())); 1220 } 1221 1222 bool HTMLInputElement::needsActivationCallback() 1223 { 1224 return m_autocomplete == Off || m_inputType->shouldResetOnDocumentActivation(); 1225 } 1226 1227 void HTMLInputElement::registerForActivationCallbackIfNeeded() 1228 { 1229 if (needsActivationCallback()) 1230 document()->registerForDocumentActivationCallbacks(this); 1231 } 1232 1233 void HTMLInputElement::unregisterForActivationCallbackIfNeeded() 1234 { 1235 if (!needsActivationCallback()) 1236 document()->unregisterForDocumentActivationCallbacks(this); 1237 } 1238 1239 bool HTMLInputElement::isRequiredFormControl() const 1240 { 1241 return m_inputType->supportsRequired() && required(); 1242 } 1243 1244 void HTMLInputElement::cacheSelection(int start, int end) 1245 { 1246 m_data.setCachedSelectionStart(start); 1247 m_data.setCachedSelectionEnd(end); 1248 } 1249 1250 void HTMLInputElement::addSearchResult() 1251 { 1252 ASSERT(isSearchField()); 1253 if (renderer()) 1254 toRenderTextControlSingleLine(renderer())->addSearchResult(); 1255 } 1256 1257 void HTMLInputElement::onSearch() 1258 { 1259 ASSERT(isSearchField()); 1260 if (renderer()) 1261 toRenderTextControlSingleLine(renderer())->stopSearchEventTimer(); 1262 dispatchEvent(Event::create(eventNames().searchEvent, true, false)); 1263 } 1264 1265 void HTMLInputElement::documentDidBecomeActive() 1266 { 1267 ASSERT(needsActivationCallback()); 1268 reset(); 1269 } 1270 1271 void HTMLInputElement::willMoveToNewOwnerDocument() 1272 { 1273 m_inputType->willMoveToNewOwnerDocument(); 1274 1275 // Always unregister for cache callbacks when leaving a document, even if we would otherwise like to be registered 1276 if (needsActivationCallback()) 1277 document()->unregisterForDocumentActivationCallbacks(this); 1278 1279 document()->checkedRadioButtons().removeButton(this); 1280 1281 HTMLFormControlElementWithState::willMoveToNewOwnerDocument(); 1282 } 1283 1284 void HTMLInputElement::didMoveToNewOwnerDocument() 1285 { 1286 registerForActivationCallbackIfNeeded(); 1287 1288 HTMLFormControlElementWithState::didMoveToNewOwnerDocument(); 1289 } 1290 1291 void HTMLInputElement::addSubresourceAttributeURLs(ListHashSet<KURL>& urls) const 1292 { 1293 HTMLFormControlElementWithState::addSubresourceAttributeURLs(urls); 1294 1295 addSubresourceURL(urls, src()); 1296 } 1297 1298 bool HTMLInputElement::recalcWillValidate() const 1299 { 1300 return m_inputType->supportsValidation() && HTMLFormControlElementWithState::recalcWillValidate(); 1301 } 1302 1303 #if ENABLE(DATALIST) 1304 1305 HTMLElement* HTMLInputElement::list() const 1306 { 1307 return dataList(); 1308 } 1309 1310 HTMLDataListElement* HTMLInputElement::dataList() const 1311 { 1312 if (!m_hasNonEmptyList) 1313 return 0; 1314 1315 if (!m_inputType->shouldRespectListAttribute()) 1316 return 0; 1317 1318 Element* element = document()->getElementById(fastGetAttribute(listAttr)); 1319 if (!element) 1320 return 0; 1321 if (!element->hasTagName(datalistTag)) 1322 return 0; 1323 1324 return static_cast<HTMLDataListElement*>(element); 1325 } 1326 1327 HTMLOptionElement* HTMLInputElement::selectedOption() const 1328 { 1329 String value = this->value(); 1330 1331 // The empty string never matches to a datalist option because it 1332 // doesn't represent a suggestion according to the standard. 1333 if (value.isEmpty()) 1334 return 0; 1335 1336 HTMLDataListElement* sourceElement = dataList(); 1337 if (!sourceElement) 1338 return 0; 1339 RefPtr<HTMLCollection> options = sourceElement->options(); 1340 if (!options) 1341 return 0; 1342 unsigned length = options->length(); 1343 for (unsigned i = 0; i < length; ++i) { 1344 HTMLOptionElement* option = static_cast<HTMLOptionElement*>(options->item(i)); 1345 if (!option->disabled() && value == option->value()) 1346 return option; 1347 } 1348 return 0; 1349 } 1350 1351 #endif // ENABLE(DATALIST) 1352 1353 void HTMLInputElement::stepUpFromRenderer(int n) 1354 { 1355 // The differences from stepUp()/stepDown(): 1356 // 1357 // Difference 1: the current value 1358 // If the current value is not a number, including empty, the current value is assumed as 0. 1359 // * If 0 is in-range, and matches to step value 1360 // - The value should be the +step if n > 0 1361 // - The value should be the -step if n < 0 1362 // If -step or +step is out of range, new value should be 0. 1363 // * If 0 is smaller than the minimum value 1364 // - The value should be the minimum value for any n 1365 // * If 0 is larger than the maximum value 1366 // - The value should be the maximum value for any n 1367 // * If 0 is in-range, but not matched to step value 1368 // - The value should be the larger matched value nearest to 0 if n > 0 1369 // e.g. <input type=number min=-100 step=3> -> 2 1370 // - The value should be the smaler matched value nearest to 0 if n < 0 1371 // e.g. <input type=number min=-100 step=3> -> -1 1372 // As for date/datetime-local/month/time/week types, the current value is assumed as "the current local date/time". 1373 // As for datetime type, the current value is assumed as "the current date/time in UTC". 1374 // If the current value is smaller than the minimum value: 1375 // - The value should be the minimum value if n > 0 1376 // - Nothing should happen if n < 0 1377 // If the current value is larger than the maximum value: 1378 // - The value should be the maximum value if n < 0 1379 // - Nothing should happen if n > 0 1380 // 1381 // Difference 2: clamping steps 1382 // If the current value is not matched to step value: 1383 // - The value should be the larger matched value nearest to 0 if n > 0 1384 // e.g. <input type=number value=3 min=-100 step=3> -> 5 1385 // - The value should be the smaler matched value nearest to 0 if n < 0 1386 // e.g. <input type=number value=3 min=-100 step=3> -> 2 1387 // 1388 // n is assumed as -n if step < 0. 1389 1390 ASSERT(hasSpinButton() || m_inputType->isRangeControl()); 1391 if (!hasSpinButton() && !m_inputType->isRangeControl()) 1392 return; 1393 ASSERT(n); 1394 if (!n) 1395 return; 1396 1397 unsigned stepDecimalPlaces, baseDecimalPlaces; 1398 double step, base; 1399 // The value will be the default value after stepping for <input value=(empty/invalid) step="any" /> 1400 // FIXME: Not any changes after stepping, even if it is an invalid value, may be better. 1401 // (e.g. Stepping-up for <input type="number" value="foo" step="any" /> => "foo") 1402 if (equalIgnoringCase(fastGetAttribute(stepAttr), "any")) 1403 step = 0; 1404 else if (!getAllowedValueStepWithDecimalPlaces(&step, &stepDecimalPlaces)) 1405 return; 1406 base = m_inputType->stepBaseWithDecimalPlaces(&baseDecimalPlaces); 1407 baseDecimalPlaces = min(baseDecimalPlaces, 16u); 1408 1409 int sign; 1410 if (step > 0) 1411 sign = n; 1412 else if (step < 0) 1413 sign = -n; 1414 else 1415 sign = 0; 1416 1417 const double nan = numeric_limits<double>::quiet_NaN(); 1418 String currentStringValue = value(); 1419 double current = m_inputType->parseToDouble(currentStringValue, nan); 1420 if (!isfinite(current)) { 1421 ExceptionCode ec; 1422 current = m_inputType->defaultValueForStepUp(); 1423 setValueAsNumber(current, ec); 1424 } 1425 if ((sign > 0 && current < m_inputType->minimum()) || (sign < 0 && current > m_inputType->maximum())) 1426 setValue(m_inputType->serialize(sign > 0 ? m_inputType->minimum() : m_inputType->maximum())); 1427 else { 1428 ExceptionCode ec; 1429 if (stepMismatch(currentStringValue)) { 1430 ASSERT(step); 1431 double newValue; 1432 double scale = pow(10.0, static_cast<double>(max(stepDecimalPlaces, baseDecimalPlaces))); 1433 1434 if (sign < 0) 1435 newValue = round((base + floor((current - base) / step) * step) * scale) / scale; 1436 else if (sign > 0) 1437 newValue = round((base + ceil((current - base) / step) * step) * scale) / scale; 1438 else 1439 newValue = current; 1440 1441 if (newValue < m_inputType->minimum()) 1442 newValue = m_inputType->minimum(); 1443 if (newValue > m_inputType->maximum()) 1444 newValue = m_inputType->maximum(); 1445 1446 setValueAsNumber(newValue, ec); 1447 current = newValue; 1448 if (n > 1) 1449 applyStep(n - 1, ec); 1450 else if (n < -1) 1451 applyStep(n + 1, ec); 1452 } else 1453 applyStep(n, ec); 1454 } 1455 1456 if (currentStringValue != value()) { 1457 if (m_inputType->isRangeControl()) 1458 dispatchFormControlChangeEvent(); 1459 else 1460 dispatchFormControlInputEvent(); 1461 } 1462 } 1463 1464 #if ENABLE(WCSS) 1465 1466 void HTMLInputElement::setWapInputFormat(String& mask) 1467 { 1468 String validateMask = validateInputMask(m_data, mask); 1469 if (!validateMask.isEmpty()) 1470 m_data.setInputFormatMask(validateMask); 1471 } 1472 1473 #endif 1474 1475 #if ENABLE(INPUT_SPEECH) 1476 1477 bool HTMLInputElement::isSpeechEnabled() const 1478 { 1479 // FIXME: Add support for RANGE, EMAIL, URL, COLOR and DATE/TIME input types. 1480 return m_inputType->shouldRespectSpeechAttribute() && RuntimeEnabledFeatures::speechInputEnabled() && hasAttribute(webkitspeechAttr); 1481 } 1482 1483 #endif 1484 1485 bool HTMLInputElement::isTextButton() const 1486 { 1487 return m_inputType->isTextButton(); 1488 } 1489 1490 bool HTMLInputElement::isRadioButton() const 1491 { 1492 return m_inputType->isRadioButton(); 1493 } 1494 1495 bool HTMLInputElement::isSearchField() const 1496 { 1497 return m_inputType->isSearchField(); 1498 } 1499 1500 bool HTMLInputElement::isInputTypeHidden() const 1501 { 1502 return m_inputType->isHiddenType(); 1503 } 1504 1505 bool HTMLInputElement::isPasswordField() const 1506 { 1507 return m_inputType->isPasswordField(); 1508 } 1509 1510 bool HTMLInputElement::isCheckbox() const 1511 { 1512 return m_inputType->isCheckbox(); 1513 } 1514 1515 bool HTMLInputElement::isText() const 1516 { 1517 return m_inputType->isTextType(); 1518 } 1519 1520 bool HTMLInputElement::isEmailField() const 1521 { 1522 return m_inputType->isEmailField(); 1523 } 1524 1525 bool HTMLInputElement::isFileUpload() const 1526 { 1527 return m_inputType->isFileUpload(); 1528 } 1529 1530 bool HTMLInputElement::isImageButton() const 1531 { 1532 return m_inputType->isImageButton(); 1533 } 1534 1535 bool HTMLInputElement::isNumberField() const 1536 { 1537 return m_inputType->isNumberField(); 1538 } 1539 1540 bool HTMLInputElement::isSubmitButton() const 1541 { 1542 return m_inputType->isSubmitButton(); 1543 } 1544 1545 bool HTMLInputElement::isTelephoneField() const 1546 { 1547 return m_inputType->isTelephoneField(); 1548 } 1549 1550 bool HTMLInputElement::isURLField() const 1551 { 1552 return m_inputType->isURLField(); 1553 } 1554 1555 bool HTMLInputElement::isEnumeratable() const 1556 { 1557 return m_inputType->isEnumeratable(); 1558 } 1559 1560 bool HTMLInputElement::isChecked() const 1561 { 1562 return checked() && m_inputType->isCheckable(); 1563 } 1564 1565 bool HTMLInputElement::hasSpinButton() const 1566 { 1567 return m_inputType->hasSpinButton(); 1568 } 1569 1570 bool HTMLInputElement::supportsPlaceholder() const 1571 { 1572 #if PLATFORM(ANDROID) 1573 return isTextType() || isNumberField(); 1574 #else 1575 return isTextType(); 1576 #endif 1577 } 1578 1579 CheckedRadioButtons& HTMLInputElement::checkedRadioButtons() const 1580 { 1581 if (HTMLFormElement* formElement = form()) 1582 return formElement->checkedRadioButtons(); 1583 return document()->checkedRadioButtons(); 1584 } 1585 1586 void HTMLInputElement::handleBeforeTextInsertedEvent(Event* event) 1587 { 1588 InputElement::handleBeforeTextInsertedEvent(m_data, this, this, event); 1589 } 1590 1591 #if PLATFORM(ANDROID) && ENABLE(MEDIA_CAPTURE) 1592 String HTMLInputElement::capture() const 1593 { 1594 if (!isFileUpload()) { 1595 // capture has no meaning on anything other than file pickers. 1596 return String(); 1597 } 1598 1599 String capture = fastGetAttribute(captureAttr).lower(); 1600 if (capture == "camera" 1601 || capture == "camcorder" 1602 || capture == "microphone" 1603 || capture == "filesystem") 1604 return capture; 1605 // According to the HTML Media Capture specification, the invalid and 1606 // missing default value is filesystem. 1607 return "filesystem"; 1608 } 1609 #endif 1610 1611 } // namespace 1612