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