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