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 #ifdef ANDROID_ACCEPT_CHANGES_TO_FOCUSED_TEXTFIELDS 448 if (newType->isPasswordField() && document()->focusedNode() == this) 449 PlatformBridge::updateTextfield(document()->view(), this, true, String()); 450 #endif 451 bool hadType = m_hasType; 452 m_hasType = true; 453 if (m_inputType->formControlType() == newType->formControlType()) 454 return; 455 456 if (hadType && !newType->canChangeFromAnotherType()) { 457 // Set the attribute back to the old value. 458 // Useful in case we were called from inside parseMappedAttribute. 459 setAttribute(typeAttr, type()); 460 return; 461 } 462 463 checkedRadioButtons().removeButton(this); 464 465 bool wasAttached = attached(); 466 if (wasAttached) 467 detach(); 468 469 bool didStoreValue = m_inputType->storesValueSeparateFromAttribute(); 470 bool neededActivationCallback = needsActivationCallback(); 471 bool didRespectHeightAndWidth = m_inputType->shouldRespectHeightAndWidthAttributes(); 472 473 m_inputType->destroyShadowSubtree(); 474 m_inputType = newType.release(); 475 m_inputType->createShadowSubtree(); 476 477 setNeedsWillValidateCheck(); 478 479 bool willStoreValue = m_inputType->storesValueSeparateFromAttribute(); 480 481 if (didStoreValue && !willStoreValue && !m_data.value().isNull()) { 482 setAttribute(valueAttr, m_data.value()); 483 m_data.setValue(String()); 484 } 485 if (!didStoreValue && willStoreValue) 486 m_data.setValue(sanitizeValue(fastGetAttribute(valueAttr))); 487 else 488 InputElement::updateValueIfNeeded(m_data, this); 489 490 if (neededActivationCallback) 491 unregisterForActivationCallbackIfNeeded(); 492 else 493 registerForActivationCallbackIfNeeded(); 494 495 if (didRespectHeightAndWidth != m_inputType->shouldRespectHeightAndWidthAttributes()) { 496 NamedNodeMap* map = attributeMap(); 497 ASSERT(map); 498 if (Attribute* height = map->getAttributeItem(heightAttr)) 499 attributeChanged(height, false); 500 if (Attribute* width = map->getAttributeItem(widthAttr)) 501 attributeChanged(width, false); 502 if (Attribute* align = map->getAttributeItem(alignAttr)) 503 attributeChanged(align, false); 504 } 505 506 if (wasAttached) { 507 attach(); 508 if (document()->focusedNode() == this) 509 updateFocusAppearance(true); 510 } 511 512 setChangedSinceLastFormControlChangeEvent(false); 513 514 checkedRadioButtons().addButton(this); 515 516 setNeedsValidityCheck(); 517 InputElement::notifyFormStateChanged(this); 518 } 519 520 const AtomicString& HTMLInputElement::formControlType() const 521 { 522 return m_inputType->formControlType(); 523 } 524 525 bool HTMLInputElement::saveFormControlState(String& result) const 526 { 527 return m_inputType->saveFormControlState(result); 528 } 529 530 void HTMLInputElement::restoreFormControlState(const String& state) 531 { 532 m_inputType->restoreFormControlState(state); 533 m_stateRestored = true; 534 } 535 536 bool HTMLInputElement::canStartSelection() const 537 { 538 if (!isTextField()) 539 return false; 540 return HTMLFormControlElementWithState::canStartSelection(); 541 } 542 543 bool HTMLInputElement::canHaveSelection() const 544 { 545 return isTextField(); 546 } 547 548 void HTMLInputElement::accessKeyAction(bool sendToAnyElement) 549 { 550 m_inputType->accessKeyAction(sendToAnyElement); 551 } 552 553 bool HTMLInputElement::mapToEntry(const QualifiedName& attrName, MappedAttributeEntry& result) const 554 { 555 if (((attrName == heightAttr || attrName == widthAttr) && m_inputType->shouldRespectHeightAndWidthAttributes()) 556 || attrName == vspaceAttr 557 || attrName == hspaceAttr) { 558 result = eUniversal; 559 return false; 560 } 561 562 if (attrName == alignAttr && m_inputType->shouldRespectAlignAttribute()) { 563 // Share with <img> since the alignment behavior is the same. 564 result = eReplaced; 565 return false; 566 } 567 568 return HTMLElement::mapToEntry(attrName, result); 569 } 570 571 void HTMLInputElement::parseMappedAttribute(Attribute* attr) 572 { 573 if (attr->name() == nameAttr) { 574 checkedRadioButtons().removeButton(this); 575 m_data.setName(attr->value()); 576 checkedRadioButtons().addButton(this); 577 HTMLFormControlElementWithState::parseMappedAttribute(attr); 578 } else if (attr->name() == autocompleteAttr) { 579 if (equalIgnoringCase(attr->value(), "off")) { 580 m_autocomplete = Off; 581 registerForActivationCallbackIfNeeded(); 582 } else { 583 bool needsToUnregister = m_autocomplete == Off; 584 585 if (attr->isEmpty()) 586 m_autocomplete = Uninitialized; 587 else 588 m_autocomplete = On; 589 590 if (needsToUnregister) 591 unregisterForActivationCallbackIfNeeded(); 592 } 593 } else if (attr->name() == typeAttr) { 594 updateType(); 595 } else if (attr->name() == valueAttr) { 596 // We only need to setChanged if the form is looking at the default value right now. 597 if (m_data.value().isNull()) 598 setNeedsStyleRecalc(); 599 setFormControlValueMatchesRenderer(false); 600 setNeedsValidityCheck(); 601 } else if (attr->name() == checkedAttr) { 602 // Another radio button in the same group might be checked by state 603 // restore. We shouldn't call setChecked() even if this has the checked 604 // attribute. So, delay the setChecked() call until 605 // finishParsingChildren() is called if parsing is in progress. 606 if (!m_parsingInProgress && m_reflectsCheckedAttribute) { 607 setChecked(!attr->isNull()); 608 m_reflectsCheckedAttribute = true; 609 } 610 } else if (attr->name() == maxlengthAttr) { 611 InputElement::parseMaxLengthAttribute(m_data, this, this, attr); 612 setNeedsValidityCheck(); 613 } else if (attr->name() == sizeAttr) 614 InputElement::parseSizeAttribute(m_data, this, attr); 615 else if (attr->name() == altAttr) 616 m_inputType->altAttributeChanged(); 617 else if (attr->name() == srcAttr) 618 m_inputType->srcAttributeChanged(); 619 else if (attr->name() == usemapAttr || attr->name() == accesskeyAttr) { 620 // FIXME: ignore for the moment 621 } else if (attr->name() == vspaceAttr) { 622 addCSSLength(attr, CSSPropertyMarginTop, attr->value()); 623 addCSSLength(attr, CSSPropertyMarginBottom, attr->value()); 624 } else if (attr->name() == hspaceAttr) { 625 addCSSLength(attr, CSSPropertyMarginLeft, attr->value()); 626 addCSSLength(attr, CSSPropertyMarginRight, attr->value()); 627 } else if (attr->name() == alignAttr) { 628 if (m_inputType->shouldRespectAlignAttribute()) 629 addHTMLAlignment(attr); 630 } else if (attr->name() == widthAttr) { 631 if (m_inputType->shouldRespectHeightAndWidthAttributes()) 632 addCSSLength(attr, CSSPropertyWidth, attr->value()); 633 } else if (attr->name() == heightAttr) { 634 if (m_inputType->shouldRespectHeightAndWidthAttributes()) 635 addCSSLength(attr, CSSPropertyHeight, attr->value()); 636 } else if (attr->name() == onsearchAttr) { 637 // Search field and slider attributes all just cause updateFromElement to be called through style recalcing. 638 setAttributeEventListener(eventNames().searchEvent, createAttributeEventListener(this, attr)); 639 } else if (attr->name() == resultsAttr) { 640 int oldResults = m_maxResults; 641 m_maxResults = !attr->isNull() ? std::min(attr->value().toInt(), maxSavedResults) : -1; 642 // FIXME: Detaching just for maxResults change is not ideal. We should figure out the right 643 // time to relayout for this change. 644 if (m_maxResults != oldResults && (m_maxResults <= 0 || oldResults <= 0) && attached()) { 645 detach(); 646 attach(); 647 } 648 setNeedsStyleRecalc(); 649 } else if (attr->name() == autosaveAttr || attr->name() == incrementalAttr) 650 setNeedsStyleRecalc(); 651 else if (attr->name() == minAttr || attr->name() == maxAttr) { 652 m_inputType->minOrMaxAttributeChanged(); 653 setNeedsValidityCheck(); 654 } else if (attr->name() == multipleAttr || attr->name() == patternAttr || attr->name() == precisionAttr || attr->name() == stepAttr) 655 setNeedsValidityCheck(); 656 #if ENABLE(DATALIST) 657 else if (attr->name() == listAttr) 658 m_hasNonEmptyList = !attr->isEmpty(); 659 // FIXME: we need to tell this change to a renderer if the attribute affects the appearance. 660 #endif 661 #if ENABLE(INPUT_SPEECH) 662 else if (attr->name() == webkitspeechAttr) { 663 if (renderer()) { 664 // This renderer and its children have quite different layouts and styles depending on 665 // whether the speech button is visible or not. So we reset the whole thing and recreate 666 // to get the right styles and layout. 667 detach(); 668 attach(); 669 } 670 setNeedsStyleRecalc(); 671 } else if (attr->name() == onwebkitspeechchangeAttr) 672 setAttributeEventListener(eventNames().webkitspeechchangeEvent, createAttributeEventListener(this, attr)); 673 #endif 674 else 675 HTMLTextFormControlElement::parseMappedAttribute(attr); 676 } 677 678 void HTMLInputElement::finishParsingChildren() 679 { 680 m_parsingInProgress = false; 681 HTMLFormControlElementWithState::finishParsingChildren(); 682 if (!m_stateRestored) { 683 bool checked = hasAttribute(checkedAttr); 684 if (checked) 685 setChecked(checked); 686 m_reflectsCheckedAttribute = true; 687 } 688 } 689 690 bool HTMLInputElement::rendererIsNeeded(RenderStyle* style) 691 { 692 return m_inputType->rendererIsNeeded() && HTMLFormControlElementWithState::rendererIsNeeded(style); 693 } 694 695 RenderObject* HTMLInputElement::createRenderer(RenderArena* arena, RenderStyle* style) 696 { 697 return m_inputType->createRenderer(arena, style); 698 } 699 700 void HTMLInputElement::attach() 701 { 702 suspendPostAttachCallbacks(); 703 704 if (!m_hasType) 705 updateType(); 706 707 HTMLFormControlElementWithState::attach(); 708 709 m_inputType->attach(); 710 711 if (document()->focusedNode() == this) 712 document()->updateFocusAppearanceSoon(true /* restore selection */); 713 714 resumePostAttachCallbacks(); 715 } 716 717 void HTMLInputElement::detach() 718 { 719 HTMLFormControlElementWithState::detach(); 720 setFormControlValueMatchesRenderer(false); 721 } 722 723 String HTMLInputElement::altText() const 724 { 725 // http://www.w3.org/TR/1998/REC-html40-19980424/appendix/notes.html#altgen 726 // also heavily discussed by Hixie on bugzilla 727 // note this is intentionally different to HTMLImageElement::altText() 728 String alt = fastGetAttribute(altAttr); 729 // fall back to title attribute 730 if (alt.isNull()) 731 alt = getAttribute(titleAttr); 732 if (alt.isNull()) 733 alt = getAttribute(valueAttr); 734 if (alt.isEmpty()) 735 alt = inputElementAltText(); 736 return alt; 737 } 738 739 bool HTMLInputElement::isSuccessfulSubmitButton() const 740 { 741 // HTML spec says that buttons must have names to be considered successful. 742 // However, other browsers do not impose this constraint. So we do not. 743 return !disabled() && m_inputType->canBeSuccessfulSubmitButton(); 744 } 745 746 bool HTMLInputElement::isActivatedSubmit() const 747 { 748 return m_isActivatedSubmit; 749 } 750 751 void HTMLInputElement::setActivatedSubmit(bool flag) 752 { 753 m_isActivatedSubmit = flag; 754 } 755 756 bool HTMLInputElement::appendFormData(FormDataList& encoding, bool multipart) 757 { 758 return m_inputType->isFormDataAppendable() && m_inputType->appendFormData(encoding, multipart); 759 } 760 761 void HTMLInputElement::reset() 762 { 763 if (m_inputType->storesValueSeparateFromAttribute()) 764 setValue(String()); 765 766 setAutofilled(false); 767 setChecked(hasAttribute(checkedAttr)); 768 m_reflectsCheckedAttribute = true; 769 } 770 771 bool HTMLInputElement::isTextField() const 772 { 773 return m_inputType->isTextField(); 774 } 775 776 bool HTMLInputElement::isTextType() const 777 { 778 return m_inputType->isTextType(); 779 } 780 781 void HTMLInputElement::setChecked(bool nowChecked, bool sendChangeEvent) 782 { 783 if (checked() == nowChecked) 784 return; 785 786 checkedRadioButtons().removeButton(this); 787 788 m_reflectsCheckedAttribute = false; 789 m_isChecked = nowChecked; 790 setNeedsStyleRecalc(); 791 792 updateCheckedRadioButtons(); 793 setNeedsValidityCheck(); 794 795 // Ideally we'd do this from the render tree (matching 796 // RenderTextView), but it's not possible to do it at the moment 797 // because of the way the code is structured. 798 if (renderer() && AXObjectCache::accessibilityEnabled()) 799 renderer()->document()->axObjectCache()->postNotification(renderer(), AXObjectCache::AXCheckedStateChanged, true); 800 801 // Only send a change event for items in the document (avoid firing during 802 // parsing) and don't send a change event for a radio button that's getting 803 // unchecked to match other browsers. DOM is not a useful standard for this 804 // because it says only to fire change events at "lose focus" time, which is 805 // definitely wrong in practice for these types of elements. 806 if (sendChangeEvent && inDocument() && m_inputType->shouldSendChangeEventAfterCheckedChanged()) { 807 setTextAsOfLastFormControlChangeEvent(String()); 808 dispatchFormControlChangeEvent(); 809 } 810 } 811 812 void HTMLInputElement::setIndeterminate(bool newValue) 813 { 814 if (!m_inputType->isCheckable() || indeterminate() == newValue) 815 return; 816 817 m_isIndeterminate = newValue; 818 819 setNeedsStyleRecalc(); 820 821 if (renderer() && renderer()->style()->hasAppearance()) 822 renderer()->theme()->stateChanged(renderer(), CheckedState); 823 } 824 825 int HTMLInputElement::size() const 826 { 827 return m_data.size(); 828 } 829 830 void HTMLInputElement::copyNonAttributeProperties(const Element* source) 831 { 832 const HTMLInputElement* sourceElement = static_cast<const HTMLInputElement*>(source); 833 834 m_data.setValue(sourceElement->m_data.value()); 835 setChecked(sourceElement->m_isChecked); 836 m_reflectsCheckedAttribute = sourceElement->m_reflectsCheckedAttribute; 837 m_isIndeterminate = sourceElement->m_isIndeterminate; 838 839 HTMLFormControlElementWithState::copyNonAttributeProperties(source); 840 } 841 842 String HTMLInputElement::value() const 843 { 844 String value; 845 if (m_inputType->getTypeSpecificValue(value)) 846 return value; 847 848 value = m_data.value(); 849 if (!value.isNull()) 850 return value; 851 852 value = sanitizeValue(fastGetAttribute(valueAttr)); 853 if (!value.isNull()) 854 return value; 855 856 return m_inputType->fallbackValue(); 857 } 858 859 String HTMLInputElement::valueWithDefault() const 860 { 861 String value = this->value(); 862 if (!value.isNull()) 863 return value; 864 865 return m_inputType->defaultValue(); 866 } 867 868 void HTMLInputElement::setValueForUser(const String& value) 869 { 870 // Call setValue and make it send a change event. 871 setValue(value, true); 872 } 873 874 const String& HTMLInputElement::suggestedValue() const 875 { 876 return m_data.suggestedValue(); 877 } 878 879 void HTMLInputElement::setSuggestedValue(const String& value) 880 { 881 if (!m_inputType->canSetSuggestedValue()) 882 return; 883 setFormControlValueMatchesRenderer(false); 884 m_data.setSuggestedValue(sanitizeValue(value)); 885 updatePlaceholderVisibility(false); 886 if (renderer()) 887 renderer()->updateFromElement(); 888 setNeedsStyleRecalc(); 889 } 890 891 void HTMLInputElement::setValue(const String& value, bool sendChangeEvent) 892 { 893 if (!m_inputType->canSetValue(value)) 894 return; 895 896 setFormControlValueMatchesRenderer(false); 897 if (m_inputType->storesValueSeparateFromAttribute()) { 898 if (files()) 899 files()->clear(); 900 else { 901 m_data.setValue(sanitizeValue(value)); 902 if (isTextField()) 903 updatePlaceholderVisibility(false); 904 } 905 setNeedsStyleRecalc(); 906 } else 907 setAttribute(valueAttr, sanitizeValue(value)); 908 909 setNeedsValidityCheck(); 910 911 if (isTextField()) { 912 unsigned max = m_data.value().length(); 913 #ifdef ANDROID_ACCEPT_CHANGES_TO_FOCUSED_TEXTFIELDS 914 // Make sure our UI side textfield changes to match the RenderTextControl 915 PlatformBridge::updateTextfield(document()->view(), this, false, value); 916 #endif 917 if (document()->focusedNode() == this) 918 InputElement::updateSelectionRange(this, this, max, max); 919 else 920 cacheSelection(max, max); 921 m_data.setSuggestedValue(String()); 922 } 923 m_inputType->valueChanged(); 924 925 if (sendChangeEvent) { 926 // If the user is still editing this field, dispatch an input event rather than a change event. 927 // The change event will be dispatched when editing finishes. 928 if (isTextField() && focused()) 929 dispatchFormControlInputEvent(); 930 else 931 dispatchFormControlChangeEvent(); 932 } 933 934 if (isText() && (!focused() || !sendChangeEvent)) 935 setTextAsOfLastFormControlChangeEvent(value); 936 937 InputElement::notifyFormStateChanged(this); 938 } 939 940 double HTMLInputElement::valueAsDate() const 941 { 942 return m_inputType->valueAsDate(); 943 } 944 945 void HTMLInputElement::setValueAsDate(double value, ExceptionCode& ec) 946 { 947 m_inputType->setValueAsDate(value, ec); 948 } 949 950 double HTMLInputElement::valueAsNumber() const 951 { 952 return m_inputType->valueAsNumber(); 953 } 954 955 void HTMLInputElement::setValueAsNumber(double newValue, ExceptionCode& ec) 956 { 957 if (!isfinite(newValue)) { 958 ec = NOT_SUPPORTED_ERR; 959 return; 960 } 961 m_inputType->setValueAsNumber(newValue, ec); 962 } 963 964 String HTMLInputElement::placeholder() const 965 { 966 return fastGetAttribute(placeholderAttr).string(); 967 } 968 969 void HTMLInputElement::setPlaceholder(const String& value) 970 { 971 setAttribute(placeholderAttr, value); 972 } 973 974 bool HTMLInputElement::searchEventsShouldBeDispatched() const 975 { 976 return hasAttribute(incrementalAttr); 977 } 978 979 void HTMLInputElement::setValueFromRenderer(const String& value) 980 { 981 // File upload controls will always use setFileListFromRenderer. 982 ASSERT(!isFileUpload()); 983 984 m_data.setSuggestedValue(String()); 985 InputElement::setValueFromRenderer(m_data, this, this, value); 986 updatePlaceholderVisibility(false); 987 setNeedsValidityCheck(); 988 989 // Clear autofill flag (and yellow background) on user edit. 990 setAutofilled(false); 991 } 992 993 void HTMLInputElement::setFileListFromRenderer(const Vector<String>& paths) 994 { 995 m_inputType->setFileList(paths); 996 997 setFormControlValueMatchesRenderer(true); 998 InputElement::notifyFormStateChanged(this); 999 setNeedsValidityCheck(); 1000 } 1001 1002 void* HTMLInputElement::preDispatchEventHandler(Event* event) 1003 { 1004 if (event->type() == eventNames().textInputEvent && m_inputType->shouldSubmitImplicitly(event)) { 1005 event->stopPropagation(); 1006 return 0; 1007 } 1008 if (event->type() != eventNames().clickEvent) 1009 return 0; 1010 if (!event->isMouseEvent() || static_cast<MouseEvent*>(event)->button() != LeftButton) 1011 return 0; 1012 // FIXME: Check whether there are any cases where this actually ends up leaking. 1013 return m_inputType->willDispatchClick().leakPtr(); 1014 } 1015 1016 void HTMLInputElement::postDispatchEventHandler(Event* event, void* dataFromPreDispatch) 1017 { 1018 OwnPtr<ClickHandlingState> state = adoptPtr(static_cast<ClickHandlingState*>(dataFromPreDispatch)); 1019 if (!state) 1020 return; 1021 m_inputType->didDispatchClick(event, *state); 1022 } 1023 1024 void HTMLInputElement::defaultEventHandler(Event* evt) 1025 { 1026 if (evt->isMouseEvent() && evt->type() == eventNames().clickEvent && static_cast<MouseEvent*>(evt)->button() == LeftButton) { 1027 m_inputType->handleClickEvent(static_cast<MouseEvent*>(evt)); 1028 if (evt->defaultHandled()) 1029 return; 1030 } 1031 1032 if (evt->isKeyboardEvent() && evt->type() == eventNames().keydownEvent) { 1033 m_inputType->handleKeydownEvent(static_cast<KeyboardEvent*>(evt)); 1034 if (evt->defaultHandled()) 1035 return; 1036 } 1037 1038 // Call the base event handler before any of our own event handling for almost all events in text fields. 1039 // Makes editing keyboard handling take precedence over the keydown and keypress handling in this function. 1040 bool callBaseClassEarly = isTextField() && (evt->type() == eventNames().keydownEvent || evt->type() == eventNames().keypressEvent); 1041 if (callBaseClassEarly) { 1042 HTMLFormControlElementWithState::defaultEventHandler(evt); 1043 if (evt->defaultHandled()) 1044 return; 1045 } 1046 1047 // DOMActivate events cause the input to be "activated" - in the case of image and submit inputs, this means 1048 // actually submitting the form. For reset inputs, the form is reset. These events are sent when the user clicks 1049 // on the element, or presses enter while it is the active element. JavaScript code wishing to activate the element 1050 // must dispatch a DOMActivate event - a click event will not do the job. 1051 if (evt->type() == eventNames().DOMActivateEvent) { 1052 m_inputType->handleDOMActivateEvent(evt); 1053 if (evt->defaultHandled()) 1054 return; 1055 } 1056 1057 // Use key press event here since sending simulated mouse events 1058 // on key down blocks the proper sending of the key press event. 1059 if (evt->isKeyboardEvent() && evt->type() == eventNames().keypressEvent) { 1060 m_inputType->handleKeypressEvent(static_cast<KeyboardEvent*>(evt)); 1061 if (evt->defaultHandled()) 1062 return; 1063 } 1064 1065 if (evt->isKeyboardEvent() && evt->type() == eventNames().keyupEvent) { 1066 m_inputType->handleKeyupEvent(static_cast<KeyboardEvent*>(evt)); 1067 if (evt->defaultHandled()) 1068 return; 1069 } 1070 1071 if (m_inputType->shouldSubmitImplicitly(evt)) { 1072 if (isSearchField()) { 1073 addSearchResult(); 1074 onSearch(); 1075 } 1076 // Form submission finishes editing, just as loss of focus does. 1077 // If there was a change, send the event now. 1078 if (wasChangedSinceLastFormControlChangeEvent()) 1079 dispatchFormControlChangeEvent(); 1080 1081 RefPtr<HTMLFormElement> formForSubmission = m_inputType->formForSubmission(); 1082 // Form may never have been present, or may have been destroyed by code responding to the change event. 1083 if (formForSubmission) 1084 formForSubmission->submitImplicitly(evt, canTriggerImplicitSubmission()); 1085 1086 evt->setDefaultHandled(); 1087 return; 1088 } 1089 1090 if (evt->isBeforeTextInsertedEvent()) 1091 m_inputType->handleBeforeTextInsertedEvent(static_cast<BeforeTextInsertedEvent*>(evt)); 1092 1093 if (evt->isWheelEvent()) { 1094 m_inputType->handleWheelEvent(static_cast<WheelEvent*>(evt)); 1095 if (evt->defaultHandled()) 1096 return; 1097 } 1098 1099 if (evt->isMouseEvent() && evt->type() == eventNames().mousedownEvent) { 1100 m_inputType->handleMouseDownEvent(static_cast<MouseEvent*>(evt)); 1101 if (evt->defaultHandled()) 1102 return; 1103 } 1104 1105 #if PLATFORM(ANDROID) && ENABLE(TOUCH_EVENTS) 1106 if (evt->isTouchEvent() && evt->type() == eventNames().touchstartEvent) { 1107 m_inputType->handleTouchStartEvent(static_cast<TouchEvent*>(evt)); 1108 if (evt->defaultHandled()) 1109 return; 1110 } 1111 #endif 1112 1113 m_inputType->forwardEvent(evt); 1114 1115 if (!callBaseClassEarly && !evt->defaultHandled()) 1116 HTMLFormControlElementWithState::defaultEventHandler(evt); 1117 } 1118 1119 bool HTMLInputElement::isURLAttribute(Attribute *attr) const 1120 { 1121 return (attr->name() == srcAttr || attr->name() == formactionAttr); 1122 } 1123 1124 String HTMLInputElement::defaultValue() const 1125 { 1126 return fastGetAttribute(valueAttr); 1127 } 1128 1129 void HTMLInputElement::setDefaultValue(const String &value) 1130 { 1131 setAttribute(valueAttr, value); 1132 } 1133 1134 void HTMLInputElement::setDefaultName(const AtomicString& name) 1135 { 1136 m_data.setName(name); 1137 } 1138 1139 String HTMLInputElement::accept() const 1140 { 1141 return fastGetAttribute(acceptAttr); 1142 } 1143 1144 String HTMLInputElement::alt() const 1145 { 1146 return fastGetAttribute(altAttr); 1147 } 1148 1149 int HTMLInputElement::maxLength() const 1150 { 1151 return m_data.maxLength(); 1152 } 1153 1154 void HTMLInputElement::setMaxLength(int maxLength, ExceptionCode& ec) 1155 { 1156 if (maxLength < 0) 1157 ec = INDEX_SIZE_ERR; 1158 else 1159 setAttribute(maxlengthAttr, String::number(maxLength)); 1160 } 1161 1162 bool HTMLInputElement::multiple() const 1163 { 1164 return fastHasAttribute(multipleAttr); 1165 } 1166 1167 void HTMLInputElement::setSize(unsigned size) 1168 { 1169 setAttribute(sizeAttr, String::number(size)); 1170 } 1171 1172 KURL HTMLInputElement::src() const 1173 { 1174 return document()->completeURL(fastGetAttribute(srcAttr)); 1175 } 1176 1177 void HTMLInputElement::setAutofilled(bool autofilled) 1178 { 1179 if (autofilled == m_isAutofilled) 1180 return; 1181 1182 m_isAutofilled = autofilled; 1183 setNeedsStyleRecalc(); 1184 } 1185 1186 FileList* HTMLInputElement::files() 1187 { 1188 return m_inputType->files(); 1189 } 1190 1191 String HTMLInputElement::visibleValue() const 1192 { 1193 return m_inputType->visibleValue(); 1194 } 1195 1196 String HTMLInputElement::convertFromVisibleValue(const String& visibleValue) const 1197 { 1198 return m_inputType->convertFromVisibleValue(visibleValue); 1199 } 1200 1201 bool HTMLInputElement::isAcceptableValue(const String& proposedValue) const 1202 { 1203 return m_inputType->isAcceptableValue(proposedValue); 1204 } 1205 1206 String HTMLInputElement::sanitizeValue(const String& proposedValue) const 1207 { 1208 return m_inputType->sanitizeValue(proposedValue); 1209 } 1210 1211 bool HTMLInputElement::hasUnacceptableValue() const 1212 { 1213 return m_inputType->hasUnacceptableValue(); 1214 } 1215 1216 bool HTMLInputElement::isInRange() const 1217 { 1218 return m_inputType->supportsRangeLimitation() && !rangeUnderflow(value()) && !rangeOverflow(value()); 1219 } 1220 1221 bool HTMLInputElement::isOutOfRange() const 1222 { 1223 return m_inputType->supportsRangeLimitation() && (rangeUnderflow(value()) || rangeOverflow(value())); 1224 } 1225 1226 bool HTMLInputElement::needsActivationCallback() 1227 { 1228 return m_autocomplete == Off || m_inputType->shouldResetOnDocumentActivation(); 1229 } 1230 1231 void HTMLInputElement::registerForActivationCallbackIfNeeded() 1232 { 1233 if (needsActivationCallback()) 1234 document()->registerForDocumentActivationCallbacks(this); 1235 } 1236 1237 void HTMLInputElement::unregisterForActivationCallbackIfNeeded() 1238 { 1239 if (!needsActivationCallback()) 1240 document()->unregisterForDocumentActivationCallbacks(this); 1241 } 1242 1243 bool HTMLInputElement::isRequiredFormControl() const 1244 { 1245 return m_inputType->supportsRequired() && required(); 1246 } 1247 1248 void HTMLInputElement::cacheSelection(int start, int end) 1249 { 1250 m_data.setCachedSelectionStart(start); 1251 m_data.setCachedSelectionEnd(end); 1252 } 1253 1254 void HTMLInputElement::addSearchResult() 1255 { 1256 ASSERT(isSearchField()); 1257 if (renderer()) 1258 toRenderTextControlSingleLine(renderer())->addSearchResult(); 1259 } 1260 1261 void HTMLInputElement::onSearch() 1262 { 1263 ASSERT(isSearchField()); 1264 if (renderer()) 1265 toRenderTextControlSingleLine(renderer())->stopSearchEventTimer(); 1266 dispatchEvent(Event::create(eventNames().searchEvent, true, false)); 1267 } 1268 1269 void HTMLInputElement::documentDidBecomeActive() 1270 { 1271 ASSERT(needsActivationCallback()); 1272 reset(); 1273 } 1274 1275 void HTMLInputElement::willMoveToNewOwnerDocument() 1276 { 1277 m_inputType->willMoveToNewOwnerDocument(); 1278 1279 // Always unregister for cache callbacks when leaving a document, even if we would otherwise like to be registered 1280 if (needsActivationCallback()) 1281 document()->unregisterForDocumentActivationCallbacks(this); 1282 1283 document()->checkedRadioButtons().removeButton(this); 1284 1285 HTMLFormControlElementWithState::willMoveToNewOwnerDocument(); 1286 } 1287 1288 void HTMLInputElement::didMoveToNewOwnerDocument() 1289 { 1290 registerForActivationCallbackIfNeeded(); 1291 1292 HTMLFormControlElementWithState::didMoveToNewOwnerDocument(); 1293 } 1294 1295 void HTMLInputElement::addSubresourceAttributeURLs(ListHashSet<KURL>& urls) const 1296 { 1297 HTMLFormControlElementWithState::addSubresourceAttributeURLs(urls); 1298 1299 addSubresourceURL(urls, src()); 1300 } 1301 1302 bool HTMLInputElement::recalcWillValidate() const 1303 { 1304 return m_inputType->supportsValidation() && HTMLFormControlElementWithState::recalcWillValidate(); 1305 } 1306 1307 #if ENABLE(DATALIST) 1308 1309 HTMLElement* HTMLInputElement::list() const 1310 { 1311 return dataList(); 1312 } 1313 1314 HTMLDataListElement* HTMLInputElement::dataList() const 1315 { 1316 if (!m_hasNonEmptyList) 1317 return 0; 1318 1319 if (!m_inputType->shouldRespectListAttribute()) 1320 return 0; 1321 1322 Element* element = document()->getElementById(fastGetAttribute(listAttr)); 1323 if (!element) 1324 return 0; 1325 if (!element->hasTagName(datalistTag)) 1326 return 0; 1327 1328 return static_cast<HTMLDataListElement*>(element); 1329 } 1330 1331 HTMLOptionElement* HTMLInputElement::selectedOption() const 1332 { 1333 String value = this->value(); 1334 1335 // The empty string never matches to a datalist option because it 1336 // doesn't represent a suggestion according to the standard. 1337 if (value.isEmpty()) 1338 return 0; 1339 1340 HTMLDataListElement* sourceElement = dataList(); 1341 if (!sourceElement) 1342 return 0; 1343 RefPtr<HTMLCollection> options = sourceElement->options(); 1344 if (!options) 1345 return 0; 1346 unsigned length = options->length(); 1347 for (unsigned i = 0; i < length; ++i) { 1348 HTMLOptionElement* option = static_cast<HTMLOptionElement*>(options->item(i)); 1349 if (!option->disabled() && value == option->value()) 1350 return option; 1351 } 1352 return 0; 1353 } 1354 1355 #endif // ENABLE(DATALIST) 1356 1357 void HTMLInputElement::stepUpFromRenderer(int n) 1358 { 1359 // The differences from stepUp()/stepDown(): 1360 // 1361 // Difference 1: the current value 1362 // If the current value is not a number, including empty, the current value is assumed as 0. 1363 // * If 0 is in-range, and matches to step value 1364 // - The value should be the +step if n > 0 1365 // - The value should be the -step if n < 0 1366 // If -step or +step is out of range, new value should be 0. 1367 // * If 0 is smaller than the minimum value 1368 // - The value should be the minimum value for any n 1369 // * If 0 is larger than the maximum value 1370 // - The value should be the maximum value for any n 1371 // * If 0 is in-range, but not matched to step value 1372 // - The value should be the larger matched value nearest to 0 if n > 0 1373 // e.g. <input type=number min=-100 step=3> -> 2 1374 // - The value should be the smaler matched value nearest to 0 if n < 0 1375 // e.g. <input type=number min=-100 step=3> -> -1 1376 // As for date/datetime-local/month/time/week types, the current value is assumed as "the current local date/time". 1377 // As for datetime type, the current value is assumed as "the current date/time in UTC". 1378 // If the current value is smaller than the minimum value: 1379 // - The value should be the minimum value if n > 0 1380 // - Nothing should happen if n < 0 1381 // If the current value is larger than the maximum value: 1382 // - The value should be the maximum value if n < 0 1383 // - Nothing should happen if n > 0 1384 // 1385 // Difference 2: clamping steps 1386 // If the current value is not matched to step value: 1387 // - The value should be the larger matched value nearest to 0 if n > 0 1388 // e.g. <input type=number value=3 min=-100 step=3> -> 5 1389 // - The value should be the smaler matched value nearest to 0 if n < 0 1390 // e.g. <input type=number value=3 min=-100 step=3> -> 2 1391 // 1392 // n is assumed as -n if step < 0. 1393 1394 ASSERT(hasSpinButton() || m_inputType->isRangeControl()); 1395 if (!hasSpinButton() && !m_inputType->isRangeControl()) 1396 return; 1397 ASSERT(n); 1398 if (!n) 1399 return; 1400 1401 unsigned stepDecimalPlaces, baseDecimalPlaces; 1402 double step, base; 1403 // The value will be the default value after stepping for <input value=(empty/invalid) step="any" /> 1404 // FIXME: Not any changes after stepping, even if it is an invalid value, may be better. 1405 // (e.g. Stepping-up for <input type="number" value="foo" step="any" /> => "foo") 1406 if (equalIgnoringCase(fastGetAttribute(stepAttr), "any")) 1407 step = 0; 1408 else if (!getAllowedValueStepWithDecimalPlaces(&step, &stepDecimalPlaces)) 1409 return; 1410 base = m_inputType->stepBaseWithDecimalPlaces(&baseDecimalPlaces); 1411 baseDecimalPlaces = min(baseDecimalPlaces, 16u); 1412 1413 int sign; 1414 if (step > 0) 1415 sign = n; 1416 else if (step < 0) 1417 sign = -n; 1418 else 1419 sign = 0; 1420 1421 const double nan = numeric_limits<double>::quiet_NaN(); 1422 String currentStringValue = value(); 1423 double current = m_inputType->parseToDouble(currentStringValue, nan); 1424 if (!isfinite(current)) { 1425 ExceptionCode ec; 1426 current = m_inputType->defaultValueForStepUp(); 1427 setValueAsNumber(current, ec); 1428 } 1429 if ((sign > 0 && current < m_inputType->minimum()) || (sign < 0 && current > m_inputType->maximum())) 1430 setValue(m_inputType->serialize(sign > 0 ? m_inputType->minimum() : m_inputType->maximum())); 1431 else { 1432 ExceptionCode ec; 1433 if (stepMismatch(currentStringValue)) { 1434 ASSERT(step); 1435 double newValue; 1436 double scale = pow(10.0, static_cast<double>(max(stepDecimalPlaces, baseDecimalPlaces))); 1437 1438 if (sign < 0) 1439 newValue = round((base + floor((current - base) / step) * step) * scale) / scale; 1440 else if (sign > 0) 1441 newValue = round((base + ceil((current - base) / step) * step) * scale) / scale; 1442 else 1443 newValue = current; 1444 1445 if (newValue < m_inputType->minimum()) 1446 newValue = m_inputType->minimum(); 1447 if (newValue > m_inputType->maximum()) 1448 newValue = m_inputType->maximum(); 1449 1450 setValueAsNumber(newValue, ec); 1451 current = newValue; 1452 if (n > 1) 1453 applyStep(n - 1, ec); 1454 else if (n < -1) 1455 applyStep(n + 1, ec); 1456 } else 1457 applyStep(n, ec); 1458 } 1459 1460 if (currentStringValue != value()) { 1461 if (m_inputType->isRangeControl()) 1462 dispatchFormControlChangeEvent(); 1463 else 1464 dispatchFormControlInputEvent(); 1465 } 1466 } 1467 1468 #if ENABLE(WCSS) 1469 1470 void HTMLInputElement::setWapInputFormat(String& mask) 1471 { 1472 String validateMask = validateInputMask(m_data, mask); 1473 if (!validateMask.isEmpty()) 1474 m_data.setInputFormatMask(validateMask); 1475 } 1476 1477 #endif 1478 1479 #if ENABLE(INPUT_SPEECH) 1480 1481 bool HTMLInputElement::isSpeechEnabled() const 1482 { 1483 // FIXME: Add support for RANGE, EMAIL, URL, COLOR and DATE/TIME input types. 1484 return m_inputType->shouldRespectSpeechAttribute() && RuntimeEnabledFeatures::speechInputEnabled() && hasAttribute(webkitspeechAttr); 1485 } 1486 1487 #endif 1488 1489 bool HTMLInputElement::isTextButton() const 1490 { 1491 return m_inputType->isTextButton(); 1492 } 1493 1494 bool HTMLInputElement::isRadioButton() const 1495 { 1496 return m_inputType->isRadioButton(); 1497 } 1498 1499 bool HTMLInputElement::isSearchField() const 1500 { 1501 return m_inputType->isSearchField(); 1502 } 1503 1504 bool HTMLInputElement::isInputTypeHidden() const 1505 { 1506 return m_inputType->isHiddenType(); 1507 } 1508 1509 bool HTMLInputElement::isPasswordField() const 1510 { 1511 return m_inputType->isPasswordField(); 1512 } 1513 1514 bool HTMLInputElement::isCheckbox() const 1515 { 1516 return m_inputType->isCheckbox(); 1517 } 1518 1519 bool HTMLInputElement::isText() const 1520 { 1521 return m_inputType->isTextType(); 1522 } 1523 1524 bool HTMLInputElement::isEmailField() const 1525 { 1526 return m_inputType->isEmailField(); 1527 } 1528 1529 bool HTMLInputElement::isFileUpload() const 1530 { 1531 return m_inputType->isFileUpload(); 1532 } 1533 1534 bool HTMLInputElement::isImageButton() const 1535 { 1536 return m_inputType->isImageButton(); 1537 } 1538 1539 bool HTMLInputElement::isNumberField() const 1540 { 1541 return m_inputType->isNumberField(); 1542 } 1543 1544 bool HTMLInputElement::isSubmitButton() const 1545 { 1546 return m_inputType->isSubmitButton(); 1547 } 1548 1549 bool HTMLInputElement::isTelephoneField() const 1550 { 1551 return m_inputType->isTelephoneField(); 1552 } 1553 1554 bool HTMLInputElement::isURLField() const 1555 { 1556 return m_inputType->isURLField(); 1557 } 1558 1559 bool HTMLInputElement::isEnumeratable() const 1560 { 1561 return m_inputType->isEnumeratable(); 1562 } 1563 1564 bool HTMLInputElement::isChecked() const 1565 { 1566 return checked() && m_inputType->isCheckable(); 1567 } 1568 1569 bool HTMLInputElement::hasSpinButton() const 1570 { 1571 return m_inputType->hasSpinButton(); 1572 } 1573 1574 bool HTMLInputElement::supportsPlaceholder() const 1575 { 1576 return isTextType(); 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 } // namespace 1592