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 * Copyright (C) 2008 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) 10 * Copyright (C) 2012 Samsung Electronics. All rights reserved. 11 * 12 * This library is free software; you can redistribute it and/or 13 * modify it under the terms of the GNU Library General Public 14 * License as published by the Free Software Foundation; either 15 * version 2 of the License, or (at your option) any later version. 16 * 17 * This library is distributed in the hope that it will be useful, 18 * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 20 * Library General Public License for more details. 21 * 22 * You should have received a copy of the GNU Library General Public License 23 * along with this library; see the file COPYING.LIB. If not, write to 24 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 25 * Boston, MA 02110-1301, USA. 26 * 27 */ 28 29 #include "config.h" 30 #include "core/html/HTMLInputElement.h" 31 32 #include "CSSPropertyNames.h" 33 #include "HTMLNames.h" 34 #include "RuntimeEnabledFeatures.h" 35 #include "bindings/v8/ExceptionState.h" 36 #include "bindings/v8/ScriptEventListener.h" 37 #include "core/accessibility/AXObjectCache.h" 38 #include "core/dom/BeforeTextInsertedEvent.h" 39 #include "core/dom/Document.h" 40 #include "core/dom/EventNames.h" 41 #include "core/dom/ExceptionCode.h" 42 #include "core/dom/IdTargetObserver.h" 43 #include "core/dom/KeyboardEvent.h" 44 #include "core/dom/MouseEvent.h" 45 #include "core/dom/ScopedEventQueue.h" 46 #include "core/dom/TouchEvent.h" 47 #include "core/dom/shadow/ElementShadow.h" 48 #include "core/dom/shadow/InsertionPoint.h" 49 #include "core/dom/shadow/ShadowRoot.h" 50 #include "core/editing/Editor.h" 51 #include "core/editing/FrameSelection.h" 52 #include "core/fileapi/FileList.h" 53 #include "core/html/ColorInputType.h" 54 #include "core/html/FileInputType.h" 55 #include "core/html/FormController.h" 56 #include "core/html/HTMLCollection.h" 57 #include "core/html/HTMLDataListElement.h" 58 #include "core/html/HTMLFormElement.h" 59 #include "core/html/HTMLImageLoader.h" 60 #include "core/html/HTMLOptionElement.h" 61 #include "core/html/InputType.h" 62 #include "core/html/SearchInputType.h" 63 #include "core/html/parser/HTMLParserIdioms.h" 64 #include "core/page/Frame.h" 65 #include "core/page/FrameView.h" 66 #include "core/page/UseCounter.h" 67 #include "core/platform/DateTimeChooser.h" 68 #include "core/platform/Language.h" 69 #include "core/platform/LocalizedStrings.h" 70 #include "core/platform/PlatformMouseEvent.h" 71 #include "core/rendering/RenderTextControlSingleLine.h" 72 #include "core/rendering/RenderTheme.h" 73 #include "wtf/MathExtras.h" 74 75 using namespace std; 76 77 namespace WebCore { 78 79 using namespace HTMLNames; 80 81 class ListAttributeTargetObserver : IdTargetObserver { 82 WTF_MAKE_FAST_ALLOCATED; 83 public: 84 static PassOwnPtr<ListAttributeTargetObserver> create(const AtomicString& id, HTMLInputElement*); 85 virtual void idTargetChanged() OVERRIDE; 86 87 private: 88 ListAttributeTargetObserver(const AtomicString& id, HTMLInputElement*); 89 90 HTMLInputElement* m_element; 91 }; 92 93 // FIXME: According to HTML4, the length attribute's value can be arbitrarily 94 // large. However, due to https://bugs.webkit.org/show_bug.cgi?id=14536 things 95 // get rather sluggish when a text field has a larger number of characters than 96 // this, even when just clicking in the text field. 97 const unsigned HTMLInputElement::maximumLength = 524288; 98 const int defaultSize = 20; 99 const int maxSavedResults = 256; 100 101 HTMLInputElement::HTMLInputElement(const QualifiedName& tagName, Document* document, HTMLFormElement* form, bool createdByParser) 102 : HTMLTextFormControlElement(tagName, document, form) 103 , m_size(defaultSize) 104 , m_maxLength(maximumLength) 105 , m_maxResults(-1) 106 , m_isChecked(false) 107 , m_reflectsCheckedAttribute(true) 108 , m_isIndeterminate(false) 109 , m_hasType(false) 110 , m_isActivatedSubmit(false) 111 , m_autocomplete(Uninitialized) 112 , m_isAutofilled(false) 113 , m_hasNonEmptyList(false) 114 , m_stateRestored(false) 115 , m_parsingInProgress(createdByParser) 116 , m_valueAttributeWasUpdatedAfterParsing(false) 117 , m_wasModifiedByUser(false) 118 , m_canReceiveDroppedFiles(false) 119 , m_hasTouchEventHandler(false) 120 , m_inputType(InputType::createText(this)) 121 { 122 ASSERT(hasTagName(inputTag) || hasTagName(isindexTag)); 123 #if ENABLE(INPUT_MULTIPLE_FIELDS_UI) 124 setHasCustomStyleCallbacks(); 125 #endif 126 ScriptWrappable::init(this); 127 } 128 129 PassRefPtr<HTMLInputElement> HTMLInputElement::create(const QualifiedName& tagName, Document* document, HTMLFormElement* form, bool createdByParser) 130 { 131 RefPtr<HTMLInputElement> inputElement = adoptRef(new HTMLInputElement(tagName, document, form, createdByParser)); 132 inputElement->ensureUserAgentShadowRoot(); 133 return inputElement.release(); 134 } 135 136 HTMLImageLoader* HTMLInputElement::imageLoader() 137 { 138 if (!m_imageLoader) 139 m_imageLoader = adoptPtr(new HTMLImageLoader(this)); 140 return m_imageLoader.get(); 141 } 142 143 void HTMLInputElement::didAddUserAgentShadowRoot(ShadowRoot*) 144 { 145 m_inputType->createShadowSubtree(); 146 } 147 148 HTMLInputElement::~HTMLInputElement() 149 { 150 // Need to remove form association while this is still an HTMLInputElement 151 // so that virtual functions are called correctly. 152 setForm(0); 153 // setForm(0) may register this to a document-level radio button group. 154 // We should unregister it to avoid accessing a deleted object. 155 if (isRadioButton()) 156 document()->formController()->checkedRadioButtons().removeButton(this); 157 if (m_hasTouchEventHandler) 158 document()->didRemoveEventTargetNode(this); 159 } 160 161 const AtomicString& HTMLInputElement::name() const 162 { 163 return m_name.isNull() ? emptyAtom : m_name; 164 } 165 166 Vector<FileChooserFileInfo> HTMLInputElement::filesFromFileInputFormControlState(const FormControlState& state) 167 { 168 return FileInputType::filesFromFormControlState(state); 169 } 170 171 HTMLElement* HTMLInputElement::containerElement() const 172 { 173 return m_inputType->containerElement(); 174 } 175 176 HTMLElement* HTMLInputElement::innerTextElement() const 177 { 178 return m_inputType->innerTextElement(); 179 } 180 181 HTMLElement* HTMLInputElement::innerBlockElement() const 182 { 183 return m_inputType->innerBlockElement(); 184 } 185 186 HTMLElement* HTMLInputElement::innerSpinButtonElement() const 187 { 188 return m_inputType->innerSpinButtonElement(); 189 } 190 191 #if ENABLE(INPUT_SPEECH) 192 HTMLElement* HTMLInputElement::speechButtonElement() const 193 { 194 return m_inputType->speechButtonElement(); 195 } 196 #endif 197 198 HTMLElement* HTMLInputElement::passwordGeneratorButtonElement() const 199 { 200 return m_inputType->passwordGeneratorButtonElement(); 201 } 202 203 HTMLElement* HTMLInputElement::sliderThumbElement() const 204 { 205 return m_inputType->sliderThumbElement(); 206 } 207 208 HTMLElement* HTMLInputElement::sliderTrackElement() const 209 { 210 return m_inputType->sliderTrackElement(); 211 } 212 213 HTMLElement* HTMLInputElement::placeholderElement() const 214 { 215 return m_inputType->placeholderElement(); 216 } 217 218 bool HTMLInputElement::shouldAutocomplete() const 219 { 220 if (m_autocomplete != Uninitialized) 221 return m_autocomplete == On; 222 return HTMLTextFormControlElement::shouldAutocomplete(); 223 } 224 225 bool HTMLInputElement::isValidValue(const String& value) const 226 { 227 if (!m_inputType->canSetStringValue()) { 228 ASSERT_NOT_REACHED(); 229 return false; 230 } 231 return !m_inputType->typeMismatchFor(value) 232 && !m_inputType->stepMismatch(value) 233 && !m_inputType->rangeUnderflow(value) 234 && !m_inputType->rangeOverflow(value) 235 && !tooLong(value, IgnoreDirtyFlag) 236 && !m_inputType->patternMismatch(value) 237 && !m_inputType->valueMissing(value); 238 } 239 240 bool HTMLInputElement::tooLong() const 241 { 242 return willValidate() && tooLong(value(), CheckDirtyFlag); 243 } 244 245 bool HTMLInputElement::typeMismatch() const 246 { 247 return willValidate() && m_inputType->typeMismatch(); 248 } 249 250 bool HTMLInputElement::valueMissing() const 251 { 252 return willValidate() && m_inputType->valueMissing(value()); 253 } 254 255 bool HTMLInputElement::hasBadInput() const 256 { 257 return willValidate() && m_inputType->hasBadInput(); 258 } 259 260 bool HTMLInputElement::patternMismatch() const 261 { 262 return willValidate() && m_inputType->patternMismatch(value()); 263 } 264 265 bool HTMLInputElement::tooLong(const String& value, NeedsToCheckDirtyFlag check) const 266 { 267 // We use isTextType() instead of supportsMaxLength() because of the 268 // 'virtual' overhead. 269 if (!isTextType()) 270 return false; 271 int max = maxLength(); 272 if (max < 0) 273 return false; 274 if (check == CheckDirtyFlag) { 275 // Return false for the default value or a value set by a script even if 276 // it is longer than maxLength. 277 if (!hasDirtyValue() || !m_wasModifiedByUser) 278 return false; 279 } 280 return numGraphemeClusters(value) > static_cast<unsigned>(max); 281 } 282 283 bool HTMLInputElement::rangeUnderflow() const 284 { 285 return willValidate() && m_inputType->rangeUnderflow(value()); 286 } 287 288 bool HTMLInputElement::rangeOverflow() const 289 { 290 return willValidate() && m_inputType->rangeOverflow(value()); 291 } 292 293 String HTMLInputElement::validationMessage() const 294 { 295 if (!willValidate()) 296 return String(); 297 298 if (customError()) 299 return customValidationMessage(); 300 301 return m_inputType->validationMessage(); 302 } 303 304 double HTMLInputElement::minimum() const 305 { 306 return m_inputType->minimum(); 307 } 308 309 double HTMLInputElement::maximum() const 310 { 311 return m_inputType->maximum(); 312 } 313 314 bool HTMLInputElement::stepMismatch() const 315 { 316 return willValidate() && m_inputType->stepMismatch(value()); 317 } 318 319 bool HTMLInputElement::getAllowedValueStep(Decimal* step) const 320 { 321 return m_inputType->getAllowedValueStep(step); 322 } 323 324 StepRange HTMLInputElement::createStepRange(AnyStepHandling anyStepHandling) const 325 { 326 return m_inputType->createStepRange(anyStepHandling); 327 } 328 329 Decimal HTMLInputElement::findClosestTickMarkValue(const Decimal& value) 330 { 331 return m_inputType->findClosestTickMarkValue(value); 332 } 333 334 void HTMLInputElement::stepUp(int n, ExceptionState& es) 335 { 336 m_inputType->stepUp(n, es); 337 } 338 339 void HTMLInputElement::stepDown(int n, ExceptionState& es) 340 { 341 m_inputType->stepUp(-n, es); 342 } 343 344 void HTMLInputElement::blur() 345 { 346 m_inputType->blur(); 347 } 348 349 void HTMLInputElement::defaultBlur() 350 { 351 HTMLTextFormControlElement::blur(); 352 } 353 354 bool HTMLInputElement::hasCustomFocusLogic() const 355 { 356 return m_inputType->hasCustomFocusLogic(); 357 } 358 359 bool HTMLInputElement::isKeyboardFocusable() const 360 { 361 return m_inputType->isKeyboardFocusable(); 362 } 363 364 bool HTMLInputElement::shouldShowFocusRingOnMouseFocus() const 365 { 366 return m_inputType->shouldShowFocusRingOnMouseFocus(); 367 } 368 369 void HTMLInputElement::updateFocusAppearance(bool restorePreviousSelection) 370 { 371 if (isTextField()) { 372 if (!restorePreviousSelection || !hasCachedSelection()) 373 select(); 374 else 375 restoreCachedSelection(); 376 if (document()->frame()) 377 document()->frame()->selection()->revealSelection(); 378 } else 379 HTMLTextFormControlElement::updateFocusAppearance(restorePreviousSelection); 380 } 381 382 void HTMLInputElement::beginEditing() 383 { 384 if (!isTextField()) 385 return; 386 387 if (Frame* frame = document()->frame()) 388 frame->editor()->textFieldDidBeginEditing(this); 389 } 390 391 void HTMLInputElement::endEditing() 392 { 393 if (!isTextField()) 394 return; 395 396 if (Frame* frame = document()->frame()) 397 frame->editor()->textFieldDidEndEditing(this); 398 } 399 400 bool HTMLInputElement::shouldUseInputMethod() 401 { 402 return m_inputType->shouldUseInputMethod(); 403 } 404 405 void HTMLInputElement::handleFocusEvent(Element* oldFocusedElement, FocusDirection direction) 406 { 407 m_inputType->handleFocusEvent(oldFocusedElement, direction); 408 } 409 410 void HTMLInputElement::handleBlurEvent() 411 { 412 m_inputType->handleBlurEvent(); 413 } 414 415 void HTMLInputElement::setType(const String& type) 416 { 417 // FIXME: This should just call setAttribute. No reason to handle the empty string specially. 418 // We should write a test case to show that setting to the empty string does not remove the 419 // attribute in other browsers and then fix this. Note that setting to null *does* remove 420 // the attribute and setAttribute implements that. 421 if (type.isEmpty()) 422 removeAttribute(typeAttr); 423 else 424 setAttribute(typeAttr, type); 425 } 426 427 void HTMLInputElement::updateType() 428 { 429 OwnPtr<InputType> newType = InputType::create(this, fastGetAttribute(typeAttr)); 430 bool hadType = m_hasType; 431 m_hasType = true; 432 if (m_inputType->formControlType() == newType->formControlType()) 433 return; 434 435 if (hadType && !newType->canChangeFromAnotherType()) { 436 // Set the attribute back to the old value. 437 // Useful in case we were called from inside parseAttribute. 438 setAttribute(typeAttr, type()); 439 return; 440 } 441 442 removeFromRadioButtonGroup(); 443 444 bool didStoreValue = m_inputType->storesValueSeparateFromAttribute(); 445 bool didRespectHeightAndWidth = m_inputType->shouldRespectHeightAndWidthAttributes(); 446 447 m_inputType->destroyShadowSubtree(); 448 449 bool wasAttached = attached(); 450 if (wasAttached) 451 detach(); 452 453 m_inputType = newType.release(); 454 m_inputType->createShadowSubtree(); 455 456 bool hasTouchEventHandler = m_inputType->hasTouchEventHandler(); 457 if (hasTouchEventHandler != m_hasTouchEventHandler) { 458 if (hasTouchEventHandler) 459 document()->didAddTouchEventHandler(this); 460 else 461 document()->didRemoveTouchEventHandler(this); 462 m_hasTouchEventHandler = hasTouchEventHandler; 463 } 464 465 setNeedsWillValidateCheck(); 466 467 bool willStoreValue = m_inputType->storesValueSeparateFromAttribute(); 468 469 if (didStoreValue && !willStoreValue && hasDirtyValue()) { 470 setAttribute(valueAttr, m_valueIfDirty); 471 m_valueIfDirty = String(); 472 } 473 if (!didStoreValue && willStoreValue) { 474 AtomicString valueString = fastGetAttribute(valueAttr); 475 m_valueIfDirty = sanitizeValue(valueString); 476 } else 477 updateValueIfNeeded(); 478 479 setFormControlValueMatchesRenderer(false); 480 m_inputType->updateInnerTextValue(); 481 482 m_wasModifiedByUser = false; 483 484 if (didRespectHeightAndWidth != m_inputType->shouldRespectHeightAndWidthAttributes()) { 485 ASSERT(elementData()); 486 if (const Attribute* height = getAttributeItem(heightAttr)) 487 attributeChanged(heightAttr, height->value()); 488 if (const Attribute* width = getAttributeItem(widthAttr)) 489 attributeChanged(widthAttr, width->value()); 490 if (const Attribute* align = getAttributeItem(alignAttr)) 491 attributeChanged(alignAttr, align->value()); 492 } 493 494 if (wasAttached) { 495 lazyAttach(); 496 if (document()->focusedElement() == this) 497 document()->updateFocusAppearanceSoon(true /* restore selection */); 498 } 499 500 setChangedSinceLastFormControlChangeEvent(false); 501 502 addToRadioButtonGroup(); 503 504 setNeedsValidityCheck(); 505 notifyFormStateChanged(); 506 } 507 508 void HTMLInputElement::subtreeHasChanged() 509 { 510 m_inputType->subtreeHasChanged(); 511 // When typing in an input field, childrenChanged is not called, so we need to force the directionality check. 512 calculateAndAdjustDirectionality(); 513 } 514 515 const AtomicString& HTMLInputElement::formControlType() const 516 { 517 return m_inputType->formControlType(); 518 } 519 520 bool HTMLInputElement::shouldSaveAndRestoreFormControlState() const 521 { 522 if (!m_inputType->shouldSaveAndRestoreFormControlState()) 523 return false; 524 return HTMLTextFormControlElement::shouldSaveAndRestoreFormControlState(); 525 } 526 527 FormControlState HTMLInputElement::saveFormControlState() const 528 { 529 return m_inputType->saveFormControlState(); 530 } 531 532 void HTMLInputElement::restoreFormControlState(const FormControlState& state) 533 { 534 m_inputType->restoreFormControlState(state); 535 m_stateRestored = true; 536 } 537 538 bool HTMLInputElement::canStartSelection() const 539 { 540 if (!isTextField()) 541 return false; 542 return HTMLTextFormControlElement::canStartSelection(); 543 } 544 545 bool HTMLInputElement::canHaveSelection() const 546 { 547 return isTextField(); 548 } 549 550 int HTMLInputElement::selectionStartForBinding(ExceptionState& es) const 551 { 552 if (!canHaveSelection()) { 553 es.throwDOMException(InvalidStateError); 554 return 0; 555 } 556 return HTMLTextFormControlElement::selectionStart(); 557 } 558 559 int HTMLInputElement::selectionEndForBinding(ExceptionState& es) const 560 { 561 if (!canHaveSelection()) { 562 es.throwDOMException(InvalidStateError); 563 return 0; 564 } 565 return HTMLTextFormControlElement::selectionEnd(); 566 } 567 568 String HTMLInputElement::selectionDirectionForBinding(ExceptionState& es) const 569 { 570 if (!canHaveSelection()) { 571 es.throwDOMException(InvalidStateError); 572 return String(); 573 } 574 return HTMLTextFormControlElement::selectionDirection(); 575 } 576 577 void HTMLInputElement::setSelectionStartForBinding(int start, ExceptionState& es) 578 { 579 if (!canHaveSelection()) { 580 es.throwDOMException(InvalidStateError); 581 return; 582 } 583 HTMLTextFormControlElement::setSelectionStart(start); 584 } 585 586 void HTMLInputElement::setSelectionEndForBinding(int end, ExceptionState& es) 587 { 588 if (!canHaveSelection()) { 589 es.throwDOMException(InvalidStateError); 590 return; 591 } 592 HTMLTextFormControlElement::setSelectionEnd(end); 593 } 594 595 void HTMLInputElement::setSelectionDirectionForBinding(const String& direction, ExceptionState& es) 596 { 597 if (!canHaveSelection()) { 598 es.throwDOMException(InvalidStateError); 599 return; 600 } 601 HTMLTextFormControlElement::setSelectionDirection(direction); 602 } 603 604 void HTMLInputElement::setSelectionRangeForBinding(int start, int end, ExceptionState& es) 605 { 606 if (!canHaveSelection()) { 607 es.throwDOMException(InvalidStateError); 608 return; 609 } 610 HTMLTextFormControlElement::setSelectionRange(start, end); 611 } 612 613 void HTMLInputElement::setSelectionRangeForBinding(int start, int end, const String& direction, ExceptionState& es) 614 { 615 if (!canHaveSelection()) { 616 es.throwDOMException(InvalidStateError); 617 return; 618 } 619 HTMLTextFormControlElement::setSelectionRange(start, end, direction); 620 } 621 622 void HTMLInputElement::accessKeyAction(bool sendMouseEvents) 623 { 624 m_inputType->accessKeyAction(sendMouseEvents); 625 } 626 627 bool HTMLInputElement::isPresentationAttribute(const QualifiedName& name) const 628 { 629 if (name == vspaceAttr || name == hspaceAttr || name == alignAttr || name == widthAttr || name == heightAttr || (name == borderAttr && isImageButton())) 630 return true; 631 return HTMLTextFormControlElement::isPresentationAttribute(name); 632 } 633 634 void HTMLInputElement::collectStyleForPresentationAttribute(const QualifiedName& name, const AtomicString& value, MutableStylePropertySet* style) 635 { 636 if (name == vspaceAttr) { 637 addHTMLLengthToStyle(style, CSSPropertyMarginTop, value); 638 addHTMLLengthToStyle(style, CSSPropertyMarginBottom, value); 639 } else if (name == hspaceAttr) { 640 addHTMLLengthToStyle(style, CSSPropertyMarginLeft, value); 641 addHTMLLengthToStyle(style, CSSPropertyMarginRight, value); 642 } else if (name == alignAttr) { 643 if (m_inputType->shouldRespectAlignAttribute()) 644 applyAlignmentAttributeToStyle(value, style); 645 } else if (name == widthAttr) { 646 if (m_inputType->shouldRespectHeightAndWidthAttributes()) 647 addHTMLLengthToStyle(style, CSSPropertyWidth, value); 648 } else if (name == heightAttr) { 649 if (m_inputType->shouldRespectHeightAndWidthAttributes()) 650 addHTMLLengthToStyle(style, CSSPropertyHeight, value); 651 } else if (name == borderAttr && isImageButton()) 652 applyBorderAttributeToStyle(value, style); 653 else 654 HTMLTextFormControlElement::collectStyleForPresentationAttribute(name, value, style); 655 } 656 657 void HTMLInputElement::parseAttribute(const QualifiedName& name, const AtomicString& value) 658 { 659 if (name == nameAttr) { 660 removeFromRadioButtonGroup(); 661 m_name = value; 662 addToRadioButtonGroup(); 663 HTMLTextFormControlElement::parseAttribute(name, value); 664 } else if (name == autocompleteAttr) { 665 if (equalIgnoringCase(value, "off")) 666 m_autocomplete = Off; 667 else { 668 if (value.isEmpty()) 669 m_autocomplete = Uninitialized; 670 else 671 m_autocomplete = On; 672 } 673 } else if (name == typeAttr) 674 updateType(); 675 else if (name == valueAttr) { 676 // We only need to setChanged if the form is looking at the default value right now. 677 if (!hasDirtyValue()) { 678 updatePlaceholderVisibility(false); 679 setNeedsStyleRecalc(); 680 } 681 setFormControlValueMatchesRenderer(false); 682 setNeedsValidityCheck(); 683 m_valueAttributeWasUpdatedAfterParsing = !m_parsingInProgress; 684 m_inputType->valueAttributeChanged(); 685 } else if (name == checkedAttr) { 686 // Another radio button in the same group might be checked by state 687 // restore. We shouldn't call setChecked() even if this has the checked 688 // attribute. So, delay the setChecked() call until 689 // finishParsingChildren() is called if parsing is in progress. 690 if (!m_parsingInProgress && m_reflectsCheckedAttribute) { 691 setChecked(!value.isNull()); 692 m_reflectsCheckedAttribute = true; 693 } 694 } else if (name == maxlengthAttr) 695 parseMaxLengthAttribute(value); 696 else if (name == sizeAttr) { 697 int oldSize = m_size; 698 int valueAsInteger = value.toInt(); 699 m_size = valueAsInteger > 0 ? valueAsInteger : defaultSize; 700 if (m_size != oldSize && renderer()) 701 renderer()->setNeedsLayoutAndPrefWidthsRecalc(); 702 } else if (name == altAttr) 703 m_inputType->altAttributeChanged(); 704 else if (name == srcAttr) 705 m_inputType->srcAttributeChanged(); 706 else if (name == usemapAttr || name == accesskeyAttr) { 707 // FIXME: ignore for the moment 708 } else if (name == onsearchAttr) { 709 // Search field and slider attributes all just cause updateFromElement to be called through style recalcing. 710 setAttributeEventListener(eventNames().searchEvent, createAttributeEventListener(this, name, value)); 711 } else if (name == resultsAttr) { 712 int oldResults = m_maxResults; 713 m_maxResults = !value.isNull() ? std::min(value.toInt(), maxSavedResults) : -1; 714 // FIXME: Detaching just for maxResults change is not ideal. We should figure out the right 715 // time to relayout for this change. 716 if (m_maxResults != oldResults && (m_maxResults <= 0 || oldResults <= 0)) 717 lazyReattachIfAttached(); 718 setNeedsStyleRecalc(); 719 UseCounter::count(document(), UseCounter::ResultsAttribute); 720 } else if (name == incrementalAttr) { 721 setNeedsStyleRecalc(); 722 UseCounter::count(document(), UseCounter::IncrementalAttribute); 723 } else if (name == minAttr) { 724 m_inputType->minOrMaxAttributeChanged(); 725 setNeedsValidityCheck(); 726 UseCounter::count(document(), UseCounter::MinAttribute); 727 } else if (name == maxAttr) { 728 m_inputType->minOrMaxAttributeChanged(); 729 setNeedsValidityCheck(); 730 UseCounter::count(document(), UseCounter::MaxAttribute); 731 } else if (name == multipleAttr) { 732 m_inputType->multipleAttributeChanged(); 733 setNeedsValidityCheck(); 734 } else if (name == stepAttr) { 735 m_inputType->stepAttributeChanged(); 736 setNeedsValidityCheck(); 737 UseCounter::count(document(), UseCounter::StepAttribute); 738 } else if (name == patternAttr) { 739 setNeedsValidityCheck(); 740 UseCounter::count(document(), UseCounter::PatternAttribute); 741 } else if (name == precisionAttr) { 742 setNeedsValidityCheck(); 743 UseCounter::count(document(), UseCounter::PrecisionAttribute); 744 } else if (name == disabledAttr) { 745 HTMLTextFormControlElement::parseAttribute(name, value); 746 m_inputType->disabledAttributeChanged(); 747 } else if (name == readonlyAttr) { 748 HTMLTextFormControlElement::parseAttribute(name, value); 749 m_inputType->readonlyAttributeChanged(); 750 } else if (name == listAttr) { 751 m_hasNonEmptyList = !value.isEmpty(); 752 if (m_hasNonEmptyList) { 753 resetListAttributeTargetObserver(); 754 listAttributeTargetChanged(); 755 } 756 UseCounter::count(document(), UseCounter::ListAttribute); 757 } 758 #if ENABLE(INPUT_SPEECH) 759 else if (name == webkitspeechAttr) { 760 if (RuntimeEnabledFeatures::speechInputEnabled() && m_inputType->shouldRespectSpeechAttribute()) { 761 // This renderer and its children have quite different layouts and 762 // styles depending on whether the speech button is visible or 763 // not. So we reset the whole thing and recreate to get the right 764 // styles and layout. 765 m_inputType->destroyShadowSubtree(); 766 lazyReattachIfAttached(); 767 m_inputType->createShadowSubtree(); 768 setFormControlValueMatchesRenderer(false); 769 } 770 UseCounter::count(document(), UseCounter::PrefixedSpeechAttribute); 771 } else if (name == onwebkitspeechchangeAttr) 772 setAttributeEventListener(eventNames().webkitspeechchangeEvent, createAttributeEventListener(this, name, value)); 773 #endif 774 else if (name == webkitdirectoryAttr) { 775 HTMLTextFormControlElement::parseAttribute(name, value); 776 UseCounter::count(document(), UseCounter::PrefixedDirectoryAttribute); 777 } 778 else 779 HTMLTextFormControlElement::parseAttribute(name, value); 780 m_inputType->attributeChanged(); 781 } 782 783 void HTMLInputElement::finishParsingChildren() 784 { 785 m_parsingInProgress = false; 786 HTMLTextFormControlElement::finishParsingChildren(); 787 if (!m_stateRestored) { 788 bool checked = hasAttribute(checkedAttr); 789 if (checked) 790 setChecked(checked); 791 m_reflectsCheckedAttribute = true; 792 } 793 } 794 795 bool HTMLInputElement::rendererIsNeeded(const NodeRenderingContext& context) 796 { 797 return m_inputType->rendererIsNeeded() && HTMLTextFormControlElement::rendererIsNeeded(context); 798 } 799 800 RenderObject* HTMLInputElement::createRenderer(RenderStyle* style) 801 { 802 return m_inputType->createRenderer(style); 803 } 804 805 void HTMLInputElement::attach(const AttachContext& context) 806 { 807 PostAttachCallbackDisabler disabler(this); 808 809 if (!m_hasType) 810 updateType(); 811 812 HTMLTextFormControlElement::attach(context); 813 814 m_inputType->attach(); 815 816 if (document()->focusedElement() == this) 817 document()->updateFocusAppearanceSoon(true /* restore selection */); 818 } 819 820 void HTMLInputElement::detach(const AttachContext& context) 821 { 822 HTMLTextFormControlElement::detach(context); 823 setFormControlValueMatchesRenderer(false); 824 m_inputType->detach(); 825 } 826 827 String HTMLInputElement::altText() const 828 { 829 // http://www.w3.org/TR/1998/REC-html40-19980424/appendix/notes.html#altgen 830 // also heavily discussed by Hixie on bugzilla 831 // note this is intentionally different to HTMLImageElement::altText() 832 String alt = fastGetAttribute(altAttr); 833 // fall back to title attribute 834 if (alt.isNull()) 835 alt = getAttribute(titleAttr); 836 if (alt.isNull()) 837 alt = getAttribute(valueAttr); 838 if (alt.isEmpty()) 839 alt = inputElementAltText(); 840 return alt; 841 } 842 843 bool HTMLInputElement::isSuccessfulSubmitButton() const 844 { 845 // HTML spec says that buttons must have names to be considered successful. 846 // However, other browsers do not impose this constraint. So we do not. 847 return !isDisabledFormControl() && m_inputType->canBeSuccessfulSubmitButton(); 848 } 849 850 bool HTMLInputElement::isActivatedSubmit() const 851 { 852 return m_isActivatedSubmit; 853 } 854 855 void HTMLInputElement::setActivatedSubmit(bool flag) 856 { 857 m_isActivatedSubmit = flag; 858 } 859 860 bool HTMLInputElement::appendFormData(FormDataList& encoding, bool multipart) 861 { 862 return m_inputType->isFormDataAppendable() && m_inputType->appendFormData(encoding, multipart); 863 } 864 865 void HTMLInputElement::reset() 866 { 867 if (m_inputType->storesValueSeparateFromAttribute()) 868 setValue(String()); 869 870 setAutofilled(false); 871 setChecked(hasAttribute(checkedAttr)); 872 m_reflectsCheckedAttribute = true; 873 } 874 875 bool HTMLInputElement::isTextField() const 876 { 877 return m_inputType->isTextField(); 878 } 879 880 bool HTMLInputElement::isTextType() const 881 { 882 return m_inputType->isTextType(); 883 } 884 885 void HTMLInputElement::setChecked(bool nowChecked, TextFieldEventBehavior eventBehavior) 886 { 887 if (checked() == nowChecked) 888 return; 889 890 m_reflectsCheckedAttribute = false; 891 m_isChecked = nowChecked; 892 setNeedsStyleRecalc(); 893 894 if (CheckedRadioButtons* buttons = checkedRadioButtons()) 895 buttons->updateCheckedState(this); 896 if (renderer() && renderer()->style()->hasAppearance()) 897 renderer()->theme()->stateChanged(renderer(), CheckedState); 898 setNeedsValidityCheck(); 899 900 // Ideally we'd do this from the render tree (matching 901 // RenderTextView), but it's not possible to do it at the moment 902 // because of the way the code is structured. 903 if (renderer()) { 904 if (AXObjectCache* cache = renderer()->document()->existingAXObjectCache()) 905 cache->checkedStateChanged(this); 906 } 907 908 // Only send a change event for items in the document (avoid firing during 909 // parsing) and don't send a change event for a radio button that's getting 910 // unchecked to match other browsers. DOM is not a useful standard for this 911 // because it says only to fire change events at "lose focus" time, which is 912 // definitely wrong in practice for these types of elements. 913 if (eventBehavior != DispatchNoEvent && inDocument() && m_inputType->shouldSendChangeEventAfterCheckedChanged()) { 914 setTextAsOfLastFormControlChangeEvent(String()); 915 dispatchFormControlChangeEvent(); 916 } 917 918 didAffectSelector(AffectedSelectorChecked); 919 } 920 921 void HTMLInputElement::setIndeterminate(bool newValue) 922 { 923 if (indeterminate() == newValue) 924 return; 925 926 m_isIndeterminate = newValue; 927 928 didAffectSelector(AffectedSelectorIndeterminate); 929 930 if (renderer() && renderer()->style()->hasAppearance()) 931 renderer()->theme()->stateChanged(renderer(), CheckedState); 932 } 933 934 int HTMLInputElement::size() const 935 { 936 return m_size; 937 } 938 939 bool HTMLInputElement::sizeShouldIncludeDecoration(int& preferredSize) const 940 { 941 return m_inputType->sizeShouldIncludeDecoration(defaultSize, preferredSize); 942 } 943 944 void HTMLInputElement::copyNonAttributePropertiesFromElement(const Element& source) 945 { 946 const HTMLInputElement& sourceElement = static_cast<const HTMLInputElement&>(source); 947 948 m_valueIfDirty = sourceElement.m_valueIfDirty; 949 m_wasModifiedByUser = false; 950 setChecked(sourceElement.m_isChecked); 951 m_reflectsCheckedAttribute = sourceElement.m_reflectsCheckedAttribute; 952 m_isIndeterminate = sourceElement.m_isIndeterminate; 953 954 HTMLTextFormControlElement::copyNonAttributePropertiesFromElement(source); 955 956 setFormControlValueMatchesRenderer(false); 957 m_inputType->updateInnerTextValue(); 958 } 959 960 String HTMLInputElement::value() const 961 { 962 String value; 963 if (m_inputType->getTypeSpecificValue(value)) 964 return value; 965 966 value = m_valueIfDirty; 967 if (!value.isNull()) 968 return value; 969 970 AtomicString valueString = fastGetAttribute(valueAttr); 971 value = sanitizeValue(valueString); 972 if (!value.isNull()) 973 return value; 974 975 return m_inputType->fallbackValue(); 976 } 977 978 String HTMLInputElement::valueWithDefault() const 979 { 980 String value = this->value(); 981 if (!value.isNull()) 982 return value; 983 984 return m_inputType->defaultValue(); 985 } 986 987 void HTMLInputElement::setValueForUser(const String& value) 988 { 989 // Call setValue and make it send a change event. 990 setValue(value, DispatchChangeEvent); 991 } 992 993 const String& HTMLInputElement::suggestedValue() const 994 { 995 return m_suggestedValue; 996 } 997 998 void HTMLInputElement::setSuggestedValue(const String& value) 999 { 1000 if (!m_inputType->canSetSuggestedValue()) 1001 return; 1002 setFormControlValueMatchesRenderer(false); 1003 m_suggestedValue = sanitizeValue(value); 1004 setNeedsStyleRecalc(); 1005 m_inputType->updateInnerTextValue(); 1006 } 1007 1008 void HTMLInputElement::setEditingValue(const String& value) 1009 { 1010 if (!renderer() || !isTextField()) 1011 return; 1012 setInnerTextValue(value); 1013 subtreeHasChanged(); 1014 1015 unsigned max = value.length(); 1016 if (focused()) 1017 setSelectionRange(max, max); 1018 else 1019 cacheSelectionInResponseToSetValue(max); 1020 1021 dispatchInputEvent(); 1022 } 1023 1024 void HTMLInputElement::setValue(const String& value, ExceptionState& es, TextFieldEventBehavior eventBehavior) 1025 { 1026 if (isFileUpload() && !value.isEmpty()) { 1027 es.throwDOMException(InvalidStateError); 1028 return; 1029 } 1030 setValue(value, eventBehavior); 1031 } 1032 1033 void HTMLInputElement::setValue(const String& value, TextFieldEventBehavior eventBehavior) 1034 { 1035 if (!m_inputType->canSetValue(value)) 1036 return; 1037 1038 RefPtr<HTMLInputElement> protector(this); 1039 EventQueueScope scope; 1040 String sanitizedValue = sanitizeValue(value); 1041 bool valueChanged = sanitizedValue != this->value(); 1042 1043 setLastChangeWasNotUserEdit(); 1044 setFormControlValueMatchesRenderer(false); 1045 m_suggestedValue = String(); // Prevent TextFieldInputType::setValue from using the suggested value. 1046 m_inputType->setValue(sanitizedValue, valueChanged, eventBehavior); 1047 1048 if (!valueChanged) 1049 return; 1050 1051 notifyFormStateChanged(); 1052 } 1053 1054 void HTMLInputElement::setValueInternal(const String& sanitizedValue, TextFieldEventBehavior eventBehavior) 1055 { 1056 m_valueIfDirty = sanitizedValue; 1057 m_wasModifiedByUser = eventBehavior != DispatchNoEvent; 1058 setNeedsValidityCheck(); 1059 } 1060 1061 double HTMLInputElement::valueAsDate() const 1062 { 1063 return m_inputType->valueAsDate(); 1064 } 1065 1066 void HTMLInputElement::setValueAsDate(double value, ExceptionState& es) 1067 { 1068 m_inputType->setValueAsDate(value, es); 1069 } 1070 1071 double HTMLInputElement::valueAsNumber() const 1072 { 1073 return m_inputType->valueAsDouble(); 1074 } 1075 1076 void HTMLInputElement::setValueAsNumber(double newValue, ExceptionState& es, TextFieldEventBehavior eventBehavior) 1077 { 1078 if (!std::isfinite(newValue)) { 1079 es.throwDOMException(NotSupportedError); 1080 return; 1081 } 1082 m_inputType->setValueAsDouble(newValue, eventBehavior, es); 1083 } 1084 1085 void HTMLInputElement::setValueFromRenderer(const String& value) 1086 { 1087 // File upload controls will never use this. 1088 ASSERT(!isFileUpload()); 1089 1090 m_suggestedValue = String(); 1091 1092 // Renderer and our event handler are responsible for sanitizing values. 1093 ASSERT(value == sanitizeValue(value) || sanitizeValue(value).isEmpty()); 1094 1095 m_valueIfDirty = value; 1096 1097 setFormControlValueMatchesRenderer(true); 1098 m_wasModifiedByUser = true; 1099 1100 // Input event is fired by the Node::defaultEventHandler for editable controls. 1101 if (!isTextField()) 1102 dispatchInputEvent(); 1103 notifyFormStateChanged(); 1104 1105 setNeedsValidityCheck(); 1106 1107 // Clear autofill flag (and yellow background) on user edit. 1108 setAutofilled(false); 1109 } 1110 1111 void* HTMLInputElement::preDispatchEventHandler(Event* event) 1112 { 1113 if (event->type() == eventNames().textInputEvent && m_inputType->shouldSubmitImplicitly(event)) { 1114 event->stopPropagation(); 1115 return 0; 1116 } 1117 if (event->type() != eventNames().clickEvent) 1118 return 0; 1119 if (!event->isMouseEvent() || toMouseEvent(event)->button() != LeftButton) 1120 return 0; 1121 // FIXME: Check whether there are any cases where this actually ends up leaking. 1122 return m_inputType->willDispatchClick().leakPtr(); 1123 } 1124 1125 void HTMLInputElement::postDispatchEventHandler(Event* event, void* dataFromPreDispatch) 1126 { 1127 OwnPtr<ClickHandlingState> state = adoptPtr(static_cast<ClickHandlingState*>(dataFromPreDispatch)); 1128 if (!state) 1129 return; 1130 m_inputType->didDispatchClick(event, *state); 1131 } 1132 1133 void HTMLInputElement::defaultEventHandler(Event* evt) 1134 { 1135 if (evt->isMouseEvent() && evt->type() == eventNames().clickEvent && toMouseEvent(evt)->button() == LeftButton) { 1136 m_inputType->handleClickEvent(toMouseEvent(evt)); 1137 if (evt->defaultHandled()) 1138 return; 1139 } 1140 1141 if (evt->isTouchEvent()) { 1142 m_inputType->handleTouchEvent(static_cast<TouchEvent*>(evt)); 1143 if (evt->defaultHandled()) 1144 return; 1145 } 1146 1147 if (evt->isKeyboardEvent() && evt->type() == eventNames().keydownEvent) { 1148 m_inputType->handleKeydownEvent(toKeyboardEvent(evt)); 1149 if (evt->defaultHandled()) 1150 return; 1151 } 1152 1153 // Call the base event handler before any of our own event handling for almost all events in text fields. 1154 // Makes editing keyboard handling take precedence over the keydown and keypress handling in this function. 1155 bool callBaseClassEarly = isTextField() && (evt->type() == eventNames().keydownEvent || evt->type() == eventNames().keypressEvent); 1156 if (callBaseClassEarly) { 1157 HTMLTextFormControlElement::defaultEventHandler(evt); 1158 if (evt->defaultHandled()) 1159 return; 1160 } 1161 1162 // DOMActivate events cause the input to be "activated" - in the case of image and submit inputs, this means 1163 // actually submitting the form. For reset inputs, the form is reset. These events are sent when the user clicks 1164 // on the element, or presses enter while it is the active element. JavaScript code wishing to activate the element 1165 // must dispatch a DOMActivate event - a click event will not do the job. 1166 if (evt->type() == eventNames().DOMActivateEvent) { 1167 m_inputType->handleDOMActivateEvent(evt); 1168 if (evt->defaultHandled()) 1169 return; 1170 } 1171 1172 // Use key press event here since sending simulated mouse events 1173 // on key down blocks the proper sending of the key press event. 1174 if (evt->isKeyboardEvent() && evt->type() == eventNames().keypressEvent) { 1175 m_inputType->handleKeypressEvent(toKeyboardEvent(evt)); 1176 if (evt->defaultHandled()) 1177 return; 1178 } 1179 1180 if (evt->isKeyboardEvent() && evt->type() == eventNames().keyupEvent) { 1181 m_inputType->handleKeyupEvent(toKeyboardEvent(evt)); 1182 if (evt->defaultHandled()) 1183 return; 1184 } 1185 1186 if (m_inputType->shouldSubmitImplicitly(evt)) { 1187 if (isSearchField()) 1188 onSearch(); 1189 // Form submission finishes editing, just as loss of focus does. 1190 // If there was a change, send the event now. 1191 if (wasChangedSinceLastFormControlChangeEvent()) 1192 dispatchFormControlChangeEvent(); 1193 1194 RefPtr<HTMLFormElement> formForSubmission = m_inputType->formForSubmission(); 1195 // Form may never have been present, or may have been destroyed by code responding to the change event. 1196 if (formForSubmission) 1197 formForSubmission->submitImplicitly(evt, canTriggerImplicitSubmission()); 1198 1199 evt->setDefaultHandled(); 1200 return; 1201 } 1202 1203 if (evt->isBeforeTextInsertedEvent()) 1204 m_inputType->handleBeforeTextInsertedEvent(static_cast<BeforeTextInsertedEvent*>(evt)); 1205 1206 if (evt->isMouseEvent() && evt->type() == eventNames().mousedownEvent) { 1207 m_inputType->handleMouseDownEvent(toMouseEvent(evt)); 1208 if (evt->defaultHandled()) 1209 return; 1210 } 1211 1212 m_inputType->forwardEvent(evt); 1213 1214 if (!callBaseClassEarly && !evt->defaultHandled()) 1215 HTMLTextFormControlElement::defaultEventHandler(evt); 1216 } 1217 1218 bool HTMLInputElement::willRespondToMouseClickEvents() 1219 { 1220 // FIXME: Consider implementing willRespondToMouseClickEvents() in InputType if more accurate results are necessary. 1221 if (!isDisabledFormControl()) 1222 return true; 1223 1224 return HTMLTextFormControlElement::willRespondToMouseClickEvents(); 1225 } 1226 1227 bool HTMLInputElement::isURLAttribute(const Attribute& attribute) const 1228 { 1229 return attribute.name() == srcAttr || attribute.name() == formactionAttr || HTMLTextFormControlElement::isURLAttribute(attribute); 1230 } 1231 1232 String HTMLInputElement::defaultValue() const 1233 { 1234 return fastGetAttribute(valueAttr); 1235 } 1236 1237 void HTMLInputElement::setDefaultValue(const String &value) 1238 { 1239 setAttribute(valueAttr, value); 1240 } 1241 1242 static inline bool isRFC2616TokenCharacter(UChar ch) 1243 { 1244 return isASCII(ch) && ch > ' ' && ch != '"' && ch != '(' && ch != ')' && ch != ',' && ch != '/' && (ch < ':' || ch > '@') && (ch < '[' || ch > ']') && ch != '{' && ch != '}' && ch != 0x7f; 1245 } 1246 1247 static bool isValidMIMEType(const String& type) 1248 { 1249 size_t slashPosition = type.find('/'); 1250 if (slashPosition == notFound || !slashPosition || slashPosition == type.length() - 1) 1251 return false; 1252 for (size_t i = 0; i < type.length(); ++i) { 1253 if (!isRFC2616TokenCharacter(type[i]) && i != slashPosition) 1254 return false; 1255 } 1256 return true; 1257 } 1258 1259 static bool isValidFileExtension(const String& type) 1260 { 1261 if (type.length() < 2) 1262 return false; 1263 return type[0] == '.'; 1264 } 1265 1266 static Vector<String> parseAcceptAttribute(const String& acceptString, bool (*predicate)(const String&)) 1267 { 1268 Vector<String> types; 1269 if (acceptString.isEmpty()) 1270 return types; 1271 1272 Vector<String> splitTypes; 1273 acceptString.split(',', false, splitTypes); 1274 for (size_t i = 0; i < splitTypes.size(); ++i) { 1275 String trimmedType = stripLeadingAndTrailingHTMLSpaces(splitTypes[i]); 1276 if (trimmedType.isEmpty()) 1277 continue; 1278 if (!predicate(trimmedType)) 1279 continue; 1280 types.append(trimmedType.lower()); 1281 } 1282 1283 return types; 1284 } 1285 1286 Vector<String> HTMLInputElement::acceptMIMETypes() 1287 { 1288 return parseAcceptAttribute(fastGetAttribute(acceptAttr), isValidMIMEType); 1289 } 1290 1291 Vector<String> HTMLInputElement::acceptFileExtensions() 1292 { 1293 return parseAcceptAttribute(fastGetAttribute(acceptAttr), isValidFileExtension); 1294 } 1295 1296 String HTMLInputElement::accept() const 1297 { 1298 return fastGetAttribute(acceptAttr); 1299 } 1300 1301 String HTMLInputElement::alt() const 1302 { 1303 return fastGetAttribute(altAttr); 1304 } 1305 1306 int HTMLInputElement::maxLength() const 1307 { 1308 return m_maxLength; 1309 } 1310 1311 void HTMLInputElement::setMaxLength(int maxLength, ExceptionState& es) 1312 { 1313 if (maxLength < 0) 1314 es.throwDOMException(IndexSizeError); 1315 else 1316 setAttribute(maxlengthAttr, String::number(maxLength)); 1317 } 1318 1319 bool HTMLInputElement::multiple() const 1320 { 1321 return fastHasAttribute(multipleAttr); 1322 } 1323 1324 void HTMLInputElement::setSize(unsigned size) 1325 { 1326 setAttribute(sizeAttr, String::number(size)); 1327 } 1328 1329 void HTMLInputElement::setSize(unsigned size, ExceptionState& es) 1330 { 1331 if (!size) 1332 es.throwDOMException(IndexSizeError); 1333 else 1334 setSize(size); 1335 } 1336 1337 KURL HTMLInputElement::src() const 1338 { 1339 return document()->completeURL(fastGetAttribute(srcAttr)); 1340 } 1341 1342 void HTMLInputElement::setAutofilled(bool autofilled) 1343 { 1344 if (autofilled == m_isAutofilled) 1345 return; 1346 1347 m_isAutofilled = autofilled; 1348 setNeedsStyleRecalc(); 1349 } 1350 1351 FileList* HTMLInputElement::files() 1352 { 1353 return m_inputType->files(); 1354 } 1355 1356 void HTMLInputElement::setFiles(PassRefPtr<FileList> files) 1357 { 1358 m_inputType->setFiles(files); 1359 } 1360 1361 bool HTMLInputElement::receiveDroppedFiles(const DragData* dragData) 1362 { 1363 return m_inputType->receiveDroppedFiles(dragData); 1364 } 1365 1366 String HTMLInputElement::droppedFileSystemId() 1367 { 1368 return m_inputType->droppedFileSystemId(); 1369 } 1370 1371 bool HTMLInputElement::canReceiveDroppedFiles() const 1372 { 1373 return m_canReceiveDroppedFiles; 1374 } 1375 1376 void HTMLInputElement::setCanReceiveDroppedFiles(bool canReceiveDroppedFiles) 1377 { 1378 if (m_canReceiveDroppedFiles == canReceiveDroppedFiles) 1379 return; 1380 m_canReceiveDroppedFiles = canReceiveDroppedFiles; 1381 if (renderer()) 1382 renderer()->updateFromElement(); 1383 } 1384 1385 String HTMLInputElement::visibleValue() const 1386 { 1387 return m_inputType->visibleValue(); 1388 } 1389 1390 String HTMLInputElement::sanitizeValue(const String& proposedValue) const 1391 { 1392 if (proposedValue.isNull()) 1393 return proposedValue; 1394 return m_inputType->sanitizeValue(proposedValue); 1395 } 1396 1397 String HTMLInputElement::localizeValue(const String& proposedValue) const 1398 { 1399 if (proposedValue.isNull()) 1400 return proposedValue; 1401 return m_inputType->localizeValue(proposedValue); 1402 } 1403 1404 bool HTMLInputElement::isInRange() const 1405 { 1406 return m_inputType->isInRange(value()); 1407 } 1408 1409 bool HTMLInputElement::isOutOfRange() const 1410 { 1411 return m_inputType->isOutOfRange(value()); 1412 } 1413 1414 bool HTMLInputElement::isRequiredFormControl() const 1415 { 1416 return m_inputType->supportsRequired() && isRequired(); 1417 } 1418 1419 bool HTMLInputElement::matchesReadOnlyPseudoClass() const 1420 { 1421 return m_inputType->supportsReadOnly() && isReadOnly(); 1422 } 1423 1424 bool HTMLInputElement::matchesReadWritePseudoClass() const 1425 { 1426 return m_inputType->supportsReadOnly() && !isReadOnly(); 1427 } 1428 1429 void HTMLInputElement::onSearch() 1430 { 1431 ASSERT(isSearchField()); 1432 if (m_inputType) 1433 static_cast<SearchInputType*>(m_inputType.get())->stopSearchEventTimer(); 1434 dispatchEvent(Event::create(eventNames().searchEvent, true, false)); 1435 } 1436 1437 void HTMLInputElement::updateClearButtonVisibility() 1438 { 1439 m_inputType->updateClearButtonVisibility(); 1440 } 1441 1442 void HTMLInputElement::willChangeForm() 1443 { 1444 removeFromRadioButtonGroup(); 1445 HTMLTextFormControlElement::willChangeForm(); 1446 } 1447 1448 void HTMLInputElement::didChangeForm() 1449 { 1450 HTMLTextFormControlElement::didChangeForm(); 1451 addToRadioButtonGroup(); 1452 } 1453 1454 Node::InsertionNotificationRequest HTMLInputElement::insertedInto(ContainerNode* insertionPoint) 1455 { 1456 HTMLTextFormControlElement::insertedInto(insertionPoint); 1457 if (insertionPoint->inDocument() && !form()) 1458 addToRadioButtonGroup(); 1459 resetListAttributeTargetObserver(); 1460 return InsertionDone; 1461 } 1462 1463 void HTMLInputElement::removedFrom(ContainerNode* insertionPoint) 1464 { 1465 if (insertionPoint->inDocument() && !form()) 1466 removeFromRadioButtonGroup(); 1467 HTMLTextFormControlElement::removedFrom(insertionPoint); 1468 ASSERT(!inDocument()); 1469 resetListAttributeTargetObserver(); 1470 } 1471 1472 void HTMLInputElement::didMoveToNewDocument(Document* oldDocument) 1473 { 1474 if (hasImageLoader()) 1475 imageLoader()->elementDidMoveToNewDocument(); 1476 1477 if (oldDocument) { 1478 if (isRadioButton()) 1479 oldDocument->formController()->checkedRadioButtons().removeButton(this); 1480 if (m_hasTouchEventHandler) 1481 oldDocument->didRemoveEventTargetNode(this); 1482 } 1483 1484 if (m_hasTouchEventHandler) 1485 document()->didAddTouchEventHandler(this); 1486 1487 HTMLTextFormControlElement::didMoveToNewDocument(oldDocument); 1488 } 1489 1490 void HTMLInputElement::addSubresourceAttributeURLs(ListHashSet<KURL>& urls) const 1491 { 1492 HTMLTextFormControlElement::addSubresourceAttributeURLs(urls); 1493 1494 addSubresourceURL(urls, src()); 1495 } 1496 1497 bool HTMLInputElement::recalcWillValidate() const 1498 { 1499 return m_inputType->supportsValidation() && HTMLTextFormControlElement::recalcWillValidate(); 1500 } 1501 1502 void HTMLInputElement::requiredAttributeChanged() 1503 { 1504 HTMLTextFormControlElement::requiredAttributeChanged(); 1505 if (CheckedRadioButtons* buttons = checkedRadioButtons()) 1506 buttons->requiredAttributeChanged(this); 1507 m_inputType->requiredAttributeChanged(); 1508 } 1509 1510 void HTMLInputElement::selectColorInColorChooser(const Color& color) 1511 { 1512 if (!m_inputType->isColorControl()) 1513 return; 1514 static_cast<ColorInputType*>(m_inputType.get())->didChooseColor(color); 1515 } 1516 1517 HTMLElement* HTMLInputElement::list() const 1518 { 1519 return dataList(); 1520 } 1521 1522 HTMLDataListElement* HTMLInputElement::dataList() const 1523 { 1524 if (!m_hasNonEmptyList) 1525 return 0; 1526 1527 if (!m_inputType->shouldRespectListAttribute()) 1528 return 0; 1529 1530 Element* element = treeScope()->getElementById(fastGetAttribute(listAttr)); 1531 if (!element) 1532 return 0; 1533 if (!element->hasTagName(datalistTag)) 1534 return 0; 1535 1536 return static_cast<HTMLDataListElement*>(element); 1537 } 1538 1539 void HTMLInputElement::resetListAttributeTargetObserver() 1540 { 1541 if (inDocument()) 1542 m_listAttributeTargetObserver = ListAttributeTargetObserver::create(fastGetAttribute(listAttr), this); 1543 else 1544 m_listAttributeTargetObserver = nullptr; 1545 } 1546 1547 void HTMLInputElement::listAttributeTargetChanged() 1548 { 1549 m_inputType->listAttributeTargetChanged(); 1550 } 1551 1552 bool HTMLInputElement::isSteppable() const 1553 { 1554 return m_inputType->isSteppable(); 1555 } 1556 1557 #if ENABLE(INPUT_SPEECH) 1558 1559 bool HTMLInputElement::isSpeechEnabled() const 1560 { 1561 // FIXME: Add support for RANGE, EMAIL, URL, COLOR and DATE/TIME input types. 1562 return m_inputType->shouldRespectSpeechAttribute() && RuntimeEnabledFeatures::speechInputEnabled() && hasAttribute(webkitspeechAttr); 1563 } 1564 1565 #endif 1566 1567 bool HTMLInputElement::isTextButton() const 1568 { 1569 return m_inputType->isTextButton(); 1570 } 1571 1572 bool HTMLInputElement::isRadioButton() const 1573 { 1574 return m_inputType->isRadioButton(); 1575 } 1576 1577 bool HTMLInputElement::isSearchField() const 1578 { 1579 return m_inputType->isSearchField(); 1580 } 1581 1582 bool HTMLInputElement::isInputTypeHidden() const 1583 { 1584 return m_inputType->isHiddenType(); 1585 } 1586 1587 bool HTMLInputElement::isPasswordField() const 1588 { 1589 return m_inputType->isPasswordField(); 1590 } 1591 1592 bool HTMLInputElement::isCheckbox() const 1593 { 1594 return m_inputType->isCheckbox(); 1595 } 1596 1597 bool HTMLInputElement::isRangeControl() const 1598 { 1599 return m_inputType->isRangeControl(); 1600 } 1601 1602 bool HTMLInputElement::isColorControl() const 1603 { 1604 return m_inputType->isColorControl(); 1605 } 1606 1607 bool HTMLInputElement::isText() const 1608 { 1609 return m_inputType->isTextType(); 1610 } 1611 1612 bool HTMLInputElement::isEmailField() const 1613 { 1614 return m_inputType->isEmailField(); 1615 } 1616 1617 bool HTMLInputElement::isFileUpload() const 1618 { 1619 return m_inputType->isFileUpload(); 1620 } 1621 1622 bool HTMLInputElement::isImageButton() const 1623 { 1624 return m_inputType->isImageButton(); 1625 } 1626 1627 bool HTMLInputElement::isNumberField() const 1628 { 1629 return m_inputType->isNumberField(); 1630 } 1631 1632 bool HTMLInputElement::isSubmitButton() const 1633 { 1634 return m_inputType->isSubmitButton(); 1635 } 1636 1637 bool HTMLInputElement::isTelephoneField() const 1638 { 1639 return m_inputType->isTelephoneField(); 1640 } 1641 1642 bool HTMLInputElement::isURLField() const 1643 { 1644 return m_inputType->isURLField(); 1645 } 1646 1647 bool HTMLInputElement::isDateField() const 1648 { 1649 return m_inputType->isDateField(); 1650 } 1651 1652 bool HTMLInputElement::isDateTimeLocalField() const 1653 { 1654 return m_inputType->isDateTimeLocalField(); 1655 } 1656 1657 bool HTMLInputElement::isMonthField() const 1658 { 1659 return m_inputType->isMonthField(); 1660 } 1661 1662 bool HTMLInputElement::isTimeField() const 1663 { 1664 return m_inputType->isTimeField(); 1665 } 1666 1667 bool HTMLInputElement::isWeekField() const 1668 { 1669 return m_inputType->isWeekField(); 1670 } 1671 1672 bool HTMLInputElement::isEnumeratable() const 1673 { 1674 return m_inputType->isEnumeratable(); 1675 } 1676 1677 bool HTMLInputElement::supportLabels() const 1678 { 1679 return m_inputType->supportLabels(); 1680 } 1681 1682 bool HTMLInputElement::shouldAppearChecked() const 1683 { 1684 return checked() && m_inputType->isCheckable(); 1685 } 1686 1687 bool HTMLInputElement::supportsPlaceholder() const 1688 { 1689 return m_inputType->supportsPlaceholder(); 1690 } 1691 1692 void HTMLInputElement::updatePlaceholderText() 1693 { 1694 return m_inputType->updatePlaceholderText(); 1695 } 1696 1697 void HTMLInputElement::parseMaxLengthAttribute(const AtomicString& value) 1698 { 1699 int maxLength; 1700 if (!parseHTMLInteger(value, maxLength)) 1701 maxLength = maximumLength; 1702 if (maxLength < 0 || maxLength > maximumLength) 1703 maxLength = maximumLength; 1704 int oldMaxLength = m_maxLength; 1705 m_maxLength = maxLength; 1706 if (oldMaxLength != maxLength) 1707 updateValueIfNeeded(); 1708 setNeedsStyleRecalc(); 1709 setNeedsValidityCheck(); 1710 } 1711 1712 void HTMLInputElement::updateValueIfNeeded() 1713 { 1714 String newValue = sanitizeValue(m_valueIfDirty); 1715 ASSERT(!m_valueIfDirty.isNull() || newValue.isNull()); 1716 if (newValue != m_valueIfDirty) 1717 setValue(newValue); 1718 } 1719 1720 String HTMLInputElement::defaultToolTip() const 1721 { 1722 return m_inputType->defaultToolTip(); 1723 } 1724 1725 bool HTMLInputElement::shouldAppearIndeterminate() const 1726 { 1727 return m_inputType->supportsIndeterminateAppearance() && indeterminate(); 1728 } 1729 1730 #if ENABLE(MEDIA_CAPTURE) 1731 bool HTMLInputElement::capture() const 1732 { 1733 if (!isFileUpload() || !fastHasAttribute(captureAttr)) 1734 return false; 1735 1736 // As per crbug.com/240252, emit a deprecation warning when the "capture" 1737 // attribute is used as an enum. The spec has been updated and "capture" is 1738 // supposed to be used as a boolean. 1739 bool hasDeprecatedUsage = !fastGetAttribute(captureAttr).isNull(); 1740 if (hasDeprecatedUsage) 1741 UseCounter::countDeprecation(document(), UseCounter::CaptureAttributeAsEnum); 1742 else 1743 UseCounter::count(document(), UseCounter::CaptureAttributeAsEnum); 1744 1745 return true; 1746 } 1747 #endif 1748 1749 bool HTMLInputElement::isInRequiredRadioButtonGroup() 1750 { 1751 ASSERT(isRadioButton()); 1752 if (CheckedRadioButtons* buttons = checkedRadioButtons()) 1753 return buttons->isInRequiredGroup(this); 1754 return false; 1755 } 1756 1757 HTMLInputElement* HTMLInputElement::checkedRadioButtonForGroup() const 1758 { 1759 if (CheckedRadioButtons* buttons = checkedRadioButtons()) 1760 return buttons->checkedButtonForGroup(name()); 1761 return 0; 1762 } 1763 1764 CheckedRadioButtons* HTMLInputElement::checkedRadioButtons() const 1765 { 1766 if (!isRadioButton()) 1767 return 0; 1768 if (HTMLFormElement* formElement = form()) 1769 return &formElement->checkedRadioButtons(); 1770 if (inDocument()) 1771 return &document()->formController()->checkedRadioButtons(); 1772 return 0; 1773 } 1774 1775 inline void HTMLInputElement::addToRadioButtonGroup() 1776 { 1777 if (CheckedRadioButtons* buttons = checkedRadioButtons()) 1778 buttons->addButton(this); 1779 } 1780 1781 inline void HTMLInputElement::removeFromRadioButtonGroup() 1782 { 1783 if (CheckedRadioButtons* buttons = checkedRadioButtons()) 1784 buttons->removeButton(this); 1785 } 1786 1787 unsigned HTMLInputElement::height() const 1788 { 1789 return m_inputType->height(); 1790 } 1791 1792 unsigned HTMLInputElement::width() const 1793 { 1794 return m_inputType->width(); 1795 } 1796 1797 void HTMLInputElement::setHeight(unsigned height) 1798 { 1799 setAttribute(heightAttr, String::number(height)); 1800 } 1801 1802 void HTMLInputElement::setWidth(unsigned width) 1803 { 1804 setAttribute(widthAttr, String::number(width)); 1805 } 1806 1807 PassOwnPtr<ListAttributeTargetObserver> ListAttributeTargetObserver::create(const AtomicString& id, HTMLInputElement* element) 1808 { 1809 return adoptPtr(new ListAttributeTargetObserver(id, element)); 1810 } 1811 1812 ListAttributeTargetObserver::ListAttributeTargetObserver(const AtomicString& id, HTMLInputElement* element) 1813 : IdTargetObserver(element->treeScope()->idTargetObserverRegistry(), id) 1814 , m_element(element) 1815 { 1816 } 1817 1818 void ListAttributeTargetObserver::idTargetChanged() 1819 { 1820 m_element->listAttributeTargetChanged(); 1821 } 1822 1823 void HTMLInputElement::setRangeText(const String& replacement, ExceptionState& es) 1824 { 1825 if (!m_inputType->supportsSelectionAPI()) { 1826 es.throwDOMException(InvalidStateError); 1827 return; 1828 } 1829 1830 HTMLTextFormControlElement::setRangeText(replacement, es); 1831 } 1832 1833 void HTMLInputElement::setRangeText(const String& replacement, unsigned start, unsigned end, const String& selectionMode, ExceptionState& es) 1834 { 1835 if (!m_inputType->supportsSelectionAPI()) { 1836 es.throwDOMException(InvalidStateError); 1837 return; 1838 } 1839 1840 HTMLTextFormControlElement::setRangeText(replacement, start, end, selectionMode, es); 1841 } 1842 1843 bool HTMLInputElement::setupDateTimeChooserParameters(DateTimeChooserParameters& parameters) 1844 { 1845 if (!document()->view()) 1846 return false; 1847 1848 parameters.type = type(); 1849 parameters.minimum = minimum(); 1850 parameters.maximum = maximum(); 1851 parameters.required = isRequired(); 1852 if (!RuntimeEnabledFeatures::langAttributeAwareFormControlUIEnabled()) 1853 parameters.locale = defaultLanguage(); 1854 else { 1855 AtomicString computedLocale = computeInheritedLanguage(); 1856 parameters.locale = computedLocale.isEmpty() ? AtomicString(defaultLanguage()) : computedLocale; 1857 } 1858 1859 StepRange stepRange = createStepRange(RejectAny); 1860 if (stepRange.hasStep()) { 1861 parameters.step = stepRange.step().toDouble(); 1862 parameters.stepBase = stepRange.stepBase().toDouble(); 1863 } else { 1864 parameters.step = 1.0; 1865 parameters.stepBase = 0; 1866 } 1867 1868 parameters.anchorRectInRootView = document()->view()->contentsToRootView(pixelSnappedBoundingBox()); 1869 parameters.currentValue = value(); 1870 parameters.isAnchorElementRTL = computedStyle()->direction() == RTL; 1871 if (RuntimeEnabledFeatures::dataListElementEnabled()) { 1872 if (HTMLDataListElement* dataList = this->dataList()) { 1873 RefPtr<HTMLCollection> options = dataList->options(); 1874 for (unsigned i = 0; HTMLOptionElement* option = toHTMLOptionElement(options->item(i)); ++i) { 1875 if (!isValidValue(option->value())) 1876 continue; 1877 parameters.suggestionValues.append(sanitizeValue(option->value())); 1878 parameters.localizedSuggestionValues.append(localizeValue(option->value())); 1879 parameters.suggestionLabels.append(option->value() == option->label() ? String() : option->label()); 1880 } 1881 } 1882 } 1883 return true; 1884 } 1885 1886 bool HTMLInputElement::supportsInputModeAttribute() const 1887 { 1888 return m_inputType->supportsInputModeAttribute(); 1889 } 1890 1891 #if ENABLE(INPUT_MULTIPLE_FIELDS_UI) 1892 PassRefPtr<RenderStyle> HTMLInputElement::customStyleForRenderer() 1893 { 1894 return m_inputType->customStyleForRenderer(originalStyleForRenderer()); 1895 } 1896 #endif 1897 1898 } // namespace 1899