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, 2009, 2010, 2011 Apple Inc. All rights reserved. 6 * (C) 2006 Alexey Proskuryakov (ap@nypop.com) 7 * Copyright (C) 2007 Samuel Weinig (sam@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 65using namespace std; 66 67namespace WebCore { 68 69using namespace HTMLNames; 70 71const int maxSavedResults = 256; 72 73HTMLInputElement::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 90PassRefPtr<HTMLInputElement> HTMLInputElement::create(const QualifiedName& tagName, Document* document, HTMLFormElement* form, bool createdByParser) 91{ 92 return adoptRef(new HTMLInputElement(tagName, document, form, createdByParser)); 93} 94 95HTMLInputElement::~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 107const AtomicString& HTMLInputElement::formControlName() const 108{ 109 return m_data.name(); 110} 111 112bool HTMLInputElement::autoComplete() const 113{ 114 if (m_autocomplete != Uninitialized) 115 return m_autocomplete == On; 116 return HTMLTextFormControlElement::autoComplete(); 117} 118 119void 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 157bool 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 168bool 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 183bool HTMLInputElement::typeMismatch() const 184{ 185 return m_inputType->typeMismatch(); 186} 187 188bool HTMLInputElement::valueMissing(const String& value) const 189{ 190 if (!isRequiredFormControl() || readOnly() || disabled()) 191 return false; 192 return m_inputType->valueMissing(value); 193} 194 195bool HTMLInputElement::patternMismatch(const String& value) const 196{ 197 return m_inputType->patternMismatch(value); 198} 199 200bool 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 218bool HTMLInputElement::rangeUnderflow(const String& value) const 219{ 220 return m_inputType->rangeUnderflow(value); 221} 222 223bool HTMLInputElement::rangeOverflow(const String& value) const 224{ 225 return m_inputType->rangeOverflow(value); 226} 227 228double HTMLInputElement::minimum() const 229{ 230 return m_inputType->minimum(); 231} 232 233double HTMLInputElement::maximum() const 234{ 235 return m_inputType->maximum(); 236} 237 238bool 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 246String HTMLInputElement::minimumString() const 247{ 248 return m_inputType->serialize(minimum()); 249} 250 251String HTMLInputElement::maximumString() const 252{ 253 return m_inputType->serialize(maximum()); 254} 255 256String HTMLInputElement::stepBaseString() const 257{ 258 return m_inputType->serialize(m_inputType->stepBase()); 259} 260 261String 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 272String HTMLInputElement::typeMismatchText() const 273{ 274 return m_inputType->typeMismatchText(); 275} 276 277String HTMLInputElement::valueMissingText() const 278{ 279 return m_inputType->valueMissingText(); 280} 281 282bool HTMLInputElement::getAllowedValueStep(double* step) const 283{ 284 return getAllowedValueStepWithDecimalPlaces(step, 0); 285} 286 287bool 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 328void 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 378void HTMLInputElement::stepUp(int n, ExceptionCode& ec) 379{ 380 applyStep(n, ec); 381} 382 383void HTMLInputElement::stepDown(int n, ExceptionCode& ec) 384{ 385 applyStep(-n, ec); 386} 387 388bool HTMLInputElement::isKeyboardFocusable(KeyboardEvent* event) const 389{ 390 if (isTextField()) 391 return HTMLFormControlElementWithState::isFocusable(); 392 return HTMLFormControlElementWithState::isKeyboardFocusable(event) && m_inputType->isKeyboardFocusable(); 393} 394 395bool HTMLInputElement::isMouseFocusable() const 396{ 397 if (isTextField()) 398 return HTMLFormControlElementWithState::isFocusable(); 399 return HTMLFormControlElementWithState::isMouseFocusable(); 400} 401 402void HTMLInputElement::updateFocusAppearance(bool restorePreviousSelection) 403{ 404 if (isTextField()) 405 InputElement::updateFocusAppearance(m_data, this, this, restorePreviousSelection); 406 else 407 HTMLFormControlElementWithState::updateFocusAppearance(restorePreviousSelection); 408} 409 410void HTMLInputElement::aboutToUnload() 411{ 412 InputElement::aboutToUnload(this, this); 413} 414 415bool HTMLInputElement::shouldUseInputMethod() const 416{ 417 return m_inputType->shouldUseInputMethod(); 418} 419 420void HTMLInputElement::handleFocusEvent() 421{ 422 InputElement::dispatchFocusEvent(this, this); 423} 424 425void HTMLInputElement::handleBlurEvent() 426{ 427 m_inputType->handleBlurEvent(); 428 InputElement::dispatchBlurEvent(this, this); 429} 430 431void 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 444void 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 516const AtomicString& HTMLInputElement::formControlType() const 517{ 518 return m_inputType->formControlType(); 519} 520 521bool HTMLInputElement::saveFormControlState(String& result) const 522{ 523 return m_inputType->saveFormControlState(result); 524} 525 526void HTMLInputElement::restoreFormControlState(const String& state) 527{ 528 m_inputType->restoreFormControlState(state); 529 m_stateRestored = true; 530} 531 532bool HTMLInputElement::canStartSelection() const 533{ 534 if (!isTextField()) 535 return false; 536 return HTMLFormControlElementWithState::canStartSelection(); 537} 538 539bool HTMLInputElement::canHaveSelection() const 540{ 541 return isTextField(); 542} 543 544void HTMLInputElement::accessKeyAction(bool sendToAnyElement) 545{ 546 m_inputType->accessKeyAction(sendToAnyElement); 547} 548 549bool 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 567void 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 674void 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 686bool HTMLInputElement::rendererIsNeeded(RenderStyle* style) 687{ 688 return m_inputType->rendererIsNeeded() && HTMLFormControlElementWithState::rendererIsNeeded(style); 689} 690 691RenderObject* HTMLInputElement::createRenderer(RenderArena* arena, RenderStyle* style) 692{ 693 return m_inputType->createRenderer(arena, style); 694} 695 696void 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 713void HTMLInputElement::detach() 714{ 715 HTMLFormControlElementWithState::detach(); 716 setFormControlValueMatchesRenderer(false); 717} 718 719String 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 735bool 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 742bool HTMLInputElement::isActivatedSubmit() const 743{ 744 return m_isActivatedSubmit; 745} 746 747void HTMLInputElement::setActivatedSubmit(bool flag) 748{ 749 m_isActivatedSubmit = flag; 750} 751 752bool HTMLInputElement::appendFormData(FormDataList& encoding, bool multipart) 753{ 754 return m_inputType->isFormDataAppendable() && m_inputType->appendFormData(encoding, multipart); 755} 756 757void 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 767bool HTMLInputElement::isTextField() const 768{ 769 return m_inputType->isTextField(); 770} 771 772bool HTMLInputElement::isTextType() const 773{ 774 return m_inputType->isTextType(); 775} 776 777void 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 808void 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 821int HTMLInputElement::size() const 822{ 823 return m_data.size(); 824} 825 826void 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 838String 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 855String HTMLInputElement::valueWithDefault() const 856{ 857 String value = this->value(); 858 if (!value.isNull()) 859 return value; 860 861 return m_inputType->defaultValue(); 862} 863 864void HTMLInputElement::setValueForUser(const String& value) 865{ 866 // Call setValue and make it send a change event. 867 setValue(value, true); 868} 869 870const String& HTMLInputElement::suggestedValue() const 871{ 872 return m_data.suggestedValue(); 873} 874 875void 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 887void 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 936double HTMLInputElement::valueAsDate() const 937{ 938 return m_inputType->valueAsDate(); 939} 940 941void HTMLInputElement::setValueAsDate(double value, ExceptionCode& ec) 942{ 943 m_inputType->setValueAsDate(value, ec); 944} 945 946double HTMLInputElement::valueAsNumber() const 947{ 948 return m_inputType->valueAsNumber(); 949} 950 951void 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 960String HTMLInputElement::placeholder() const 961{ 962 return fastGetAttribute(placeholderAttr).string(); 963} 964 965void HTMLInputElement::setPlaceholder(const String& value) 966{ 967 setAttribute(placeholderAttr, value); 968} 969 970bool HTMLInputElement::searchEventsShouldBeDispatched() const 971{ 972 return hasAttribute(incrementalAttr); 973} 974 975void 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 989void HTMLInputElement::setFileListFromRenderer(const Vector<String>& paths) 990{ 991 m_inputType->setFileList(paths); 992 993 setFormControlValueMatchesRenderer(true); 994 InputElement::notifyFormStateChanged(this); 995 setNeedsValidityCheck(); 996} 997 998void* 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 1012void 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 1020void 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 1115bool HTMLInputElement::isURLAttribute(Attribute *attr) const 1116{ 1117 return (attr->name() == srcAttr || attr->name() == formactionAttr); 1118} 1119 1120String HTMLInputElement::defaultValue() const 1121{ 1122 return fastGetAttribute(valueAttr); 1123} 1124 1125void HTMLInputElement::setDefaultValue(const String &value) 1126{ 1127 setAttribute(valueAttr, value); 1128} 1129 1130void HTMLInputElement::setDefaultName(const AtomicString& name) 1131{ 1132 m_data.setName(name); 1133} 1134 1135String HTMLInputElement::accept() const 1136{ 1137 return fastGetAttribute(acceptAttr); 1138} 1139 1140String HTMLInputElement::alt() const 1141{ 1142 return fastGetAttribute(altAttr); 1143} 1144 1145int HTMLInputElement::maxLength() const 1146{ 1147 return m_data.maxLength(); 1148} 1149 1150void 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 1158bool HTMLInputElement::multiple() const 1159{ 1160 return fastHasAttribute(multipleAttr); 1161} 1162 1163void HTMLInputElement::setSize(unsigned size) 1164{ 1165 setAttribute(sizeAttr, String::number(size)); 1166} 1167 1168KURL HTMLInputElement::src() const 1169{ 1170 return document()->completeURL(fastGetAttribute(srcAttr)); 1171} 1172 1173void HTMLInputElement::setAutofilled(bool autofilled) 1174{ 1175 if (autofilled == m_isAutofilled) 1176 return; 1177 1178 m_isAutofilled = autofilled; 1179 setNeedsStyleRecalc(); 1180} 1181 1182FileList* HTMLInputElement::files() 1183{ 1184 return m_inputType->files(); 1185} 1186 1187String HTMLInputElement::visibleValue() const 1188{ 1189 return m_inputType->visibleValue(); 1190} 1191 1192String HTMLInputElement::convertFromVisibleValue(const String& visibleValue) const 1193{ 1194 return m_inputType->convertFromVisibleValue(visibleValue); 1195} 1196 1197bool HTMLInputElement::isAcceptableValue(const String& proposedValue) const 1198{ 1199 return m_inputType->isAcceptableValue(proposedValue); 1200} 1201 1202String HTMLInputElement::sanitizeValue(const String& proposedValue) const 1203{ 1204 return m_inputType->sanitizeValue(proposedValue); 1205} 1206 1207bool HTMLInputElement::hasUnacceptableValue() const 1208{ 1209 return m_inputType->hasUnacceptableValue(); 1210} 1211 1212bool HTMLInputElement::isInRange() const 1213{ 1214 return m_inputType->supportsRangeLimitation() && !rangeUnderflow(value()) && !rangeOverflow(value()); 1215} 1216 1217bool HTMLInputElement::isOutOfRange() const 1218{ 1219 return m_inputType->supportsRangeLimitation() && (rangeUnderflow(value()) || rangeOverflow(value())); 1220} 1221 1222bool HTMLInputElement::needsActivationCallback() 1223{ 1224 return m_autocomplete == Off || m_inputType->shouldResetOnDocumentActivation(); 1225} 1226 1227void HTMLInputElement::registerForActivationCallbackIfNeeded() 1228{ 1229 if (needsActivationCallback()) 1230 document()->registerForDocumentActivationCallbacks(this); 1231} 1232 1233void HTMLInputElement::unregisterForActivationCallbackIfNeeded() 1234{ 1235 if (!needsActivationCallback()) 1236 document()->unregisterForDocumentActivationCallbacks(this); 1237} 1238 1239bool HTMLInputElement::isRequiredFormControl() const 1240{ 1241 return m_inputType->supportsRequired() && required(); 1242} 1243 1244void HTMLInputElement::cacheSelection(int start, int end) 1245{ 1246 m_data.setCachedSelectionStart(start); 1247 m_data.setCachedSelectionEnd(end); 1248} 1249 1250void HTMLInputElement::addSearchResult() 1251{ 1252 ASSERT(isSearchField()); 1253 if (renderer()) 1254 toRenderTextControlSingleLine(renderer())->addSearchResult(); 1255} 1256 1257void HTMLInputElement::onSearch() 1258{ 1259 ASSERT(isSearchField()); 1260 if (renderer()) 1261 toRenderTextControlSingleLine(renderer())->stopSearchEventTimer(); 1262 dispatchEvent(Event::create(eventNames().searchEvent, true, false)); 1263} 1264 1265void HTMLInputElement::documentDidBecomeActive() 1266{ 1267 ASSERT(needsActivationCallback()); 1268 reset(); 1269} 1270 1271void 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 1284void HTMLInputElement::didMoveToNewOwnerDocument() 1285{ 1286 registerForActivationCallbackIfNeeded(); 1287 1288 HTMLFormControlElementWithState::didMoveToNewOwnerDocument(); 1289} 1290 1291void HTMLInputElement::addSubresourceAttributeURLs(ListHashSet<KURL>& urls) const 1292{ 1293 HTMLFormControlElementWithState::addSubresourceAttributeURLs(urls); 1294 1295 addSubresourceURL(urls, src()); 1296} 1297 1298bool HTMLInputElement::recalcWillValidate() const 1299{ 1300 return m_inputType->supportsValidation() && HTMLFormControlElementWithState::recalcWillValidate(); 1301} 1302 1303#if ENABLE(DATALIST) 1304 1305HTMLElement* HTMLInputElement::list() const 1306{ 1307 return dataList(); 1308} 1309 1310HTMLDataListElement* 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 1327HTMLOptionElement* 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 1353void 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 1466void 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 1477bool 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 1485bool HTMLInputElement::isTextButton() const 1486{ 1487 return m_inputType->isTextButton(); 1488} 1489 1490bool HTMLInputElement::isRadioButton() const 1491{ 1492 return m_inputType->isRadioButton(); 1493} 1494 1495bool HTMLInputElement::isSearchField() const 1496{ 1497 return m_inputType->isSearchField(); 1498} 1499 1500bool HTMLInputElement::isInputTypeHidden() const 1501{ 1502 return m_inputType->isHiddenType(); 1503} 1504 1505bool HTMLInputElement::isPasswordField() const 1506{ 1507 return m_inputType->isPasswordField(); 1508} 1509 1510bool HTMLInputElement::isCheckbox() const 1511{ 1512 return m_inputType->isCheckbox(); 1513} 1514 1515bool HTMLInputElement::isText() const 1516{ 1517 return m_inputType->isTextType(); 1518} 1519 1520bool HTMLInputElement::isEmailField() const 1521{ 1522 return m_inputType->isEmailField(); 1523} 1524 1525bool HTMLInputElement::isFileUpload() const 1526{ 1527 return m_inputType->isFileUpload(); 1528} 1529 1530bool HTMLInputElement::isImageButton() const 1531{ 1532 return m_inputType->isImageButton(); 1533} 1534 1535bool HTMLInputElement::isNumberField() const 1536{ 1537 return m_inputType->isNumberField(); 1538} 1539 1540bool HTMLInputElement::isSubmitButton() const 1541{ 1542 return m_inputType->isSubmitButton(); 1543} 1544 1545bool HTMLInputElement::isTelephoneField() const 1546{ 1547 return m_inputType->isTelephoneField(); 1548} 1549 1550bool HTMLInputElement::isURLField() const 1551{ 1552 return m_inputType->isURLField(); 1553} 1554 1555bool HTMLInputElement::isEnumeratable() const 1556{ 1557 return m_inputType->isEnumeratable(); 1558} 1559 1560bool HTMLInputElement::isChecked() const 1561{ 1562 return checked() && m_inputType->isCheckable(); 1563} 1564 1565bool HTMLInputElement::hasSpinButton() const 1566{ 1567 return m_inputType->hasSpinButton(); 1568} 1569 1570bool HTMLInputElement::supportsPlaceholder() const 1571{ 1572#if PLATFORM(ANDROID) 1573 return isTextType() || isNumberField(); 1574#else 1575 return isTextType(); 1576#endif 1577} 1578 1579CheckedRadioButtons& HTMLInputElement::checkedRadioButtons() const 1580{ 1581 if (HTMLFormElement* formElement = form()) 1582 return formElement->checkedRadioButtons(); 1583 return document()->checkedRadioButtons(); 1584} 1585 1586void HTMLInputElement::handleBeforeTextInsertedEvent(Event* event) 1587{ 1588 InputElement::handleBeforeTextInsertedEvent(m_data, this, this, event); 1589} 1590 1591#if PLATFORM(ANDROID) && ENABLE(MEDIA_CAPTURE) 1592String 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